Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let package = Package(
dependencies: [
.package(
url: "https://github.com/claucambra/NextcloudCapabilitiesKit.git",
.upToNextMajor(from: "2.0.0")
.upToNextMajor(from: "2.1.2")
),
.package(url: "https://github.com/nextcloud/NextcloudKit", branch: "develop"),
.package(url: "https://github.com/realm/realm-swift.git", exact: "10.49.0"),
Expand Down
7 changes: 7 additions & 0 deletions Sources/NextcloudFileProviderKit/Item/Item+Create.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ extension Item {
domain: NSFileProviderDomain? = nil,
account: Account,
remoteInterface: RemoteInterface,
forcedChunkSize: Int?,
progress: Progress,
dbManager: FilesDatabaseManager
) async -> (Item?, Error?) {
Expand All @@ -112,6 +113,7 @@ extension Item {
toRemotePath: remotePath,
usingRemoteInterface: remoteInterface,
withAccount: account,
inChunksSized: forcedChunkSize,
usingChunkUploadId: chunkUploadId,
dbManager: dbManager,
creationDate: itemTemplate.creationDate as? Date,
Expand Down Expand Up @@ -204,6 +206,7 @@ extension Item {
domain: NSFileProviderDomain? = nil,
account: Account,
remoteInterface: RemoteInterface,
forcedChunkSize: Int?,
progress: Progress,
dbManager: FilesDatabaseManager
) async throws -> Item? {
Expand Down Expand Up @@ -311,6 +314,7 @@ extension Item {
toRemotePath: childRemoteUrl,
usingRemoteInterface: remoteInterface,
withAccount: account,
inChunksSized: forcedChunkSize,
dbManager: dbManager,
creationDate: childUrlAttributes.creationDate,
modificationDate: childUrlAttributes.contentModificationDate,
Expand Down Expand Up @@ -397,6 +401,7 @@ extension Item {
domain: NSFileProviderDomain? = nil,
account: Account,
remoteInterface: RemoteInterface,
forcedChunkSize: Int? = nil,
progress: Progress,
dbManager: FilesDatabaseManager = .shared
) async -> (Item?, Error?) {
Expand Down Expand Up @@ -575,6 +580,7 @@ extension Item {
domain: domain,
account: account,
remoteInterface: remoteInterface,
forcedChunkSize: forcedChunkSize,
progress: progress,
dbManager: dbManager
), nil)
Expand All @@ -592,6 +598,7 @@ extension Item {
domain: domain,
account: account,
remoteInterface: remoteInterface,
forcedChunkSize: forcedChunkSize,
progress: progress,
dbManager: dbManager
)
Expand Down
7 changes: 7 additions & 0 deletions Sources/NextcloudFileProviderKit/Item/Item+Modify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public extension Item {
remotePath: String,
newCreationDate: Date?,
newContentModificationDate: Date?,
forcedChunkSize: Int?,
domain: NSFileProviderDomain?,
progress: Progress,
dbManager: FilesDatabaseManager
Expand Down Expand Up @@ -137,6 +138,7 @@ public extension Item {
toRemotePath: remotePath,
usingRemoteInterface: remoteInterface,
withAccount: account,
inChunksSized: forcedChunkSize,
usingChunkUploadId: metadata.chunkUploadId,
dbManager: dbManager,
creationDate: newCreationDate,
Expand Down Expand Up @@ -221,6 +223,7 @@ public extension Item {
private func modifyBundleOrPackageContents(
contents newContents: URL?,
remotePath: String,
forcedChunkSize: Int?,
domain: NSFileProviderDomain?,
progress: Progress,
dbManager: FilesDatabaseManager
Expand Down Expand Up @@ -402,6 +405,7 @@ public extension Item {
toRemotePath: childRemoteUrl,
usingRemoteInterface: remoteInterface,
withAccount: account,
inChunksSized: forcedChunkSize,
dbManager: dbManager,
creationDate: childUrlAttributes.creationDate,
modificationDate: childUrlAttributes.contentModificationDate,
Expand Down Expand Up @@ -833,6 +837,7 @@ public extension Item {
options: NSFileProviderModifyItemOptions = [],
request: NSFileProviderRequest = NSFileProviderRequest(),
domain: NSFileProviderDomain? = nil,
forcedChunkSize: Int? = nil,
progress: Progress = .init(),
dbManager: FilesDatabaseManager = .shared
) async -> (Item?, Error?) {
Expand Down Expand Up @@ -1045,6 +1050,7 @@ public extension Item {
contentModifiedItem = try await modifiedItem.modifyBundleOrPackageContents(
contents: newContents,
remotePath: newServerUrlFileName,
forcedChunkSize: forcedChunkSize,
domain: domain,
progress: progress,
dbManager: dbManager
Expand All @@ -1058,6 +1064,7 @@ public extension Item {
remotePath: newServerUrlFileName,
newCreationDate: newCreationDate,
newContentModificationDate: newContentModificationDate,
forcedChunkSize: forcedChunkSize,
domain: domain,
progress: progress,
dbManager: dbManager
Expand Down
36 changes: 34 additions & 2 deletions Sources/NextcloudFileProviderKit/Utilities/Upload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@

import Alamofire
import Foundation
import NextcloudCapabilitiesKit
import NextcloudKit
import OSLog
import RealmSwift

let defaultFileChunkSize = 10_000_000 // 10 MB
let defaultFileChunkSize = 104_857_600 // 100 MiB
let uploadLogger = Logger(subsystem: Logger.subsystem, category: "upload")

func upload(
fileLocatedAt localFilePath: String,
toRemotePath remotePath: String,
usingRemoteInterface remoteInterface: RemoteInterface,
withAccount account: Account,
inChunksSized chunkSize: Int = defaultFileChunkSize,
inChunksSized chunkSize: Int? = nil,
usingChunkUploadId chunkUploadId: String = UUID().uuidString,
dbManager: FilesDatabaseManager = .shared,
creationDate: Date? = nil,
Expand All @@ -40,6 +41,37 @@ func upload(
) {
let fileSize =
(try? FileManager.default.attributesOfItem(atPath: localFilePath)[.size] as? Int64) ?? 0

let chunkSize = await {
if let chunkSize {
uploadLogger.info("Using provided chunkSize: \(chunkSize, privacy: .public)")
return chunkSize
}
let (_, capabilitiesData, error) = await remoteInterface.fetchCapabilities(
account: account, options: options, taskHandler: taskHandler
)
guard let capabilitiesData,
let capabilities = Capabilities(data: capabilitiesData),
let serverChunkSize = capabilities.files?.chunkedUpload?.maxChunkSize,
serverChunkSize > 0
else {
uploadLogger.info(
"""
Received nil capabilities data.
Received error: \(error.errorDescription, privacy: .public)
Using default file chunk size: \(defaultFileChunkSize, privacy: .public)
"""
)
return defaultFileChunkSize
}
uploadLogger.info(
"""
Received file chunk size from server: \(serverChunkSize, privacy: .public)
"""
)
return Int(serverChunkSize)
}()

guard fileSize > chunkSize else {
let (_, ocId, etag, date, size, _, afError, remoteError) = await remoteInterface.upload(
remotePath: remotePath,
Expand Down
2 changes: 1 addition & 1 deletion Tests/Interface/MockRemoteInterface.swift

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions Tests/NextcloudFileProviderKitTests/ItemCreateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,9 @@ final class ItemCreateTests: XCTestCase {
fileItemMetadata.classFile = NKCommon.TypeClassFile.document.rawValue
fileItemMetadata.serverUrl = Self.account.davFilesUrl

let chunkSize = 2
let tempUrl = FileManager.default.temporaryDirectory.appendingPathComponent("file")
let tempData = Data(repeating: 1, count: defaultFileChunkSize * 3)
let tempData = Data(repeating: 1, count: chunkSize * 3)
try tempData.write(to: tempUrl)

let fileItemTemplate = Item(
Expand All @@ -373,6 +374,7 @@ final class ItemCreateTests: XCTestCase {
contents: tempUrl,
account: Self.account,
remoteInterface: remoteInterface,
forcedChunkSize: chunkSize,
progress: Progress(),
dbManager: Self.dbManager
)
Expand Down Expand Up @@ -401,12 +403,13 @@ final class ItemCreateTests: XCTestCase {
}

func testCreateFileChunkedResumed() async throws {
let chunkSize = 2
let expectedChunkUploadId = UUID().uuidString // Check if illegal characters are stripped
let illegalChunkUploadId = expectedChunkUploadId + "/" // Check if illegal characters are stripped
let previousUploadedChunkNum = 1
let preexistingChunk = RemoteFileChunk(
fileName: String(previousUploadedChunkNum),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: expectedChunkUploadId
)

Expand All @@ -415,12 +418,12 @@ final class ItemCreateTests: XCTestCase {
db.add([
RemoteFileChunk(
fileName: String(previousUploadedChunkNum + 1),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: expectedChunkUploadId
),
RemoteFileChunk(
fileName: String(previousUploadedChunkNum + 2),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: expectedChunkUploadId
)
])
Expand All @@ -447,7 +450,7 @@ final class ItemCreateTests: XCTestCase {
fileItemMetadata.serverUrl = Self.account.davFilesUrl

let tempUrl = FileManager.default.temporaryDirectory.appendingPathComponent("file")
let tempData = Data(repeating: 1, count: defaultFileChunkSize * 3)
let tempData = Data(repeating: 1, count: chunkSize * 3)
try tempData.write(to: tempUrl)

let fileItemTemplate = Item(
Expand All @@ -461,6 +464,7 @@ final class ItemCreateTests: XCTestCase {
contents: tempUrl,
account: Self.account,
remoteInterface: remoteInterface,
forcedChunkSize: chunkSize,
progress: Progress(),
dbManager: Self.dbManager
)
Expand Down
14 changes: 9 additions & 5 deletions Tests/NextcloudFileProviderKitTests/ItemModifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,8 @@ final class ItemModifyTests: XCTestCase {
let itemMetadata = remoteItem.toItemMetadata(account: Self.account)
Self.dbManager.addItemMetadata(itemMetadata)

let newContents = Data(repeating: 1, count: defaultFileChunkSize * 3)
let chunkSize = 2
let newContents = Data(repeating: 1, count: chunkSize * 3)
let newContentsUrl = FileManager.default.temporaryDirectory.appendingPathComponent("test")
try newContents.write(to: newContentsUrl)

Expand All @@ -1239,6 +1240,7 @@ final class ItemModifyTests: XCTestCase {
itemTarget: targetItem,
changedFields: [.contents, .contentModificationDate],
contents: newContentsUrl,
forcedChunkSize: chunkSize,
dbManager: Self.dbManager
)
XCTAssertNil(error)
Expand All @@ -1252,11 +1254,12 @@ final class ItemModifyTests: XCTestCase {
}

func testModifyFileContentsChunkedResumed() async throws {
let chunkSize = 2
let chunkUploadId = UUID().uuidString
let previousUploadedChunkNum = 1
let preexistingChunk = RemoteFileChunk(
fileName: String(previousUploadedChunkNum),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: chunkUploadId
)

Expand All @@ -1265,12 +1268,12 @@ final class ItemModifyTests: XCTestCase {
db.add([
RemoteFileChunk(
fileName: String(previousUploadedChunkNum + 1),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: chunkUploadId
),
RemoteFileChunk(
fileName: String(previousUploadedChunkNum + 2),
size: Int64(defaultFileChunkSize),
size: Int64(chunkSize),
remoteChunkStoreFolderName: chunkUploadId
)
])
Expand All @@ -1283,7 +1286,7 @@ final class ItemModifyTests: XCTestCase {
itemMetadata.chunkUploadId = chunkUploadId
Self.dbManager.addItemMetadata(itemMetadata)

let newContents = Data(repeating: 1, count: defaultFileChunkSize * 3)
let newContents = Data(repeating: 1, count: chunkSize * 3)
let newContentsUrl = FileManager.default.temporaryDirectory.appendingPathComponent("test")
try newContents.write(to: newContentsUrl)

Expand All @@ -1310,6 +1313,7 @@ final class ItemModifyTests: XCTestCase {
itemTarget: targetItem,
changedFields: [.contents, .contentModificationDate],
contents: newContentsUrl,
forcedChunkSize: chunkSize,
dbManager: Self.dbManager
)
XCTAssertNil(error)
Expand Down
Loading