FileProvider.swift 8.3 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. guard let fileName = CCUtility.getFileNameExt() else {
  85. self.stopProvidingItem(at: url)
  86. return
  87. }
  88. // -------> Fix : Clear FileName for twice Office 365
  89. CCUtility.setFileNameExt("")
  90. // --------------------------------------------------
  91. if (fileName != url.lastPathComponent) {
  92. self.stopProvidingItem(at: url)
  93. return
  94. }
  95. guard let serverUrl = CCUtility.getServerUrlExt() else {
  96. self.stopProvidingItem(at: url)
  97. return
  98. }
  99. guard let directoryID = NCManageDatabase.sharedInstance.getDirectoryID(serverUrl) else {
  100. self.stopProvidingItem(at: url)
  101. return
  102. }
  103. let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: NSPredicate(format: "fileName == %@ AND directoryID == %@", fileName, directoryID))
  104. if metadata != nil {
  105. // Update
  106. let uploadID = k_uploadSessionID + CCUtility.createRandomString(16)
  107. let directoryUser = CCUtility.getDirectoryActiveUser(account.user, activeUrl: account.url)
  108. let destinationURLDirectoryUser = URL(string: "file://\(directoryUser!)/\(uploadID)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!
  109. // copy sourceURL on directoryUser
  110. do {
  111. try FileManager.default.removeItem(at: destinationURLDirectoryUser)
  112. } catch _ {
  113. print("file do not exists")
  114. }
  115. do {
  116. try FileManager.default.copyItem(at: url, to: destinationURLDirectoryUser)
  117. } catch _ {
  118. print("file do not exists")
  119. self.stopProvidingItem(at: url)
  120. return
  121. }
  122. // Prepare for send Metadata
  123. metadata!.sessionID = uploadID
  124. metadata!.session = k_upload_session
  125. metadata!.sessionTaskIdentifier = Int(k_taskIdentifierWaitStart)
  126. _ = NCManageDatabase.sharedInstance.updateMetadata(metadata!)
  127. } else {
  128. // New
  129. let directoryUser = CCUtility.getDirectoryActiveUser(account.user, activeUrl: account.url)
  130. let destinationURLDirectoryUser = URL(string: "file://\(directoryUser!)/\(fileName)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)!
  131. do {
  132. try FileManager.default.removeItem(at: destinationURLDirectoryUser)
  133. } catch _ {
  134. print("file do not exists")
  135. }
  136. do {
  137. try FileManager.default.copyItem(at: url, to: destinationURLDirectoryUser)
  138. } catch _ {
  139. print("file do not exists")
  140. self.stopProvidingItem(at: url)
  141. return
  142. }
  143. 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)
  144. }
  145. self.stopProvidingItem(at: url)
  146. }
  147. override func stopProvidingItem(at url: URL) {
  148. // 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.
  149. // Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted.
  150. do {
  151. _ = try FileManager.default.removeItem(at: url)
  152. } catch {
  153. // Handle error
  154. }
  155. self.providePlaceholder(at: url, completionHandler: { error in
  156. // TODO: handle any error, do any necessary cleanup
  157. })
  158. }
  159. // UTILITY //
  160. func appGroupContainerURL() -> URL? {
  161. guard let groupURL = FileManager.default
  162. .containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.sharedInstance.capabilitiesGroups) else {
  163. return nil
  164. }
  165. let storagePathUrl = groupURL.appendingPathComponent("File Provider Storage")
  166. let storagePath = storagePathUrl.path
  167. if !FileManager.default.fileExists(atPath: storagePath) {
  168. do {
  169. try FileManager.default.createDirectory(atPath: storagePath, withIntermediateDirectories: false, attributes: nil)
  170. } catch let error {
  171. print("error creating filepath: \(error)")
  172. return nil
  173. }
  174. }
  175. return storagePathUrl
  176. }
  177. }