NCNetworkingChunkedUpload.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //
  2. // NCNetworkingUploadChunk.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 05/04/21.
  6. // Copyright © 2021 Marino Faggiana. All rights reserved.
  7. //
  8. import Foundation
  9. import NCCommunication
  10. import Queuer
  11. extension NCNetworking {
  12. func uploadChunkFile(metadata: tableMetadata, account: tableAccount, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) {
  13. let serverUrl = metadata.serverUrl
  14. let directoryProviderStorageOcId = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
  15. let chunkFolder = NCManageDatabase.shared.getChunkFolder(account: metadata.account, ocId: metadata.ocId)
  16. let chunkFolderPath = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getDAV() + "/uploads/" + account.userId + "/" + chunkFolder
  17. let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
  18. var uploadErrorCode: Int = 0
  19. var uploadErrorDescription: String = ""
  20. var counterFileNameInUpload: Int = 0
  21. let chunkSize = CCUtility.getChunkSize()
  22. var filesNames = NCManageDatabase.shared.getChunks(account: metadata.account, ocId: metadata.ocId)
  23. if filesNames.count == 0 {
  24. if let chunkedFilesNames = NCCommunicationCommon.shared.fileChunks(path: directoryProviderStorageOcId, fileName: metadata.fileName, pathChunks: directoryProviderStorageOcId, sizeInMB: chunkSize) {
  25. filesNames = chunkedFilesNames
  26. NCManageDatabase.shared.addChunks(account: metadata.account, ocId: metadata.ocId, chunkFolder: chunkFolder, fileNames: filesNames)
  27. } else {
  28. NCContentPresenter.shared.messageNotification("_error_", description: "_err_file_not_found_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode:NCGlobal.shared.errorReadFile, forced: true)
  29. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  30. return
  31. }
  32. }
  33. NCContentPresenter.shared.messageNotification("_info_", description: "_upload_chunk_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.info, errorCode:0, forced: false)
  34. createChunkFolder(chunkFolderPath: chunkFolderPath, account: metadata.account) { (errorCode, errorDescription) in
  35. if errorCode == 0 || errorCode == NCGlobal.shared.errordMethodNotSupported { // errordMethodNotSupported = already exists
  36. NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId])
  37. DispatchQueue.global(qos: .background).async {
  38. for fileName in filesNames {
  39. let serverUrlFileName = chunkFolderPath + "/" + fileName
  40. let fileNameChunkLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)!
  41. let semaphore = Semaphore()
  42. NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameChunkLocalPath, requestHandler: { (request) in
  43. self.uploadRequest[fileNameLocalPath] = request
  44. counterFileNameInUpload += 1
  45. let progress: Float = Float(counterFileNameInUpload) / Float(filesNames.count)
  46. let totalBytes: Int64 = (metadata.size / Int64(filesNames.count)) * Int64(counterFileNameInUpload)
  47. let totalBytesExpected: Int64 = metadata.size
  48. NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterProgressTask, userInfo: ["account":metadata.account, "ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "status":NSNumber(value: NCGlobal.shared.metadataStatusInUpload), "progress":NSNumber(value: progress), "totalBytes":NSNumber(value: totalBytes), "totalBytesExpected":NSNumber(value: totalBytesExpected)])
  49. }, taskHandler: { (task) in
  50. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading)
  51. }, progressHandler: { (_) in
  52. }) { (_, _, _, _, _, _, _, errorCode, errorDescription) in
  53. self.uploadRequest[fileNameLocalPath] = nil
  54. uploadErrorCode = errorCode
  55. uploadErrorDescription = errorDescription
  56. semaphore.continue()
  57. }
  58. semaphore.wait()
  59. if uploadErrorCode == 0 {
  60. NCManageDatabase.shared.deleteChunk(account: metadata.account, ocId: metadata.ocId, fileName: fileName)
  61. } else {
  62. break
  63. }
  64. }
  65. if uploadErrorCode == 0 {
  66. // Assembling the chunks
  67. let serverUrlFileNameSource = chunkFolderPath + "/.file"
  68. let pathServerUrl = CCUtility.returnPathfromServerUrl(serverUrl, urlBase: metadata.urlBase, account: metadata.account)!
  69. let serverUrlFileNameDestination = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getDAV() + "/files/" + account.userId + pathServerUrl + "/" + metadata.fileName
  70. var addCustomHeaders: [String:String] = [:]
  71. let creationDate = "\(metadata.creationDate.timeIntervalSince1970)"
  72. let modificationDate = "\(metadata.date.timeIntervalSince1970)"
  73. addCustomHeaders["X-OC-CTime"] = creationDate
  74. addCustomHeaders["X-OC-MTime"] = modificationDate
  75. NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: true, addCustomHeaders: addCustomHeaders) { (_, errorCode, errorDescription) in
  76. if errorCode == 0 {
  77. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  78. NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
  79. NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId)
  80. self.readFile(serverUrlFileName: serverUrlFileNameDestination, account: metadata.account) { (_, metadata, _, _) in
  81. if errorCode == 0, let metadata = metadata {
  82. NCManageDatabase.shared.addMetadata(metadata)
  83. NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl":serverUrl])
  84. } else {
  85. NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": serverUrl])
  86. }
  87. }
  88. } else {
  89. self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, errorCode: errorCode, errorDescription: errorDescription)
  90. }
  91. }
  92. } else {
  93. NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { (_, _, _) in
  94. self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, errorCode: uploadErrorCode, errorDescription: uploadErrorDescription)
  95. }
  96. }
  97. }
  98. } else {
  99. self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, errorCode: errorCode, errorDescription: errorDescription)
  100. }
  101. }
  102. }
  103. private func createChunkFolder(chunkFolderPath: String, account: String, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) {
  104. NCCommunication.shared.readFileOrFolder(serverUrlFileName: chunkFolderPath, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (_, _, _, errorCode, errorDescription) in
  105. if errorCode == 0 {
  106. completion(0, "")
  107. } else if errorCode == NCGlobal.shared.errorResourceNotFound {
  108. NCCommunication.shared.createFolder(chunkFolderPath) { (_, _, _, errorCode, errorDescription) in
  109. completion(errorCode, errorDescription)
  110. }
  111. } else {
  112. completion(errorCode, errorDescription)
  113. }
  114. }
  115. }
  116. private func uploadChunkFileError(metadata: tableMetadata, chunkFolderPath: String, errorCode: Int, errorDescription: String) {
  117. if errorCode == NSURLErrorCancelled || errorCode == NCGlobal.shared.errorRequestExplicityCancelled {
  118. let directoryProviderStorageOcId = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
  119. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  120. NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
  121. NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId)
  122. NCCommunication.shared.deleteFileOrFolder(chunkFolderPath) { (_, _, _) in }
  123. } else {
  124. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: nil, sessionError: errorDescription, sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusUploadError)
  125. let description = errorDescription + " code: \(errorCode)"
  126. NCContentPresenter.shared.messageNotification("_error_", description: description, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError, forced: true)
  127. }
  128. NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl":metadata.serverUrl])
  129. }
  130. }