Some context for the following:
1) DBAPIMetadata is just my wrapper for Files.Metadata that I can pass to Objective-C
2) The BGHelper at the end (when the call is not on the MainThread) just call the function
On the main thread and blocks the background thread until it completes.
Basically any calls on the main thread are async and those on the background thread are
synchronous for my use.
What succeeds ..
1) I pass an empty NDData to filesUploadSessionStart and get a session.
2) I pass the NSData with the real data to filesUploadSessionAppend
Data was smaller than MaxLength so everything was transfer in the first call to ProcessNextBlock
3) On successfull completion it tried to call filesUploadSessionAppend
Here I get:
DropboxAPI:UploadFile:SessionFinish:[request-id 9dc97cd33ec9680b0ea58decc87cc4dd] API route error - handle programmatically
Previously I tried to NOT use filesUploadSessionAppend when a single transfer would work and send the data in filesUploadSessionAppend ... that failed as well with a different error.
Sorry the following really gets mangled on this forum ... it's just a single Swift function that handles the transfer.
func UploadFile(dbPath:String, toPath:String, withParentRev:String, fromPath:String, completion: (DBAPIMetadata?) -> Void) -> Void {
if (NSThread.isMainThread()) {
// Context for Process Next
let ins = NSInputStream(fileAtPath: fromPath)
ins!.open()
let MaxLength = 1024 * 1024 * 2
var transferCnt:UInt64 = 0
var buffer = Array<UInt8>(count:MaxLength, repeatedValue:0)
var data = NSData.init(bytesNoCopy: &buffer, length:MaxLength, freeWhenDone:false)
var sessionID = ""
var retry = 0
// Initially blank ... so it can call itself
var ProcessNextBlock:() -> Void = { () -> Void in }
ProcessNextBlock = {
() in
let readCnt = ins!.read(&buffer, maxLength: MaxLength)
if (readCnt > 0) {
if (readCnt != MaxLength) {
data = NSData.init(bytesNoCopy: &buffer, length:(readCnt >= 0 ? readCnt: 0), freeWhenDone:false)
}
// Initiall blank ... so it can call itself
var compClosure:((Void)?, CallError<(Files.UploadSessionLookupError)>?) -> Void = { (_, _) -> Void in }
compClosure = {
(response, errorType) in
if errorType != nil {
// Lets Rety
retry++
if (retry < 4) {
self.mClient.filesUploadSessionAppend(sessionId:sessionID, offset:transferCnt, body:data).response(compClosure)
} else {
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionAppend:" + fromPath)
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionAppend:" + errorType!.description)
completion(nil)
}
} else {
transferCnt = transferCnt + UInt64(readCnt)
retry = 0
ProcessNextBlock()
}
}
self.mClient.filesUploadSessionAppend(sessionId:sessionID, offset:transferCnt, body:data).response(compClosure)
} else {
// Send the last non full block with filesUploadSession Finish
if (transferCnt > 0) {
let cursor = Files.UploadSessionCursor(sessionId: sessionID, offset: transferCnt)
let info = Files.CommitInfo(path: dbPath)
self.mClient.filesUploadSessionFinish(cursor: cursor, commit: info, body: NSData()).response( {
(response, errorType) in
if let (meta) = response {
completion(DBAPIMetadata(meta:meta))
} else {
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionFinish:" + fromPath)
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionFinish:" + errorType!.description)
completion(nil)
}
})
} else {
PersistLog.e(self.TAG, andMsg: "UploadFile:NoData:" + fromPath)
completion(nil)
}
}
}
// Start the Process - Use empty data just to get a Session ID
let tmp = NSData()
mClient.filesUploadSessionStart(body:tmp).response( {
(response, errorType) -> Void in
if let (startResult) = response {
sessionID = startResult.sessionId
ProcessNextBlock()
} else {
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionStart:" + fromPath)
PersistLog.e(self.TAG, andMsg: "UploadFile:SessionStart:" + errorType!.description)
completion(nil)
}
})
} else {
PersistLog.i(TAG, andMsg: "UploadFile")
let BG = BGHelper<DBAPIMetadata>(completion:completion)
BG.CallerStart( {
self.UploadFile(dbPath, toPath:toPath, withParentRev:withParentRev, fromPath: fromPath, completion: BG.completion)
})
BG.CallerWait()
}
}