NCNetworking+Upload.swift 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. //
  2. // NCNetworking+Upload.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 07/02/24.
  6. // Copyright © 2024 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. import UIKit
  24. import JGProgressHUD
  25. import NextcloudKit
  26. import Alamofire
  27. extension NCNetworking {
  28. func upload(metadata: tableMetadata,
  29. uploadE2EEDelegate: uploadE2EEDelegate? = nil,
  30. hudView: UIView?,
  31. hud: JGProgressHUD?,
  32. start: @escaping () -> Void = { },
  33. requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in },
  34. progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in },
  35. completion: @escaping (_ afError: AFError?, _ error: NKError) -> Void = { _, _ in }) {
  36. let metadata = tableMetadata.init(value: metadata)
  37. var numChunks: Int = 0
  38. NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Upload file \(metadata.fileNameView) with Identifier \(metadata.assetLocalIdentifier) with size \(metadata.size) [CHUNK \(metadata.chunk), E2EE \(metadata.isDirectoryE2EE)]")
  39. if metadata.isDirectoryE2EE {
  40. #if !EXTENSION_FILE_PROVIDER_EXTENSION && !EXTENSION_WIDGET
  41. Task {
  42. let error = await NCNetworkingE2EEUpload().upload(metadata: metadata, uploadE2EEDelegate: uploadE2EEDelegate, hudView: hudView, hud: hud)
  43. completion(nil, error)
  44. }
  45. #endif
  46. } else if metadata.chunk > 0 {
  47. if let hudView {
  48. DispatchQueue.main.async {
  49. if let hud {
  50. hud.indicatorView = JGProgressHUDRingIndicatorView()
  51. if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
  52. indicatorView.ringWidth = 1.5
  53. indicatorView.ringColor = NCBrandColor.shared.brandElement
  54. }
  55. hud.tapOnHUDViewBlock = { _ in
  56. NotificationCenter.default.postOnMainThread(name: "NextcloudKit.chunkedFile.stop")
  57. }
  58. hud.textLabel.text = NSLocalizedString("_wait_file_preparation_", comment: "")
  59. hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "")
  60. hud.detailTextLabel.textColor = NCBrandColor.shared.iconImageColor2
  61. hud.show(in: hudView)
  62. }
  63. }
  64. }
  65. uploadChunkFile(metadata: metadata) { num in
  66. numChunks = num
  67. } counterChunk: { counter in
  68. DispatchQueue.main.async { hud?.progress = Float(counter) / Float(numChunks) }
  69. } start: {
  70. DispatchQueue.main.async { hud?.dismiss() }
  71. } completion: { account, _, afError, error in
  72. DispatchQueue.main.async { hud?.dismiss() }
  73. var sessionTaskFailedCode = 0
  74. let directory = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId)
  75. if let error = NextcloudKit.shared.nkCommonInstance.getSessionErrorFromAFError(afError) {
  76. sessionTaskFailedCode = error.code
  77. }
  78. switch error.errorCode {
  79. case NKError.chunkNoEnoughMemory, NKError.chunkCreateFolder, NKError.chunkFilesNull, NKError.chunkFileNull:
  80. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  81. NCManageDatabase.shared.deleteChunks(account: account, ocId: metadata.ocId, directory: directory)
  82. NCContentPresenter().messageNotification("_error_files_upload_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error, afterDelay: 0.5)
  83. case NKError.chunkFileUpload:
  84. if let afError, (afError.isExplicitlyCancelledError || sessionTaskFailedCode == NCGlobal.shared.errorExplicitlyCancelled ) {
  85. NCManageDatabase.shared.deleteChunks(account: account, ocId: metadata.ocId, directory: directory)
  86. }
  87. case NKError.chunkMoveFile:
  88. NCManageDatabase.shared.deleteChunks(account: account, ocId: metadata.ocId, directory: directory)
  89. NCContentPresenter().messageNotification("_chunk_move_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error, afterDelay: 0.5)
  90. default: break
  91. }
  92. completion(afError, error)
  93. }
  94. } else if metadata.session == NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload {
  95. let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
  96. uploadFile(metadata: metadata, fileNameLocalPath: fileNameLocalPath, start: start, progressHandler: progressHandler) { _, _, _, _, _, _, afError, error in
  97. completion(afError, error)
  98. }
  99. } else {
  100. uploadFileInBackground(metadata: metadata, start: start) { error in
  101. completion(nil, error)
  102. }
  103. }
  104. }
  105. func uploadFile(metadata: tableMetadata,
  106. fileNameLocalPath: String,
  107. withUploadComplete: Bool = true,
  108. customHeaders: [String: String]? = nil,
  109. start: @escaping () -> Void = { },
  110. requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in },
  111. progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in },
  112. completion: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: NSDate?, _ size: Int64, _ allHeaderFields: [AnyHashable: Any]?, _ afError: AFError?, _ error: NKError) -> Void) {
  113. let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
  114. let options = NKRequestOptions(customHeader: customHeaders, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
  115. NextcloudKit.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, options: options, requestHandler: { request in
  116. self.uploadRequest[fileNameLocalPath] = request
  117. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  118. status: NCGlobal.shared.metadataStatusUploading)
  119. requestHandler(request)
  120. }, taskHandler: { task in
  121. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  122. taskIdentifier: task.taskIdentifier)
  123. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile),
  124. object: nil,
  125. userInfo: ["ocId": metadata.ocId,
  126. "serverUrl": metadata.serverUrl,
  127. "account": metadata.account,
  128. "fileName": metadata.fileName,
  129. "sessionSelector": metadata.sessionSelector])
  130. start()
  131. }, progressHandler: { progress in
  132. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask),
  133. object: nil,
  134. userInfo: ["account": metadata.account,
  135. "ocId": metadata.ocId,
  136. "fileName": metadata.fileName,
  137. "serverUrl": metadata.serverUrl,
  138. "status": NSNumber(value: NCGlobal.shared.metadataStatusUploading),
  139. "progress": NSNumber(value: progress.fractionCompleted),
  140. "totalBytes": NSNumber(value: progress.totalUnitCount),
  141. "totalBytesExpected": NSNumber(value: progress.completedUnitCount)])
  142. progressHandler(progress.completedUnitCount, progress.totalUnitCount, progress.fractionCompleted)
  143. }) { account, ocId, etag, date, size, allHeaderFields, afError, error in
  144. var error = error
  145. self.uploadRequest.removeValue(forKey: fileNameLocalPath)
  146. if withUploadComplete {
  147. if afError?.isExplicitlyCancelledError ?? false {
  148. error = NKError(errorCode: NCGlobal.shared.errorRequestExplicityCancelled, errorDescription: "error request explicity cancelled")
  149. }
  150. self.uploadComplete(metadata: metadata, ocId: ocId, etag: etag, date: date, size: size, error: error)
  151. }
  152. completion(account, ocId, etag, date, size, allHeaderFields, afError, error)
  153. }
  154. }
  155. func uploadChunkFile(metadata: tableMetadata,
  156. withUploadComplete: Bool = true,
  157. customHeaders: [String: String]? = nil,
  158. numChunks: @escaping (_ num: Int) -> Void = { _ in },
  159. counterChunk: @escaping (_ counter: Int) -> Void = { _ in },
  160. start: @escaping () -> Void = { },
  161. progressHandler: @escaping (_ totalBytesExpected: Int64, _ totalBytes: Int64, _ fractionCompleted: Double) -> Void = { _, _, _ in },
  162. completion: @escaping (_ account: String, _ file: NKFile?, _ afError: AFError?, _ error: NKError) -> Void) {
  163. let directory = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId)
  164. let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
  165. let chunkFolder = NCManageDatabase.shared.getChunkFolder(account: metadata.account, ocId: metadata.ocId)
  166. let filesChunk = NCManageDatabase.shared.getChunks(account: metadata.account, ocId: metadata.ocId)
  167. var chunkSize = NCGlobal.shared.chunkSizeMBCellular
  168. if NCNetworking.shared.networkReachability == NKCommon.TypeReachability.reachableEthernetOrWiFi {
  169. chunkSize = NCGlobal.shared.chunkSizeMBEthernetOrWiFi
  170. }
  171. let options = NKRequestOptions(customHeader: customHeaders, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
  172. NextcloudKit.shared.uploadChunk(directory: directory, fileName: metadata.fileName, date: metadata.date as Date, creationDate: metadata.creationDate as Date, serverUrl: metadata.serverUrl, chunkFolder: chunkFolder, filesChunk: filesChunk, chunkSize: chunkSize, options: options) { num in
  173. numChunks(num)
  174. } counterChunk: { counter in
  175. counterChunk(counter)
  176. } start: { filesChunk in
  177. start()
  178. NCManageDatabase.shared.addChunks(account: metadata.account, ocId: metadata.ocId, chunkFolder: chunkFolder, filesChunk: filesChunk)
  179. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile),
  180. object: nil,
  181. userInfo: ["ocId": metadata.ocId,
  182. "serverUrl": metadata.serverUrl,
  183. "account": metadata.account,
  184. "fileName": metadata.fileName,
  185. "sessionSelector": metadata.sessionSelector])
  186. } requestHandler: { request in
  187. self.uploadRequest[fileNameLocalPath] = request
  188. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  189. status: NCGlobal.shared.metadataStatusUploading)
  190. } taskHandler: { task in
  191. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  192. taskIdentifier: task.taskIdentifier)
  193. } progressHandler: { totalBytesExpected, totalBytes, fractionCompleted in
  194. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask),
  195. object: nil,
  196. userInfo: ["account": metadata.account,
  197. "ocId": metadata.ocId,
  198. "fileName": metadata.fileName,
  199. "serverUrl": metadata.serverUrl,
  200. "status": NSNumber(value: NCGlobal.shared.metadataStatusUploading),
  201. "chunk": metadata.chunk,
  202. "e2eEncrypted": metadata.e2eEncrypted,
  203. "progress": NSNumber(value: fractionCompleted),
  204. "totalBytes": NSNumber(value: totalBytes),
  205. "totalBytesExpected": NSNumber(value: totalBytesExpected)])
  206. progressHandler(totalBytesExpected, totalBytes, fractionCompleted)
  207. } uploaded: { fileChunk in
  208. NCManageDatabase.shared.deleteChunk(account: metadata.account, ocId: metadata.ocId, fileChunk: fileChunk, directory: directory)
  209. } completion: { account, _, file, afError, error in
  210. self.uploadRequest.removeValue(forKey: fileNameLocalPath)
  211. if error == .success {
  212. NCManageDatabase.shared.deleteChunks(account: account, ocId: metadata.ocId, directory: directory)
  213. }
  214. if withUploadComplete {
  215. self.uploadComplete(metadata: metadata, ocId: file?.ocId, etag: file?.etag, date: file?.date, size: file?.size ?? 0, error: error)
  216. }
  217. completion(account, file, afError, error)
  218. }
  219. }
  220. private func uploadFileInBackground(metadata: tableMetadata,
  221. start: @escaping () -> Void = { },
  222. completion: @escaping (_ error: NKError) -> Void) {
  223. var session: URLSession?
  224. let metadata = tableMetadata.init(value: metadata)
  225. let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
  226. let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
  227. if metadata.session == sessionUploadBackground || metadata.session == sessionUploadBackgroundExtension {
  228. session = sessionManagerUploadBackground
  229. } else if metadata.session == sessionUploadBackgroundWWan {
  230. session = sessionManagerUploadBackgroundWWan
  231. }
  232. start()
  233. // Check file dim > 0
  234. if utilityFileSystem.getFileSize(filePath: fileNameLocalPath) == 0 && metadata.size != 0 {
  235. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  236. completion(NKError(errorCode: NCGlobal.shared.errorResourceNotFound, errorDescription: NSLocalizedString("_error_not_found_", value: "The requested resource could not be found", comment: "")))
  237. } else {
  238. if let task = nkBackground.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, session: session!) {
  239. NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Upload file \(metadata.fileNameView) with task with taskIdentifier \(task.taskIdentifier)")
  240. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  241. status: NCGlobal.shared.metadataStatusUploading,
  242. taskIdentifier: task.taskIdentifier)
  243. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile),
  244. object: nil,
  245. userInfo: ["ocId": metadata.ocId,
  246. "serverUrl": metadata.serverUrl,
  247. "account": metadata.account,
  248. "fileName": metadata.fileName,
  249. "sessionSelector": metadata.sessionSelector])
  250. completion(NKError())
  251. } else {
  252. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  253. completion(NKError(errorCode: NCGlobal.shared.errorResourceNotFound, errorDescription: "task null"))
  254. }
  255. }
  256. }
  257. func uploadComplete(fileName: String,
  258. serverUrl: String,
  259. ocId: String?,
  260. etag: String?,
  261. date: NSDate?,
  262. size: Int64,
  263. task: URLSessionTask,
  264. error: NKError) {
  265. guard let url = task.currentRequest?.url,
  266. let metadata = NCManageDatabase.shared.getMetadata(from: url, sessionTaskIdentifier: task.taskIdentifier) else { return }
  267. uploadComplete(metadata: metadata, ocId: ocId, etag: etag, date: date, size: size, error: error)
  268. }
  269. func uploadComplete(metadata: tableMetadata,
  270. ocId: String?,
  271. etag: String?,
  272. date: NSDate?,
  273. size: Int64,
  274. error: NKError) {
  275. DispatchQueue.main.async {
  276. var isApplicationStateActive = false
  277. #if !EXTENSION
  278. isApplicationStateActive = UIApplication.shared.applicationState == .active
  279. #endif
  280. DispatchQueue.global(qos: .userInteractive).async {
  281. let ocIdTemp = metadata.ocId
  282. let selector = metadata.sessionSelector
  283. self.uploadMetadataInBackground.removeValue(forKey: FileNameServerUrl(fileName: metadata.fileName, serverUrl: metadata.serverUrl))
  284. if error == .success, let ocId = ocId, size == metadata.size {
  285. self.removeTransferInError(ocId: ocIdTemp)
  286. let metadata = tableMetadata.init(value: metadata)
  287. metadata.uploadDate = date ?? NSDate()
  288. metadata.etag = etag ?? ""
  289. metadata.ocId = ocId
  290. metadata.chunk = 0
  291. if let fileId = self.utility.ocIdToFileId(ocId: ocId) {
  292. metadata.fileId = fileId
  293. }
  294. metadata.session = ""
  295. metadata.sessionError = ""
  296. metadata.status = NCGlobal.shared.metadataStatusNormal
  297. NCManageDatabase.shared.addMetadata(metadata)
  298. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocIdTemp))
  299. if selector == NCGlobal.shared.selectorUploadFileNODelete {
  300. self.utilityFileSystem.moveFile(atPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(ocIdTemp), toPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId))
  301. NCManageDatabase.shared.addLocalFile(metadata: metadata)
  302. } else {
  303. self.utilityFileSystem.removeFile(atPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(ocIdTemp))
  304. }
  305. NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Upload complete " + metadata.serverUrl + "/" + metadata.fileName + ", result: success(\(size) bytes)")
  306. let userInfo: [AnyHashable: Any] = ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "fileName": metadata.fileName, "ocIdTemp": ocIdTemp, "error": error]
  307. if metadata.isLivePhoto, NCGlobal.shared.isLivePhotoServerAvailable {
  308. self.uploadLivePhoto(metadata: metadata, userInfo: userInfo)
  309. } else {
  310. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
  311. object: nil,
  312. userInfo: userInfo)
  313. }
  314. } else {
  315. if error.errorCode == NSURLErrorCancelled || error.errorCode == NCGlobal.shared.errorRequestExplicityCancelled {
  316. self.removeTransferInError(ocId: ocIdTemp)
  317. self.utilityFileSystem.removeFile(atPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
  318. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  319. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile),
  320. object: nil,
  321. userInfo: ["ocId": metadata.ocId,
  322. "serverUrl": metadata.serverUrl,
  323. "account": metadata.account])
  324. } else if error.errorCode == NCGlobal.shared.errorBadRequest || error.errorCode == NCGlobal.shared.errorUnsupportedMediaType {
  325. self.removeTransferInError(ocId: ocIdTemp)
  326. self.utilityFileSystem.removeFile(atPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
  327. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  328. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile),
  329. object: nil,
  330. userInfo: ["ocId": metadata.ocId,
  331. "serverUrl": metadata.serverUrl,
  332. "account": metadata.account])
  333. if isApplicationStateActive {
  334. NCContentPresenter().showError(error: NKError(errorCode: error.errorCode, errorDescription: "_virus_detect_"))
  335. }
  336. // Client Diagnostic
  337. NCManageDatabase.shared.addDiagnostic(account: metadata.account, issue: NCGlobal.shared.diagnosticIssueVirusDetected)
  338. } else if error.errorCode == NCGlobal.shared.errorForbidden && isApplicationStateActive {
  339. self.removeTransferInError(ocId: ocIdTemp)
  340. #if !EXTENSION
  341. DispatchQueue.main.async {
  342. let newFileName = self.utilityFileSystem.createFileName(metadata.fileName, serverUrl: metadata.serverUrl, account: metadata.account)
  343. let alertController = UIAlertController(title: error.errorDescription, message: NSLocalizedString("_change_upload_filename_", comment: ""), preferredStyle: .alert)
  344. alertController.addAction(UIAlertAction(title: String(format: NSLocalizedString("_save_file_as_", comment: ""), newFileName), style: .default, handler: { _ in
  345. let atpath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + metadata.fileName
  346. let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + newFileName
  347. self.utilityFileSystem.moveFile(atPath: atpath, toPath: toPath)
  348. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  349. newFileName: newFileName,
  350. sessionError: "",
  351. status: NCGlobal.shared.metadataStatusWaitUpload,
  352. errorCode: error.errorCode)
  353. }))
  354. alertController.addAction(UIAlertAction(title: NSLocalizedString("_discard_changes_", comment: ""), style: .destructive, handler: { _ in
  355. self.utilityFileSystem.removeFile(atPath: self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
  356. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  357. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile),
  358. object: nil,
  359. userInfo: ["ocId": metadata.ocId,
  360. "serverUrl": metadata.serverUrl,
  361. "account": metadata.account])
  362. }))
  363. // Select UIWindowScene active in serverUrl
  364. var controller = UIApplication.shared.firstWindow?.rootViewController
  365. let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
  366. for windowScene in windowScenes {
  367. if let rootViewController = windowScene.keyWindow?.rootViewController as? NCMainTabBarController,
  368. rootViewController.currentServerUrl() == metadata.serverUrl {
  369. controller = rootViewController
  370. break
  371. }
  372. }
  373. controller?.present(alertController, animated: true)
  374. // Client Diagnostic
  375. NCManageDatabase.shared.addDiagnostic(account: metadata.account, issue: NCGlobal.shared.diagnosticIssueProblems, error: NCGlobal.shared.diagnosticProblemsForbidden)
  376. }
  377. #endif
  378. } else {
  379. self.transferInError(ocId: metadata.ocId)
  380. NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
  381. sessionError: error.errorDescription,
  382. status: NCGlobal.shared.metadataStatusUploadError,
  383. errorCode: error.errorCode)
  384. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile),
  385. object: nil,
  386. userInfo: ["ocId": metadata.ocId,
  387. "serverUrl": metadata.serverUrl,
  388. "account": metadata.account,
  389. "fileName": metadata.fileName,
  390. "ocIdTemp": ocIdTemp,
  391. "error": error])
  392. // Client Diagnostic
  393. if error.errorCode == NCGlobal.shared.errorInternalServerError {
  394. NCManageDatabase.shared.addDiagnostic(account: metadata.account, issue: NCGlobal.shared.diagnosticIssueProblems, error: NCGlobal.shared.diagnosticProblemsBadResponse)
  395. } else {
  396. NCManageDatabase.shared.addDiagnostic(account: metadata.account, issue: NCGlobal.shared.diagnosticIssueProblems, error: NCGlobal.shared.diagnosticProblemsUploadServerError)
  397. }
  398. }
  399. }
  400. }
  401. }
  402. }
  403. func uploadProgress(_ progress: Float,
  404. totalBytes: Int64,
  405. totalBytesExpected: Int64,
  406. fileName: String,
  407. serverUrl: String,
  408. session: URLSession,
  409. task: URLSessionTask) {
  410. DispatchQueue.global().async {
  411. var metadata: tableMetadata?
  412. if let metadataTmp = self.uploadMetadataInBackground[FileNameServerUrl(fileName: fileName, serverUrl: serverUrl)] {
  413. metadata = metadataTmp
  414. } else if let metadataTmp = NCManageDatabase.shared.getMetadataFromFileName(fileName, serverUrl: serverUrl) {
  415. self.uploadMetadataInBackground[FileNameServerUrl(fileName: fileName, serverUrl: serverUrl)] = metadataTmp
  416. metadata = metadataTmp
  417. }
  418. if let metadata {
  419. NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask),
  420. object: nil,
  421. userInfo: ["account": metadata.account,
  422. "ocId": metadata.ocId,
  423. "fileName": metadata.fileName,
  424. "serverUrl": serverUrl,
  425. "status": NSNumber(value: NCGlobal.shared.metadataStatusUploading),
  426. "chunk": metadata.chunk,
  427. "e2eEncrypted": metadata.e2eEncrypted,
  428. "progress": NSNumber(value: progress),
  429. "totalBytes": NSNumber(value: totalBytes),
  430. "totalBytesExpected": NSNumber(value: totalBytesExpected)])
  431. }
  432. }
  433. }
  434. func getUploadBackgroundSession(queue: DispatchQueue = .main,
  435. completion: @escaping (_ filesNameLocalPath: [String]) -> Void) {
  436. var filesNameLocalPath: [String] = []
  437. sessionManagerUploadBackground.getAllTasks(completionHandler: { tasks in
  438. for task in tasks {
  439. filesNameLocalPath.append(task.description)
  440. }
  441. self.sessionManagerUploadBackgroundWWan.getAllTasks(completionHandler: { tasks in
  442. for task in tasks {
  443. filesNameLocalPath.append(task.description)
  444. }
  445. queue.async { completion(filesNameLocalPath) }
  446. })
  447. })
  448. }
  449. func cancelUploadTasks() {
  450. uploadRequest.removeAll()
  451. let sessionManager = NextcloudKit.shared.sessionManager
  452. sessionManager.session.getTasksWithCompletionHandler { _, uploadTasks, _ in
  453. uploadTasks.forEach {
  454. $0.cancel()
  455. }
  456. }
  457. if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status > 0 AND session == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload)) {
  458. NCManageDatabase.shared.deleteMetadata(results: results)
  459. }
  460. }
  461. func cancelUploadBackgroundTask() {
  462. Task {
  463. let tasksBackground = await NCNetworking.shared.sessionManagerUploadBackground.tasks
  464. for task in tasksBackground.1 { // ([URLSessionDataTask], [URLSessionUploadTask], [URLSessionDownloadTask])
  465. task.cancel()
  466. }
  467. let tasksBackgroundWWan = await NCNetworking.shared.sessionManagerUploadBackgroundWWan.tasks
  468. for task in tasksBackgroundWWan.1 { // ([URLSessionDataTask], [URLSessionUploadTask], [URLSessionDownloadTask])
  469. task.cancel()
  470. }
  471. if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status > 0 AND (session == %@ || session == %@)", NCNetworking.shared.sessionUploadBackground, NCNetworking.shared.sessionUploadBackgroundWWan)) {
  472. NCManageDatabase.shared.deleteMetadata(results: results)
  473. }
  474. }
  475. }
  476. }