NCOperationQueue.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. //
  2. // NCOperationQueue.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 03/06/2020.
  6. // Copyright © 2020 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 Foundation
  24. import Queuer
  25. import NCCommunication
  26. @objc class NCOperationQueue: NSObject {
  27. @objc public static let shared: NCOperationQueue = {
  28. let instance = NCOperationQueue()
  29. return instance
  30. }()
  31. private var downloadQueue = Queuer(name: "downloadQueue", maxConcurrentOperationCount: 5, qualityOfService: .default)
  32. private let deleteQueue = Queuer(name: "deleteQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
  33. private let copyMoveQueue = Queuer(name: "copyMoveQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
  34. private let synchronizationQueue = Queuer(name: "synchronizationQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
  35. private let downloadThumbnailQueue = Queuer(name: "downloadThumbnailQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
  36. private var timerReadFileForMediaQueue: Timer?
  37. @objc func cancelAllQueue() {
  38. downloadCancelAll()
  39. deleteCancelAll()
  40. copyMoveCancelAll()
  41. synchronizationCancelAll()
  42. downloadThumbnailCancelAll()
  43. }
  44. // Download file
  45. @objc func download(metadata: tableMetadata, selector: String, setFavorite: Bool, forceDownload: Bool) {
  46. if !forceDownload && CCUtility.fileProviderStorageSize(metadata.ocId, fileNameView: metadata.fileNameView) > 0 {
  47. NotificationCenter.default.postOnMainThread(name: k_notificationCenter_downloadedFile, userInfo: ["metadata":metadata, "selector":selector, "errorCode":0, "errorDescription":""])
  48. return
  49. }
  50. for operation in downloadQueue.operations as! [NCOperationDownload] {
  51. if operation.metadata.ocId == metadata.ocId {
  52. return
  53. }
  54. }
  55. downloadQueue.addOperation(NCOperationDownload.init(metadata: metadata, selector: selector, setFavorite: setFavorite))
  56. }
  57. @objc func downloadCancelAll() {
  58. downloadQueue.cancelAll()
  59. }
  60. @objc func downloadCount() -> Int {
  61. return downloadQueue.operationCount
  62. }
  63. @objc func downloadExists(metadata: tableMetadata) -> Bool {
  64. for operation in downloadQueue.operations as! [NCOperationDownload] {
  65. if operation.metadata.ocId == metadata.ocId {
  66. return true
  67. }
  68. }
  69. return false
  70. }
  71. // Delete file
  72. @objc func delete(metadata: tableMetadata, onlyLocal: Bool) {
  73. for operation in deleteQueue.operations as! [NCOperationDelete] {
  74. if operation.metadata.ocId == metadata.ocId {
  75. return
  76. }
  77. }
  78. deleteQueue.addOperation(NCOperationDelete.init(metadata: metadata, onlyLocal: onlyLocal))
  79. }
  80. @objc func deleteCancelAll() {
  81. deleteQueue.cancelAll()
  82. }
  83. @objc func deleteCount() -> Int {
  84. return deleteQueue.operationCount
  85. }
  86. // Copy Move file
  87. @objc func copyMove(metadata: tableMetadata, serverUrl: String, overwrite: Bool, move: Bool) {
  88. for operation in copyMoveQueue.operations as! [NCOperationCopyMove] {
  89. if operation.metadata.ocId == metadata.ocId {
  90. return
  91. }
  92. }
  93. copyMoveQueue.addOperation(NCOperationCopyMove.init(metadata: metadata, serverUrlTo: serverUrl, overwrite: overwrite, move: move))
  94. }
  95. @objc func copyMoveCancelAll() {
  96. copyMoveQueue.cancelAll()
  97. }
  98. @objc func copyMoveCount() -> Int {
  99. return copyMoveQueue.operationCount
  100. }
  101. // Synchronization
  102. @objc func synchronizationMetadata(_ metadata: tableMetadata, selector: String) {
  103. for operation in synchronizationQueue.operations as! [NCOperationSynchronization] {
  104. if operation.metadata.ocId == metadata.ocId {
  105. return
  106. }
  107. }
  108. synchronizationQueue.addOperation(NCOperationSynchronization.init(metadata: metadata, selector: selector))
  109. }
  110. @objc func synchronizationCancelAll() {
  111. synchronizationQueue.cancelAll()
  112. }
  113. // Download Thumbnail
  114. @objc func downloadThumbnail(metadata: tableMetadata, urlBase: String, view: Any, indexPath: IndexPath) {
  115. if metadata.hasPreview && metadata.status == k_metadataStatusNormal && (!CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) {
  116. for operation in downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] {
  117. if operation.metadata.ocId == metadata.ocId {
  118. return
  119. }
  120. }
  121. downloadThumbnailQueue.addOperation(NCOperationDownloadThumbnail.init(metadata: metadata, urlBase: urlBase, view: view, indexPath: indexPath))
  122. }
  123. }
  124. func cancelDownloadThumbnail(metadata: tableMetadata) {
  125. for operation in downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] {
  126. if operation.metadata.ocId == metadata.ocId {
  127. operation.cancel()
  128. }
  129. }
  130. }
  131. @objc func downloadThumbnailCancelAll() {
  132. downloadThumbnailQueue.cancelAll()
  133. }
  134. }
  135. //MARK: -
  136. class NCOperationDownload: ConcurrentOperation {
  137. var metadata: tableMetadata
  138. var selector: String
  139. var setFavorite: Bool
  140. init(metadata: tableMetadata, selector: String, setFavorite: Bool) {
  141. self.metadata = tableMetadata.init(value: metadata)
  142. self.selector = selector
  143. self.setFavorite = setFavorite
  144. }
  145. override func start() {
  146. if isCancelled {
  147. self.finish()
  148. } else {
  149. NCNetworking.shared.download(metadata: metadata, selector: self.selector, setFavorite: self.setFavorite) { (_) in
  150. self.finish()
  151. }
  152. }
  153. }
  154. }
  155. //MARK: -
  156. class NCOperationDelete: ConcurrentOperation {
  157. var metadata: tableMetadata
  158. var onlyLocal: Bool
  159. init(metadata: tableMetadata, onlyLocal: Bool) {
  160. self.metadata = tableMetadata.init(value: metadata)
  161. self.onlyLocal = onlyLocal
  162. }
  163. override func start() {
  164. if isCancelled {
  165. self.finish()
  166. } else {
  167. NCNetworking.shared.deleteMetadata(metadata, account: metadata.account, urlBase: metadata.urlBase, onlyLocal: onlyLocal) { (errorCode, errorDescription) in
  168. if errorCode != 0 {
  169. NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: TimeInterval(k_dismissAfterSecond), type: NCContentPresenter.messageType.error, errorCode: errorCode)
  170. }
  171. self.finish()
  172. }
  173. }
  174. }
  175. }
  176. //MARK: -
  177. class NCOperationCopyMove: ConcurrentOperation {
  178. var metadata: tableMetadata
  179. var serverUrlTo: String
  180. var overwrite: Bool
  181. var move: Bool
  182. init(metadata: tableMetadata, serverUrlTo: String, overwrite: Bool, move: Bool) {
  183. self.metadata = tableMetadata.init(value: metadata)
  184. self.serverUrlTo = serverUrlTo
  185. self.overwrite = overwrite
  186. self.move = move
  187. }
  188. override func start() {
  189. if isCancelled {
  190. self.finish()
  191. } else {
  192. if move {
  193. NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in
  194. if errorCode != 0 {
  195. NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: TimeInterval(k_dismissAfterSecond), type: NCContentPresenter.messageType.error, errorCode: errorCode)
  196. }
  197. self.finish()
  198. }
  199. } else {
  200. NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrlTo, overwrite: overwrite) { (errorCode, errorDescription) in
  201. if errorCode != 0 {
  202. NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: TimeInterval(k_dismissAfterSecond), type: NCContentPresenter.messageType.error, errorCode: errorCode)
  203. }
  204. self.finish()
  205. }
  206. }
  207. }
  208. }
  209. }
  210. //MARK: -
  211. class NCOperationSynchronization: ConcurrentOperation {
  212. var metadata: tableMetadata
  213. var selector: String
  214. var download: Bool
  215. init(metadata: tableMetadata, selector: String) {
  216. self.metadata = tableMetadata.init(value: metadata)
  217. self.selector = selector
  218. if selector == selectorDownloadFile {
  219. self.download = true
  220. } else {
  221. self.download = false
  222. }
  223. }
  224. override func start() {
  225. if isCancelled {
  226. self.finish()
  227. } else {
  228. if metadata.directory {
  229. let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
  230. NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in
  231. if errorCode == 0 {
  232. NCManageDatabase.sharedInstance.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: true, account: account) { (metadataFolder, metadatasFolder, metadatas) in
  233. let metadatasResult = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrlFileName, k_metadataStatusNormal))
  234. if self.selector == selectorDownloadAllFile {
  235. NCManageDatabase.sharedInstance.updateMetadatas(metadatas, metadatasResult: metadatasResult)
  236. for metadata in metadatas {
  237. if metadata.directory {
  238. NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector)
  239. } else {
  240. let localFile = NCManageDatabase.sharedInstance.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  241. if localFile == nil || localFile?.etag != metadata.etag {
  242. NCOperationQueue.shared.download(metadata: metadata, selector: self.selector, setFavorite: false, forceDownload: true)
  243. }
  244. }
  245. }
  246. } else {
  247. let metadatasChanged = NCManageDatabase.sharedInstance.updateMetadatas(metadatas, metadatasResult: metadatasResult, addExistsInLocal: self.download, addCompareEtagLocal: true)
  248. for metadata in metadatasChanged.metadatasUpdate {
  249. if metadata.directory {
  250. NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector)
  251. }
  252. }
  253. for metadata in metadatasChanged.metadatasLocalUpdate {
  254. NCOperationQueue.shared.download(metadata: metadata, selector: self.selector, setFavorite: false, forceDownload: true)
  255. }
  256. }
  257. // Update etag directory
  258. NCManageDatabase.sharedInstance.addDirectory(encrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, serverUrl: serverUrlFileName, richWorkspace: metadataFolder.richWorkspace, account: metadataFolder.account)
  259. }
  260. } else if errorCode == k_CCErrorResourceNotFound && self.metadata.directory {
  261. NCManageDatabase.sharedInstance.deleteDirectoryAndSubDirectory(serverUrl: self.metadata.serverUrl, account: self.metadata.account)
  262. }
  263. self.finish()
  264. }
  265. } else {
  266. if self.download {
  267. let localFile = NCManageDatabase.sharedInstance.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
  268. if localFile == nil || localFile?.etag != metadata.etag {
  269. NCOperationQueue.shared.download(metadata: metadata, selector: self.selector, setFavorite: false, forceDownload: true)
  270. }
  271. }
  272. self.finish()
  273. }
  274. }
  275. }
  276. }
  277. //MARK: -
  278. class NCOperationDownloadThumbnail: ConcurrentOperation {
  279. var metadata: tableMetadata
  280. var urlBase: String
  281. var view: Any
  282. var indexPath: IndexPath
  283. init(metadata: tableMetadata, urlBase: String, view: Any, indexPath: IndexPath) {
  284. self.metadata = tableMetadata.init(value: metadata)
  285. self.urlBase = urlBase
  286. self.view = view
  287. self.indexPath = indexPath
  288. }
  289. override func start() {
  290. if isCancelled {
  291. self.finish()
  292. } else {
  293. let fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: urlBase, account: metadata.account)!
  294. let fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)!
  295. let fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)!
  296. NCCommunication.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, fileNamePreviewLocalPath: fileNamePreviewLocalPath , widthPreview: Int(k_sizePreview), heightPreview: Int(k_sizePreview), fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: Int(k_sizeIcon)) { (account, imagePreview, imageIcon, errorCode, errorDescription) in
  297. var cell: NCImageCellProtocol?
  298. if self.view is UICollectionView {
  299. if self.indexPath.section < (self.view as! UICollectionView).numberOfSections && self.indexPath.row < (self.view as! UICollectionView).numberOfItems(inSection: self.indexPath.section) {
  300. cell = (self.view as! UICollectionView).cellForItem(at: self.indexPath) as? NCImageCellProtocol
  301. }
  302. } else {
  303. if self.indexPath.section < (self.view as! UITableView).numberOfSections && self.indexPath.row < (self.view as! UITableView).numberOfRows(inSection: self.indexPath.section) {
  304. cell = (self.view as! UITableView).cellForRow(at: self.indexPath) as? NCImageCellProtocol
  305. }
  306. }
  307. if (cell != nil) {
  308. var previewImage: UIImage!
  309. if errorCode == 0 && imageIcon != nil {
  310. previewImage = imageIcon
  311. } else {
  312. if self.metadata.iconName.count > 0 {
  313. previewImage = UIImage(named: self.metadata.iconName)
  314. } else {
  315. previewImage = UIImage(named: "file")
  316. }
  317. }
  318. cell!.filePreviewImageView.backgroundColor = nil
  319. UIView.transition(with: cell!.filePreviewImageView,
  320. duration: 0.75,
  321. options: .transitionCrossDissolve,
  322. animations: { cell!.filePreviewImageView.image = previewImage! },
  323. completion: nil)
  324. }
  325. self.finish()
  326. }
  327. }
  328. }
  329. }