123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- //
- // NCOperationQueue.swift
- // Nextcloud
- //
- // Created by Marino Faggiana on 03/06/2020.
- // Copyright © 2020 Marino Faggiana. All rights reserved.
- //
- // Author Marino Faggiana <marino.faggiana@nextcloud.com>
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- import UIKit
- import Queuer
- import NextcloudKit
- @objc class NCOperationQueue: NSObject {
- @objc public static let shared: NCOperationQueue = {
- let instance = NCOperationQueue()
- return instance
- }()
- private var downloadQueue = Queuer(name: "downloadQueue", maxConcurrentOperationCount: 5, qualityOfService: .default)
- private let synchronizationQueue = Queuer(name: "synchronizationQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
- private let downloadThumbnailQueue = Queuer(name: "downloadThumbnailQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
- private let downloadThumbnailActivityQueue = Queuer(name: "downloadThumbnailActivityQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
- private let downloadAvatarQueue = Queuer(name: "downloadAvatarQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
- private let unifiedSearchQueue = Queuer(name: "unifiedSearchQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
- private let readFileQueue = Queuer(name: "readFileQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
- @objc func cancelAllQueue() {
- downloadCancelAll()
- synchronizationCancelAll()
- downloadThumbnailCancelAll()
- downloadThumbnailActivityCancelAll()
- downloadAvatarCancelAll()
- unifiedSearchCancelAll()
- readFileCancelAll()
- }
- // MARK: - Download file
- func download(metadata: tableMetadata, selector: String) {
- for case let operation as NCOperationDownload in downloadQueue.operations where operation.metadata.ocId == metadata.ocId {
- return
- }
- downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: selector))
- }
- func downloadCancelAll() {
- downloadQueue.cancelAll()
- }
- func downloadQueueCount() -> Int {
- return downloadQueue.operationCount
- }
- func downloadExists(metadata: tableMetadata) -> Bool {
- for case let operation as NCOperationDownload in downloadQueue.operations where operation.metadata.ocId == metadata.ocId {
- return true
- }
- return false
- }
- // MARK: - Synchronization
- func synchronizationMetadata(_ metadata: tableMetadata, selector: String) {
- for case let operation as NCOperationSynchronization in synchronizationQueue.operations where operation.metadata.ocId == metadata.ocId {
- return
- }
- synchronizationQueue.addOperation(NCOperationSynchronization(metadata: metadata, selector: selector))
- }
- func synchronizationCancelAll() {
- synchronizationQueue.cancelAll()
- }
- // MARK: - Download Thumbnail
- func downloadThumbnail(metadata: tableMetadata, placeholder: Bool, cell: UIView?, view: UIView?) {
- let cell: NCCellProtocol? = cell as? NCCellProtocol
- if placeholder {
- if metadata.iconName.isEmpty {
- cell?.filePreviewImageView?.image = NCBrandColor.cacheImages.file
- } else {
- cell?.filePreviewImageView?.image = UIImage(named: metadata.iconName)
- }
- }
- if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && (!CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) {
- for case let operation as NCOperationDownloadThumbnail in downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId {
- return
- }
- downloadThumbnailQueue.addOperation(NCOperationDownloadThumbnail(metadata: metadata, cell: cell, view: view))
- }
- }
- func cancelDownloadThumbnail(metadata: tableMetadata) {
- for case let operation as NCOperationDownloadThumbnail in downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId {
- operation.cancel()
- }
- }
- func downloadThumbnailCancelAll() {
- downloadThumbnailQueue.cancelAll()
- }
- // MARK: - Download Thumbnail Activity
- func downloadThumbnailActivity(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell, collectionView: UICollectionView?) {
- cell.imageView?.image = UIImage(named: "file_photo")
- cell.fileId = fileId
- if !FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
- for case let operation as NCOperationDownloadThumbnailActivity in downloadThumbnailActivityQueue.operations where operation.fileId == fileId {
- return
- }
- downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, fileId: fileId, cell: cell, collectionView: collectionView))
- }
- }
- func cancelDownloadThumbnailActivity(fileId: String) {
- for case let operation as NCOperationDownloadThumbnailActivity in downloadThumbnailActivityQueue.operations where operation.fileId == fileId {
- operation.cancel()
- }
- }
- func downloadThumbnailActivityCancelAll() {
- downloadThumbnailActivityQueue.cancelAll()
- }
- // MARK: - Download Avatar
- func downloadAvatar(user: String, dispalyName: String?, fileName: String, cell: NCCellProtocol, view: UIView?, cellImageView: UIImageView?) {
- let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
- if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
- cellImageView?.image = image
- cell.fileAvatarImageView?.image = image
- return
- }
- if let account = NCManageDatabase.shared.getActiveAccount() {
- cellImageView?.image = NCUtility.shared.loadUserImage(
- for: user,
- displayName: dispalyName,
- userBaseUrl: account)
- }
- for case let operation as NCOperationDownloadAvatar in downloadAvatarQueue.operations where operation.fileName == fileName {
- return
- }
- downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: user, fileName: fileName, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view, cellImageView: cellImageView))
- }
- func cancelDownloadAvatar(user: String) {
- for case let operation as NCOperationDownloadAvatar in downloadAvatarQueue.operations where operation.user == user {
- operation.cancel()
- }
- }
- func downloadAvatarCancelAll() {
- downloadAvatarQueue.cancelAll()
- }
- // MARK: - Unified Search
- func unifiedSearchAddSection(collectionViewCommon: NCCollectionViewCommon, metadatas: [tableMetadata], searchResult: NKSearchResult) {
- unifiedSearchQueue.addOperation(NCOperationUnifiedSearch(collectionViewCommon: collectionViewCommon, metadatas: metadatas, searchResult: searchResult))
- }
- func unifiedSearchCancelAll() {
- unifiedSearchQueue.cancelAll()
- }
- // MARK: - Read file
- func readFile(serverUrlFileName: String) {
- for case let operation as NCOperationReadFile in readFileQueue.operations where operation.serverUrlFileName == serverUrlFileName {
- return
- }
- readFileQueue.addOperation(NCOperationReadFile(serverUrlFileName: serverUrlFileName))
- }
- func readFileCancelAll() {
- readFileQueue.cancelAll()
- }
- }
- // MARK: -
- class NCOperationDownload: ConcurrentOperation {
- var metadata: tableMetadata
- var selector: String
- init(metadata: tableMetadata, selector: String) {
- self.metadata = tableMetadata.init(value: metadata)
- self.selector = selector
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- NCNetworking.shared.download(metadata: metadata, selector: self.selector) { _, _ in
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationSynchronization: ConcurrentOperation {
- var metadata: tableMetadata
- var selector: String
- var download: Bool
- init(metadata: tableMetadata, selector: String) {
- self.metadata = tableMetadata.init(value: metadata)
- self.selector = selector
- if selector == NCGlobal.shared.selectorDownloadFile || selector == NCGlobal.shared.selectorDownloadAllFile {
- self.download = true
- } else {
- self.download = false
- }
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- if metadata.directory {
- let serverUrl = metadata.serverUrl + "/" + metadata.fileName
- let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, serverUrl))
- NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, error in
- if (error == .success) && (directory?.etag != files.first?.etag || self.selector == NCGlobal.shared.selectorDownloadAllFile) {
- let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
- NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { account, files, _, error in
- if error == .success {
- NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: true) { metadataFolder, _, metadatas in
- let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal))
- if self.selector == NCGlobal.shared.selectorDownloadAllFile {
- NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult)
- for metadata in metadatas {
- if metadata.directory {
- NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector)
- } else {
- if NCManageDatabase.shared.isDownloadMetadata(metadata, download: true) {
- NCOperationQueue.shared.download(metadata: metadata, selector: self.selector)
- }
- }
- }
- } else {
- let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addExistsInLocal: self.download, addCompareEtagLocal: true, addDirectorySynchronized: true)
- for metadata in metadatasChanged.metadatasUpdate {
- if metadata.directory {
- NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector)
- }
- }
- for metadata in metadatasChanged.metadatasLocalUpdate {
- NCOperationQueue.shared.download(metadata: metadata, selector: self.selector)
- }
- }
- // Update etag directory
- NCManageDatabase.shared.addDirectory(encrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, serverUrl: serverUrl, account: metadataFolder.account)
- }
- } else if error.errorCode == NCGlobal.shared.errorResourceNotFound && self.metadata.directory {
- NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: self.metadata.serverUrl, account: self.metadata.account)
- }
- self.finish()
- }
- } else {
- let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", account, serverUrl))
- for metadata in metadatas {
- if metadata.directory {
- NCOperationQueue.shared.synchronizationMetadata(metadata, selector: self.selector)
- } else {
- if NCManageDatabase.shared.isDownloadMetadata(metadata, download: self.download) {
- NCOperationQueue.shared.download(metadata: metadata, selector: self.selector)
- }
- }
- }
- self.finish()
- }
- }
- } else {
- if NCManageDatabase.shared.isDownloadMetadata(metadata, download: self.download) {
- NCOperationQueue.shared.download(metadata: metadata, selector: self.selector)
- }
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationDownloadThumbnail: ConcurrentOperation {
- var metadata: tableMetadata
- var cell: NCCellProtocol?
- var view: UIView?
- var fileNamePath: String
- var fileNamePreviewLocalPath: String
- var fileNameIconLocalPath: String
- init(metadata: tableMetadata, cell: NCCellProtocol?, view: UIView?) {
- self.metadata = tableMetadata.init(value: metadata)
- self.cell = cell
- self.view = view
- self.fileNamePath = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId, account: metadata.account)!
- self.fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)!
- self.fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)!
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- var etagResource: String?
- if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
- etagResource = metadata.etagResource
- }
- let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
- NextcloudKit.shared.downloadPreview(
- fileNamePathOrFileId: fileNamePath,
- fileNamePreviewLocalPath: fileNamePreviewLocalPath,
- widthPreview: NCGlobal.shared.sizePreview,
- heightPreview: NCGlobal.shared.sizePreview,
- fileNameIconLocalPath: fileNameIconLocalPath,
- sizeIcon: NCGlobal.shared.sizeIcon,
- etag: etagResource,
- options: options) { _, _, imageIcon, _, etag, error in
- if error == .success, let imageIcon = imageIcon {
- NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag)
- DispatchQueue.main.async {
- if self.metadata.ocId == self.cell?.fileObjectId, let filePreviewImageView = self.cell?.filePreviewImageView {
- UIView.transition(with: filePreviewImageView,
- duration: 0.75,
- options: .transitionCrossDissolve,
- animations: { filePreviewImageView.image = imageIcon },
- completion: nil)
- } else {
- if self.view is UICollectionView {
- (self.view as? UICollectionView)?.reloadData()
- } else if self.view is UITableView {
- (self.view as? UITableView)?.reloadData()
- }
- }
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedThumbnail, userInfo: ["ocId": self.metadata.ocId])
- }
- }
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationDownloadThumbnailActivity: ConcurrentOperation {
- var cell: NCActivityCollectionViewCell?
- var collectionView: UICollectionView?
- var fileNamePathOrFileId: String
- var fileNamePreviewLocalPath: String
- var fileId: String
- init(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) {
- self.fileNamePathOrFileId = fileNamePathOrFileId
- self.fileNamePreviewLocalPath = fileNamePreviewLocalPath
- self.fileId = fileId
- self.cell = cell
- self.collectionView = collectionView
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
- NextcloudKit.shared.downloadPreview(
- fileNamePathOrFileId: fileNamePathOrFileId,
- fileNamePreviewLocalPath: fileNamePreviewLocalPath,
- widthPreview: 0,
- heightPreview: 0,
- etag: nil,
- useInternalEndpoint: false,
- options: options) { _, imagePreview, _, _, _, error in
- if error == .success, let imagePreview = imagePreview {
- DispatchQueue.main.async {
- if self.fileId == self.cell?.fileId, let imageView = self.cell?.imageView {
- UIView.transition(with: imageView,
- duration: 0.75,
- options: .transitionCrossDissolve,
- animations: { imageView.image = imagePreview },
- completion: nil)
- } else {
- self.collectionView?.reloadData()
- }
- }
- }
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationDownloadAvatar: ConcurrentOperation {
- var user: String
- var fileName: String
- var etag: String?
- var fileNameLocalPath: String
- var cell: NCCellProtocol!
- var view: UIView?
- var cellImageView: UIImageView?
- init(user: String, fileName: String, fileNameLocalPath: String, cell: NCCellProtocol, view: UIView?, cellImageView: UIImageView?) {
- self.user = user
- self.fileName = fileName
- self.fileNameLocalPath = fileNameLocalPath
- self.cell = cell
- self.view = view
- self.etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
- self.cellImageView = cellImageView
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
- NextcloudKit.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: self.etag, options: options) { _, imageAvatar, _, etag, error in
- if error == .success, let imageAvatar = imageAvatar, let etag = etag {
- NCManageDatabase.shared.addAvatar(fileName: self.fileName, etag: etag)
- DispatchQueue.main.async {
- if self.user == self.cell.fileUser, let avatarImageView = self.cellImageView {
- UIView.transition(with: avatarImageView,
- duration: 0.75,
- options: .transitionCrossDissolve,
- animations: { avatarImageView.image = imageAvatar },
- completion: nil)
- } else {
- if self.view is UICollectionView {
- (self.view as? UICollectionView)?.reloadData()
- } else if self.view is UITableView {
- (self.view as? UITableView)?.reloadData()
- }
- }
- }
- } else if error.errorCode == NCGlobal.shared.errorNotModified {
- NCManageDatabase.shared.setAvatarLoaded(fileName: self.fileName)
- }
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationUnifiedSearch: ConcurrentOperation {
- var collectionViewCommon: NCCollectionViewCommon
- var metadatas: [tableMetadata]
- var searchResult: NKSearchResult
- init(collectionViewCommon: NCCollectionViewCommon, metadatas: [tableMetadata], searchResult: NKSearchResult) {
- self.collectionViewCommon = collectionViewCommon
- self.metadatas = metadatas
- self.searchResult = searchResult
- }
- func reloadDataThenPerform(_ closure: @escaping (() -> Void)) {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
- CATransaction.begin()
- CATransaction.setCompletionBlock(closure)
- self.collectionViewCommon.collectionView.reloadData()
- CATransaction.commit()
- }
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- self.collectionViewCommon.dataSource.addSection(metadatas: metadatas, searchResult: searchResult)
- self.collectionViewCommon.searchResults?.append(self.searchResult)
- reloadDataThenPerform {
- self.finish()
- }
- }
- }
- }
- // MARK: -
- class NCOperationReadFile: ConcurrentOperation {
- var serverUrlFileName: String
- init(serverUrlFileName: String) {
- self.serverUrlFileName = serverUrlFileName
- }
- override func start() {
- if isCancelled {
- self.finish()
- } else {
- NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName) { account, metadata, error in
- if error == .success, let metadata = metadata {
- NCManageDatabase.shared.addMetadata(metadata)
- if metadata.directory {
- NCManageDatabase.shared.addDirectory(encrypted: metadata.e2eEncrypted, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: self.serverUrlFileName, account: account)
- }
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterOperationReadFile, userInfo: ["ocId": metadata.ocId])
- }
- }
- }
- }
- }
|