FileProvider.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. //
  2. // FileProvider.swift
  3. // PickerFileProvider
  4. //
  5. // Created by Marino Faggiana on 27/12/16.
  6. // Copyright © 2017 TWS. All rights reserved.
  7. //
  8. // Author Marino Faggiana <m.faggiana@twsweb.it>
  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. class FileProvider: NSFileProviderExtension, CCNetworkingDelegate {
  25. lazy var networkingOperationQueue: OperationQueue = {
  26. var queue = OperationQueue()
  27. queue.name = k_queue
  28. queue.maxConcurrentOperationCount = 10
  29. return queue
  30. }()
  31. var fileCoordinator: NSFileCoordinator {
  32. let fileCoordinator = NSFileCoordinator()
  33. fileCoordinator.purposeIdentifier = self.providerIdentifier
  34. return fileCoordinator
  35. }
  36. override init() {
  37. super.init()
  38. self.fileCoordinator.coordinate(writingItemAt: self.documentStorageURL, options: [], error: nil, byAccessor: { newURL in
  39. // ensure the documentStorageURL actually exists
  40. do {
  41. try FileManager.default.createDirectory(at: newURL, withIntermediateDirectories: true, attributes: nil)
  42. } catch {
  43. // Handle error
  44. }
  45. })
  46. }
  47. override func providePlaceholder(at url: URL, completionHandler: ((_ error: Error?) -> Void)?) {
  48. // Should call writePlaceholderAtURL(_:withMetadata:error:) with the placeholder URL, then call the completion handler with the error if applicable.
  49. let fileName = url.lastPathComponent
  50. let placeholderURL = NSFileProviderExtension.placeholderURL(for: self.documentStorageURL.appendingPathComponent(fileName))
  51. // TODO: get file size for file at <url> from model
  52. let fileSize = 0
  53. let metadata = [AnyHashable(URLResourceKey.fileSizeKey): fileSize]
  54. do {
  55. try NSFileProviderExtension.writePlaceholder(at: placeholderURL, withMetadata: metadata)
  56. } catch {
  57. // Handle error
  58. }
  59. completionHandler?(nil)
  60. }
  61. override func startProvidingItem(at url: URL, completionHandler: ((_ error: Error?) -> Void)?) {
  62. guard let fileData = try? Data(contentsOf: url) else {
  63. // NOTE: you would generate an NSError to supply to the completionHandler
  64. // here however that is outside of the scope for this tutorial
  65. completionHandler?(nil)
  66. return
  67. }
  68. do {
  69. _ = try fileData.write(to: url, options: NSData.WritingOptions())
  70. completionHandler?(nil)
  71. } catch let error as NSError {
  72. print("error writing file to URL")
  73. completionHandler?(error)
  74. }
  75. }
  76. override func itemChanged(at url: URL) {
  77. // Called at some point after the file has changed; the provider may then trigger an upload
  78. let fileSize = (try! FileManager.default.attributesOfItem(atPath: url.path)[FileAttributeKey.size] as! NSNumber).uint64Value
  79. NSLog("Item changed at URL %@ %lu", url as NSURL, fileSize)
  80. guard let account = NCManageDatabase.sharedInstance.getAccountActive() else {
  81. self.stopProvidingItem(at: url)
  82. return
  83. }
  84. let directoryUser = CCUtility.getDirectoryActiveUser(account.user, activeUrl: account.url)
  85. guard let fileID = CCUtility.getFileIDExt() else {
  86. self.stopProvidingItem(at: url)
  87. return
  88. }
  89. let fileName = url.lastPathComponent
  90. if fileID == "NEW" {
  91. let destinationURLDirectoryUser = URL(string: "file://\(directoryUser!)/\(fileName)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!
  92. guard let serverUrl = CCUtility.getServerUrlExt() else {
  93. self.stopProvidingItem(at: url)
  94. return
  95. }
  96. // copy sourceURL on directoryUser
  97. do {
  98. try FileManager.default.removeItem(at: destinationURLDirectoryUser)
  99. } catch _ {
  100. print("file do not exists")
  101. }
  102. do {
  103. try FileManager.default.copyItem(at: url, to: destinationURLDirectoryUser)
  104. } catch _ {
  105. print("file do not exists")
  106. return
  107. }
  108. CCNetworking.shared().settingDelegate(self)
  109. CCNetworking.shared().uploadFile(fileName, serverUrl: serverUrl, cryptated: false, onlyPlist: false, session: k_upload_session, taskStatus: Int(k_taskStatusResume), selector: nil, selectorPost: nil, errorCode: 0, delegate: self)
  110. } else {
  111. guard let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: NSPredicate(format: "fileID == %@", fileID)) else {
  112. self.stopProvidingItem(at: url)
  113. return
  114. }
  115. if (fileName != metadata.fileName) {
  116. self.stopProvidingItem(at: url)
  117. return
  118. }
  119. let uploadID = k_uploadSessionID + CCUtility.createRandomString(16)
  120. let destinationURLDirectoryUser = URL(string: "file://\(directoryUser!)/\(uploadID)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!
  121. // copy sourceURL on directoryUser
  122. do {
  123. try FileManager.default.removeItem(at: destinationURLDirectoryUser)
  124. } catch _ {
  125. print("file do not exists")
  126. }
  127. do {
  128. try FileManager.default.copyItem(at: url, to: destinationURLDirectoryUser)
  129. } catch _ {
  130. print("file do not exists")
  131. return
  132. }
  133. // Prepare for send Metadata
  134. metadata.fileID = uploadID
  135. metadata.sessionID = uploadID
  136. metadata.session = k_upload_session
  137. metadata.sessionTaskIdentifier = Int(k_taskIdentifierWaitStart)
  138. _ = NCManageDatabase.sharedInstance.updateMetadata(metadata)
  139. }
  140. self.stopProvidingItem(at: url)
  141. }
  142. override func stopProvidingItem(at url: URL) {
  143. // Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file.
  144. // Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted.
  145. do {
  146. _ = try FileManager.default.removeItem(at: url)
  147. } catch {
  148. // Handle error
  149. }
  150. self.providePlaceholder(at: url, completionHandler: { error in
  151. // TODO: handle any error, do any necessary cleanup
  152. })
  153. }
  154. // UTILITY //
  155. func appGroupContainerURL() -> URL? {
  156. guard let groupURL = FileManager.default
  157. .containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.sharedInstance.capabilitiesGroups) else {
  158. return nil
  159. }
  160. let storagePathUrl = groupURL.appendingPathComponent("File Provider Storage")
  161. let storagePath = storagePathUrl.path
  162. if !FileManager.default.fileExists(atPath: storagePath) {
  163. do {
  164. try FileManager.default.createDirectory(atPath: storagePath, withIntermediateDirectories: false, attributes: nil)
  165. } catch let error {
  166. print("error creating filepath: \(error)")
  167. return nil
  168. }
  169. }
  170. return storagePathUrl
  171. }
  172. }