Consistancy to delegate call in all contents(of:) methods

- renamed opType instances to operation
- moved to v2 in Dropbox
- removed redundant CloudFileProvider methods
This commit is contained in:
Amir Abbas
2017-08-20 22:41:53 +04:30
parent 0da957d25f
commit f0b4925db2
10 changed files with 186 additions and 234 deletions
+16 -73
View File
@@ -379,55 +379,6 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
}
}
/**
Creates a new directory at the specified path asynchronously.
This will create any necessary intermediate directories.
- Parameters:
- folder: Directory name.
- at: Parent path of new directory.
- completionHandler: If an error parameter was provided, a presentable `Error` will be returned.
- Returns: A `Progress` object to get progress or cancel progress. Doesn't work on `CloudFileProvider`.
*/
@discardableResult
open override func create(folder folderName: String, at atPath: String, completionHandler: SimpleCompletionHandler) -> Progress? {
return super.create(folder: folderName, at: atPath, completionHandler: completionHandler)
}
/**
Moves a file or directory from `path` to designated path asynchronously.
When you want move a file, destination path should also consists of file name.
Either a new name or the old one.
- Parameters:
- path: original file or directory path.
- to: destination path of file or directory, including file/directory name.
- overwrite: Destination file should be overwritten if file is already exists. **Default** is `false`.
- completionHandler: If an error parameter was provided, a presentable `Error` will be returned.
- Returns: A `Progress` object to get progress or cancel progress. Doesn't work on `CloudFileProvider`.
*/
@discardableResult
open override func moveItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
return super.moveItem(path: path, to: toPath, overwrite: overwrite, completionHandler: completionHandler)
}
/**
Copies a file or directory from `path` to designated path asynchronously.
When want copy a file, destination path should also consists of file name.
Either a new name or the old one.
- Parameters:
- path: original file or directory path.
- to: destination path of file or directory, including file/directory name.
- overwrite: Destination file should be overwritten if file is already exists. **Default** is `false`.
- completionHandler: If an error parameter was provided, a presentable `Error` will be returned.
- Returns: A `Progress` object to get progress or cancel progress. Doesn't work on `CloudFileProvider`.
*/
@discardableResult
open override func copyItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
return super.copyItem(path: path, to: toPath, overwrite: overwrite, completionHandler: completionHandler)
}
/**
Removes the file or directory at the specified path.
@@ -459,14 +410,14 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
@discardableResult
open override func copyItem(localFile: URL, to toPath: String, overwrite: Bool, completionHandler: SimpleCompletionHandler) -> Progress? {
// TODO: Make use of overwrite parameter
let opType = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
let operation = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
let progress = Progress(parent: nil, userInfo: nil)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.isCancellable = false
progress.setUserInfoObject(localFile, forKey: .fileURLKey)
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
monitorFile(path: toPath, opType: opType, progress: progress)
monitorFile(path: toPath, operation: operation, progress: progress)
operation_queue.addOperation {
let tempFolder: URL
if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
@@ -481,17 +432,13 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
let toUrl = self.url(of: toPath)
try self.opFileManager.setUbiquitous(true, itemAt: tmpFile, destinationURL: toUrl)
completionHandler?(nil)
DispatchQueue.main.async(execute: {
self.delegate?.fileproviderSucceed(self, operation: opType)
})
self.delegateNotify(operation, error: nil)
} catch let e {
if self.opFileManager.fileExists(atPath: tmpFile.path) {
try? self.opFileManager.removeItem(at: tmpFile)
}
completionHandler?(e)
DispatchQueue.main.async(execute: {
self.delegate?.fileproviderFailed(self, operation: opType)
})
self.delegateNotify(operation, error: e)
}
}
return progress
@@ -509,21 +456,19 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
*/
@discardableResult
open override func copyItem(path: String, toLocalURL: URL, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
let operation = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
let progress = Progress(parent: nil, userInfo: nil)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.isCancellable = false
progress.setUserInfoObject(self.url(of: path), forKey: .fileURLKey)
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
monitorFile(path: path, opType: opType, progress: progress)
monitorFile(path: path, operation: operation, progress: progress)
do {
try self.opFileManager.startDownloadingUbiquitousItem(at: self.url(of: path))
} catch let e {
completionHandler?(e)
DispatchQueue.main.async(execute: {
self.delegate?.fileproviderFailed(self, operation: opType)
})
self.delegateNotify(operation, error: e)
return nil
}
let _ = super.copyItem(path: path, toLocalURL: toLocalURL, completionHandler: completionHandler)
@@ -549,7 +494,7 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
progress.kind = .file
progress.setUserInfoObject(self.url(of: path), forKey: .fileURLKey)
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
monitorFile(path: path, opType: operation, progress: progress)
monitorFile(path: path, operation: operation, progress: progress)
_ = super.contents(path: path, completionHandler: completionHandler)
return progress
}
@@ -575,7 +520,7 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
progress.kind = .file
progress.setUserInfoObject(self.url(of: path), forKey: .fileURLKey)
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
monitorFile(path: path, opType: operation, progress: progress)
monitorFile(path: path, operation: operation, progress: progress)
_ = super.contents(path: path, offset: offset, length: length, completionHandler: completionHandler)
return progress
}
@@ -599,7 +544,7 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
progress.kind = .file
progress.setUserInfoObject(self.url(of: path), forKey: .fileURLKey)
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
monitorFile(path: path, opType: operation, progress: progress)
monitorFile(path: path, operation: operation, progress: progress)
_ = super.writeContents(path: path, contents: data, atomically: atomically, overwrite: overwrite, completionHandler: completionHandler)
return progress
}
@@ -686,7 +631,7 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
return file
}
fileprivate func monitorFile(path: String, opType: FileOperationType, progress: Progress?) {
fileprivate func monitorFile(path: String, operation: FileOperationType, progress: Progress?) {
dispatch_queue.async {
let pathURL = self.url(of: path)
let size = pathURL.fileSize
@@ -711,20 +656,18 @@ open class CloudFileProvider: LocalFileProvider, FileProviderSharing {
if (downloaded == 0 || downloaded == 100) && (uploaded > 0 && uploaded < 100) {
progress?.completedUnitCount = Int64(uploaded / 100 * Double(progress?.totalUnitCount ?? 0))
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(uploaded / 100))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(uploaded / 100))
}
} else if (uploaded == 0 || uploaded == 100) && (downloaded > 0 && downloaded < 100) {
progress?.completedUnitCount = Int64(downloaded / 100 * Double(progress?.totalUnitCount ?? 0))
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(downloaded / 100))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(downloaded / 100))
}
} else if uploaded == 100 || downloaded == 100 {
progress?.completedUnitCount = progress?.totalUnitCount ?? 0
query.stop()
NotificationCenter.default.removeObserver(updateObserver!)
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: opType)
}
self.delegateNotify(operation, error: nil)
}
query.enableUpdates()
+12 -9
View File
@@ -133,7 +133,7 @@ open class DropboxFileProvider: HTTPFileProvider, FileProviderSharing {
return progress
}
override func request(for operation: FileOperationType, overwrite: Bool, attributes: [URLResourceKey : Any]) -> URLRequest {
override func request(for operation: FileOperationType, overwrite: Bool = false, attributes: [URLResourceKey : Any] = [:]) -> URLRequest {
// content operations
var request: URLRequest
switch operation {
@@ -169,25 +169,29 @@ open class DropboxFileProvider: HTTPFileProvider, FileProviderSharing {
request.set(httpAuthentication: credential, with: .oAuth2)
request.set(contentType: .stream)
request.set(dropboxArgKey: requestDictionary)
default: // modify, link, fetch
return self.apiRequest(for: operation)
default:
return self.apiRequest(for: operation, overwrite: overwrite)
}
return request
}
func apiRequest(for operation: FileOperationType) -> URLRequest {
func apiRequest(for operation: FileOperationType, overwrite: Bool = false) -> URLRequest {
let url: String
let sourcePath = operation.source
let destPath = operation.destination
var requestDictionary = [String: AnyObject]()
switch operation {
case .create:
url = "files/create_folder"
url = "files/create_folder_v2"
case .copy:
url = "files/copy"
url = "files/copy_v2"
requestDictionary["allow_shared_folder"] = NSNumber(value: true)
case .move:
url = "files/move"
url = "files/move_v2"
requestDictionary["allow_shared_folder"] = NSNumber(value: true)
case .remove:
url = "files/delete"
url = "files/delete_v2"
default: // modify, link, fetch
fatalError("Unimplemented operation \(operation.description) in \(#file)")
}
@@ -195,7 +199,6 @@ open class DropboxFileProvider: HTTPFileProvider, FileProviderSharing {
request.httpMethod = "POST"
request.set(httpAuthentication: credential, with: .oAuth2)
request.set(contentType: .json)
var requestDictionary = [String: AnyObject]()
if let dest = correctPath(destPath) as NSString? {
requestDictionary["from_path"] = correctPath(sourcePath) as NSString?
requestDictionary["to_path"] = dest
+4
View File
@@ -23,6 +23,10 @@ public final class DropboxFileObject: FileObject {
}
internal init? (json: [String: AnyObject]) {
var json = json
if json["name"] == nil, let metadata = json["metadata"] as? [String: AnyObject] {
json = metadata
}
guard let name = json["name"] as? String else { return nil }
guard let path = json["path_display"] as? String else { return nil }
super.init(url: nil, name: name, path: path)
+62 -62
View File
@@ -374,13 +374,13 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
return nil
}
let opType = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
let operation = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: operation) ?? true == true else {
return nil
}
let progress = Progress(totalUnitCount: 0)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -389,7 +389,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -403,7 +403,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}, onProgress: { bytesSent, totalSent, expectedBytes in
progress.completedUnitCount = totalSent
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(progress.fractionCompleted))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(progress.fractionCompleted))
}
}, completionHandler: { (error) in
if error != nil {
@@ -412,7 +412,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
self.ftpQuit(task)
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
})
}
@@ -421,12 +421,12 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}
open func copyItem(path: String, toLocalURL destURL: URL, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.copy(source: path, destination: destURL.absoluteString)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
let operation = FileOperationType.copy(source: path, destination: destURL.absoluteString)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: operation) ?? true == true else {
return nil
}
var progress = Progress(totalUnitCount: 0)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -435,7 +435,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -444,7 +444,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
self.dispatch_queue.async {
let error = self.throwError(path, code: URLError.fileIsDirectory)
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -461,7 +461,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
completionHandler?(e)
}
}
task.taskDescription = opType.json
task.taskDescription = operation.json
task.addObserver(self.sessionDelegate!, forKeyPath: #keyPath(URLSessionTask.countOfBytesReceived), options: .new, context: &progress)
task.addObserver(self.sessionDelegate!, forKeyPath: #keyPath(URLSessionTask.countOfBytesExpectedToReceive), options: .new, context: &progress)
progress.cancellationHandler = { [weak task] in
@@ -490,14 +490,14 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
progress.totalUnitCount = totalSize
progress.completedUnitCount = totalReceived
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(progress.fractionCompleted))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(progress.fractionCompleted))
}
}) { (tmpurl, error) in
if let error = error {
progress.cancel()
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -506,7 +506,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
try? FileManager.default.moveItem(at: tmpurl, to: destURL)
self.dispatch_queue.async {
completionHandler?(nil)
self.delegateNotify(opType, error: nil)
self.delegateNotify(operation, error: nil)
}
}
}
@@ -516,14 +516,14 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}
open func contents(path: String, completionHandler: @escaping ((Data?, Error?) -> Void)) -> Progress? {
let opType = FileOperationType.fetch(path: path)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
let operation = FileOperationType.fetch(path: path)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: operation) ?? true == true else {
return nil
}
if self.useAppleImplementation {
var progress = Progress(totalUnitCount: 0)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -542,7 +542,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
completionHandler(nil, e)
}
}
task.taskDescription = opType.json
task.taskDescription = operation.json
task.addObserver(sessionDelegate!, forKeyPath: #keyPath(URLSessionTask.countOfBytesReceived), options: .new, context: &progress)
task.addObserver(sessionDelegate!, forKeyPath: #keyPath(URLSessionTask.countOfBytesExpectedToReceive), options: .new, context: &progress)
progress.cancellationHandler = { [weak task] in
@@ -557,16 +557,16 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}
open func contents(path: String, offset: Int64, length: Int, completionHandler: @escaping ((_ contents: Data?, _ error: Error?) -> Void)) -> Progress? {
let opType = FileOperationType.fetch(path: path)
let operation = FileOperationType.fetch(path: path)
if length == 0 || offset < 0 {
dispatch_queue.async {
completionHandler(Data(), nil)
self.delegateNotify(opType, error: nil)
self.delegateNotify(operation, error: nil)
}
return nil
}
let progress = Progress(totalUnitCount: 0)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -589,14 +589,14 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
progress.totalUnitCount = totalSize
progress.completedUnitCount = totalReceived
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(progress.fractionCompleted))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(progress.fractionCompleted))
}
}) { (data, error) in
if let error = error {
progress.cancel()
self.dispatch_queue.async {
completionHandler(nil, error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -604,7 +604,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
if let data = data {
self.dispatch_queue.async {
completionHandler(data, nil)
self.delegateNotify(opType, error: nil)
self.delegateNotify(operation, error: nil)
}
}
}
@@ -614,13 +614,13 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}
open func writeContents(path: String, contents data: Data?, atomically: Bool, overwrite: Bool, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.modify(path: path)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
let operation = FileOperationType.modify(path: path)
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: operation) ?? true == true else {
return nil
}
let progress = Progress(totalUnitCount: Int64(data?.count ?? 0))
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -629,7 +629,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -644,7 +644,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
}, onProgress: { bytesSent, totalSent, expectedBytes in
progress.completedUnitCount = totalSent
DispatchQueue.main.async {
self.delegate?.fileproviderProgress(self, operation: opType, progress: Float(progress.fractionCompleted))
self.delegate?.fileproviderProgress(self, operation: operation, progress: Float(progress.fractionCompleted))
}
}, completionHandler: { (error) in
if error != nil {
@@ -653,7 +653,7 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
self.ftpQuit(task)
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
})
}
@@ -686,21 +686,21 @@ open class FTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fil
- completionHandler: If an error parameter was provided, a presentable `Error` will be returned.
*/
open func create(symbolicLink path: String, withDestinationPath destPath: String, completionHandler: SimpleCompletionHandler) {
let opType = FileOperationType.link(link: path, target: destPath)
_=self.doOperation(opType, completionHandler: completionHandler)
let operation = FileOperationType.link(link: path, target: destPath)
_=self.doOperation(operation, completionHandler: completionHandler)
}
}
extension FTPFileProvider {
fileprivate func doOperation(_ opType: FileOperationType, completionHandler: SimpleCompletionHandler) -> Progress? {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
fileprivate func doOperation(_ operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> Progress? {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: operation) ?? true == true else {
return nil
}
let sourcePath = opType.source
let destPath = opType.destination
let sourcePath = operation.source
let destPath = operation.destination
let command: String
switch opType {
switch operation {
case .create:
command = "MKD \(ftpPath(sourcePath))"
case .copy:
@@ -715,7 +715,7 @@ extension FTPFileProvider {
return nil
}
let progress = Progress(totalUnitCount: 1)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
@@ -724,7 +724,7 @@ extension FTPFileProvider {
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -733,7 +733,7 @@ extension FTPFileProvider {
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -741,7 +741,7 @@ extension FTPFileProvider {
guard let response = response else {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: self.throwError(sourcePath, code: URLError.badServerResponse))
self.delegateNotify(operation, error: self.throwError(sourcePath, code: URLError.badServerResponse))
}
return
}
@@ -754,18 +754,18 @@ extension FTPFileProvider {
if codes.filter({ (450..<560).contains($0) }).count > 0 {
let errorCode: URLError.Code
switch opType {
switch operation {
case .create:
errorCode = URLError.cannotCreateFile
case .modify:
errorCode = URLError.cannotWriteToFile
case .copy:
self.fallbackCopy(opType, progress: progress, completionHandler: completionHandler)
self.fallbackCopy(operation, progress: progress, completionHandler: completionHandler)
return
case .move:
errorCode = URLError.cannotMoveFile
case .remove:
self.fallbackRemove(opType, progress: progress, on: task, completionHandler: completionHandler)
self.fallbackRemove(operation, progress: progress, on: task, completionHandler: completionHandler)
return
case .link:
errorCode = URLError.cannotWriteToFile
@@ -777,7 +777,7 @@ extension FTPFileProvider {
self.dispatch_queue.async {
completionHandler?(error)
}
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
return
}
@@ -785,7 +785,7 @@ extension FTPFileProvider {
self.dispatch_queue.async {
completionHandler?(nil)
}
self.delegateNotify(opType, error: nil)
self.delegateNotify(operation, error: nil)
})
}
@@ -796,9 +796,9 @@ extension FTPFileProvider {
return progress
}
private func fallbackCopy(_ opType: FileOperationType, progress: Progress, completionHandler: SimpleCompletionHandler) {
let sourcePath = opType.source
guard let destPath = opType.destination else { return }
private func fallbackCopy(_ operation: FileOperationType, progress: Progress, completionHandler: SimpleCompletionHandler) {
let sourcePath = operation.source
guard let destPath = operation.destination else { return }
let localURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("tmp")
@@ -807,7 +807,7 @@ extension FTPFileProvider {
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -815,7 +815,7 @@ extension FTPFileProvider {
progress.becomeCurrent(withPendingUnitCount: 1)
_ = self.copyItem(localFile: localURL, to: destPath) { error in
completionHandler?(nil)
self.delegateNotify(opType, error: nil)
self.delegateNotify(operation, error: nil)
}
progress.resignCurrent()
}
@@ -823,8 +823,8 @@ extension FTPFileProvider {
return
}
private func fallbackRemove(_ opType: FileOperationType, progress: Progress, on task: FileProviderStreamTask, completionHandler: SimpleCompletionHandler) {
let sourcePath = opType.source
private func fallbackRemove(_ operation: FileOperationType, progress: Progress, on task: FileProviderStreamTask, completionHandler: SimpleCompletionHandler) {
let sourcePath = operation.source
self.execute(command: "SITE RMDIR \(ftpPath(sourcePath))", on: task) { (response, error) in
if let error = error {
@@ -832,7 +832,7 @@ extension FTPFileProvider {
self.dispatch_queue.async {
completionHandler?(error)
}
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
return
}
@@ -842,12 +842,12 @@ extension FTPFileProvider {
self.dispatch_queue.async {
completionHandler?(error)
}
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
return
}
if response.hasPrefix("50") {
self.fallbackRecursiveRemove(opType, progress: progress, on: task, completionHandler: completionHandler)
self.fallbackRecursiveRemove(operation, progress: progress, on: task, completionHandler: completionHandler)
return
}
@@ -858,18 +858,18 @@ extension FTPFileProvider {
self.dispatch_queue.async {
completionHandler?(error)
}
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
}
private func fallbackRecursiveRemove(_ opType: FileOperationType, progress: Progress, on task: FileProviderStreamTask, completionHandler: SimpleCompletionHandler) {
let sourcePath = opType.source
private func fallbackRecursiveRemove(_ operation: FileOperationType, progress: Progress, on task: FileProviderStreamTask, completionHandler: SimpleCompletionHandler) {
let sourcePath = operation.source
_ = self.recursiveList(path: sourcePath, useMLST: true, completionHandler: { (contents, error) in
if let error = error {
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
return
}
@@ -889,7 +889,7 @@ extension FTPFileProvider {
recursiveProgress.completedUnitCount += 1
self.dispatch_queue.async {
completionHandler?(error)
self.delegateNotify(opType, error: error)
self.delegateNotify(operation, error: error)
}
// TODO: Digest response
})
-10
View File
@@ -9,16 +9,6 @@
import Foundation
internal extension FTPFileProvider {
func delegateNotify(_ operation: FileOperationType, error: Error?) {
DispatchQueue.main.async(execute: {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: operation)
} else {
self.delegate?.fileproviderFailed(self, operation: operation)
}
})
}
func readDataUntilEOF(of task: FileProviderStreamTask, minLength: Int, receivedData: Data? = nil, timeout: TimeInterval, completionHandler: @escaping (_ data: Data?, _ errror:Error?) -> Void) {
task.readData(ofMinLength: minLength, maxLength: 65535, timeout: timeout) { (data, eof, error) in
if let error = error {
+14 -1
View File
@@ -418,6 +418,18 @@ public extension FileProviderOperations {
}
}
internal extension FileProviderOperations {
internal func delegateNotify(_ operation: FileOperationType, error: Error?) {
DispatchQueue.main.async(execute: {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: operation)
} else {
self.delegate?.fileproviderFailed(self, operation: operation)
}
})
}
}
/// Defines method for fetching and modifying file contents
public protocol FileProviderReadWrite: FileProviderBasic {
/**
@@ -695,8 +707,9 @@ extension FileProviderBasic {
}
/// Returns a file name supposed to be unique with adding numbers to end of file.
/// - Important: It's a synchronous method. Don't use it on matin thread.
/// - Important: It's a synchronous method. Don't use it on main thread.
public func fileByUniqueName(_ filePath: String) -> String {
assert(!Thread.isMainThread, "\(#function) is not recommended to be executed on Main Thread.")
let fileUrl = URL(fileURLWithPath: filePath)
let dirPath = fileUrl.deletingLastPathComponent().path
let fileName = fileUrl.deletingPathExtension().lastPathComponent
+5 -15
View File
@@ -9,10 +9,10 @@
import Foundation
/**
Allows accessing to Dropbox stored files. This provider doesn't cache or save files internally, however you can
set `useCache` and `cache` properties to use Foundation `NSURLCache` system.
The abstract base class for all REST/Web based providers such as WebDAV, Dropbox, OneDrive, Google Drive, etc. and encapsulates basic
functionalitis such as downloading/uploading.
- Note: Uploading files and data are limited to 150MB, for now.
No instance of this class should (and can) be created. Use derivated classes instead. It leads to a crash with `fatalError()`.
*/
open class HTTPFileProvider: FileProviderBasicRemote, FileProviderOperations, FileProviderReadWrite {
open class var type: String { fatalError("HTTPFileProvider is an abstract class. Please implement \(#function) in subclass.") }
@@ -360,6 +360,7 @@ open class HTTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fi
progress.cancel()
}
completionHandler(nil, error)
self.delegateNotify(operation, error: error)
}
downloadCompletionHandlersForTasks[session.sessionDescription!]?[task.taskIdentifier] = { tempURL in
guard let httpResponse = task.response as? HTTPURLResponse , httpResponse.statusCode < 300 else {
@@ -370,6 +371,7 @@ open class HTTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fi
progress.cancel()
}
completionHandler(nil, serverError)
self.delegateNotify(operation, error: nil)
return
}
@@ -387,16 +389,4 @@ open class HTTPFileProvider: FileProviderBasicRemote, FileProviderOperations, Fi
}
}
extension HTTPFileProvider {
internal func delegateNotify(_ operation: FileOperationType, error: Error?) {
DispatchQueue.main.async(execute: {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: operation)
} else {
self.delegate?.fileproviderFailed(self, operation: operation)
}
})
}
}
extension HTTPFileProvider: FileProvider { }
+61 -56
View File
@@ -211,58 +211,67 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
@discardableResult
open func create(folder folderName: String, at atPath: String, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.create(path: (atPath as NSString).appendingPathComponent(folderName) + "/")
return self.doOperation(opType, completionHandler: completionHandler)
let operation = FileOperationType.create(path: (atPath as NSString).appendingPathComponent(folderName) + "/")
return self.doOperation(operation, completionHandler: completionHandler)
}
@discardableResult
open func moveItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.move(source: path, destination: toPath)
let operation = FileOperationType.move(source: path, destination: toPath)
if !overwrite && self.fileManager.fileExists(atPath: self.url(of: toPath).path) {
completionHandler?(self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum))
let e = self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum)
dispatch_queue.async {
completionHandler?(e)
}
self.delegateNotify(operation, error: e)
return nil
}
return self.doOperation(opType, completionHandler: completionHandler)
return self.doOperation(operation, completionHandler: completionHandler)
}
@discardableResult
open func copyItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.copy(source: path, destination: toPath)
let operation = FileOperationType.copy(source: path, destination: toPath)
if !overwrite && self.fileManager.fileExists(atPath: self.url(of: toPath).path) {
self.dispatch_queue.async {
completionHandler?(self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum))
let e = self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum)
dispatch_queue.async {
completionHandler?(e)
}
self.delegateNotify(operation, error: e)
return nil
}
return self.doOperation(opType, completionHandler: completionHandler)
return self.doOperation(operation, completionHandler: completionHandler)
}
@discardableResult
open func removeItem(path: String, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.remove(path: path)
return self.doOperation(opType, completionHandler: completionHandler)
let operation = FileOperationType.remove(path: path)
return self.doOperation(operation, completionHandler: completionHandler)
}
@discardableResult
open func copyItem(localFile: URL, to toPath: String, overwrite: Bool, completionHandler: SimpleCompletionHandler) -> Progress? {
let operation = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
if !overwrite && self.fileManager.fileExists(atPath: self.url(of: toPath).path) {
self.dispatch_queue.async {
completionHandler?(self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum))
let e = self.throwError(toPath, code: CocoaError.fileWriteFileExists as FoundationErrorEnum)
dispatch_queue.async {
completionHandler?(e)
}
self.delegateNotify(operation, error: e)
return nil
}
let opType = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
return self.doOperation(opType, forUploading: true, completionHandler: completionHandler)
return self.doOperation(operation, forUploading: true, completionHandler: completionHandler)
}
@discardableResult
open func copyItem(path: String, toLocalURL: URL, completionHandler: SimpleCompletionHandler) -> Progress? {
let opType = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
return self.doOperation(opType, completionHandler: completionHandler)
let operation = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
return self.doOperation(operation, completionHandler: completionHandler)
}
@objc dynamic func doSimpleOperation(_ box: UndoBox) {
@@ -273,9 +282,9 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
}
@discardableResult
fileprivate func doOperation(_ opType: FileOperationType, data: Data? = nil, atomically: Bool = false, forUploading: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
fileprivate func doOperation(_ operation: FileOperationType, data: Data? = nil, atomically: Bool = false, forUploading: Bool = false, completionHandler: SimpleCompletionHandler) -> Progress? {
let progress = Progress(parent: nil, userInfo: nil)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.isCancellable = false
progress.setUserInfoObject(Progress.FileOperationKind.receiving, forKey: .fileOperationKindKey)
@@ -289,8 +298,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
}
}
let sourcePath = opType.source
let destPath = opType.destination
let sourcePath = operation.source
let destPath = operation.destination
let source: URL = urlofpath(path: sourcePath)
progress.setUserInfoObject(source, forKey: .fileURLKey)
@@ -301,11 +310,11 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
dest = nil
}
if let undoManager = self.undoManager, let undoOp = self.undoOperation(for: opType) {
let undoBox = UndoBox(provider: self, operation: opType, undoOperation: undoOp)
if let undoManager = self.undoManager, let undoOp = self.undoOperation(for: operation) {
let undoBox = UndoBox(provider: self, operation: operation, undoOperation: undoOp)
undoManager.beginUndoGrouping()
undoManager.registerUndo(withTarget: self, selector: #selector(LocalFileProvider.doSimpleOperation(_:)), object: undoBox)
undoManager.setActionName(opType.actionDescription)
undoManager.setActionName(operation.actionDescription)
undoManager.endUndoGrouping()
}
@@ -314,7 +323,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
let operationHandler: (URL, URL?) -> Void = { source, dest in
do {
progress.setUserInfoObject(Date(), forKey: .startingTimeKey)
switch opType {
switch operation {
case .create:
if sourcePath.hasSuffix("/") {
progress.totalUnitCount = 1
@@ -350,9 +359,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
self.dispatch_queue.async {
completionHandler?(nil)
}
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: opType)
}
self.delegateNotify(operation, error: nil)
} catch let e {
if successfulSecurityScopedResourceAccess {
source.stopAccessingSecurityScopedResource()
@@ -361,16 +368,14 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
self.dispatch_queue.async {
completionHandler?(e)
}
DispatchQueue.main.async {
self.delegate?.fileproviderFailed(self, operation: opType)
}
self.delegateNotify(operation, error: e)
}
}
if isCoorinating {
successfulSecurityScopedResourceAccess = source.startAccessingSecurityScopedResource()
var intents = [NSFileAccessIntent]()
switch opType {
switch operation {
case .create, .modify:
intents.append(NSFileAccessIntent.writingIntent(with: source, options: .forReplacing))
case .copy:
@@ -390,9 +395,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
self.dispatch_queue.async {
completionHandler?(error)
}
DispatchQueue.main.async {
self.delegate?.fileproviderFailed(self, operation: opType)
}
self.delegateNotify(operation, error: error)
})
} else {
operation_queue.addOperation {
@@ -404,11 +407,11 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
@discardableResult
open func contents(path: String, completionHandler: @escaping ((_ contents: Data?, _ error: Error?) -> Void)) -> Progress? {
let opType = FileOperationType.fetch(path: path)
let operation = FileOperationType.fetch(path: path)
let url = self.url(of: path)
let progress = Progress(parent: nil, userInfo: nil)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.isCancellable = false
progress.setUserInfoObject(Progress.FileOperationKind.receiving, forKey: .fileOperationKindKey)
@@ -423,11 +426,13 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
self.dispatch_queue.async {
completionHandler(data, nil)
}
self.delegateNotify(operation, error: nil)
} catch let e {
progress.cancel()
self.dispatch_queue.async {
completionHandler(nil, e)
}
self.delegateNotify(operation, error: e)
}
}
@@ -437,9 +442,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
self.dispatch_queue.async {
completionHandler(nil, error)
}
DispatchQueue.main.async {
self.delegate?.fileproviderFailed(self, operation: opType)
}
self.delegateNotify(operation, error: error)
})
} else {
dispatch_queue.async {
@@ -463,11 +466,11 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
return self.contents(path: path, completionHandler: completionHandler)
}
let opType = FileOperationType.fetch(path: path)
let operation = FileOperationType.fetch(path: path)
let url = self.url(of: path)
let progress = Progress(parent: nil, userInfo: nil)
progress.setUserInfoObject(opType, forKey: .fileProvderOperationTypeKey)
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
progress.kind = .file
progress.isCancellable = false
progress.setUserInfoObject(url, forKey: .fileURLKey)
@@ -476,7 +479,9 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
let operationHandler: (URL) -> Void = { url in
guard let handle = FileHandle(forReadingAtPath: url.path) else {
self.dispatch_queue.async {
completionHandler(nil, self.throwError(path, code: CocoaError.fileNoSuchFile as FoundationErrorEnum))
let e = self.throwError(path, code: CocoaError.fileNoSuchFile as FoundationErrorEnum)
completionHandler(nil, e)
self.delegateNotify(operation, error: e)
}
return
}
@@ -490,7 +495,9 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
guard size > offset else {
progress.cancel()
self.dispatch_queue.async {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum))
let e = self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum)
completionHandler(nil, e)
self.delegateNotify(operation, error: e)
}
return
}
@@ -499,7 +506,9 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
guard Int64(handle.offsetInFile) == offset else {
progress.cancel()
self.dispatch_queue.async {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum))
let e = self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum)
completionHandler(nil, e)
self.delegateNotify(operation, error: e)
}
return
}
@@ -508,6 +517,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
progress.completedUnitCount = progress.totalUnitCount
self.dispatch_queue.async {
completionHandler(data, nil)
self.delegateNotify(operation, error: nil)
}
}
@@ -515,9 +525,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
let intent = NSFileAccessIntent.readingIntent(with: url, options: .withoutChanges)
coordinated(intents: [intent], completionHandler: operationHandler, errorHandler: { error in
completionHandler(nil, error)
DispatchQueue.main.async {
self.delegate?.fileproviderFailed(self, operation: opType)
}
self.delegateNotify(operation, error: error)
})
} else {
dispatch_queue.async {
@@ -531,8 +539,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
@discardableResult
open func writeContents(path: String, contents data: Data?, atomically: Bool, overwrite: Bool, completionHandler: SimpleCompletionHandler) -> Progress? {
let fileExists = fileManager.fileExists(atPath: url(of: path).path)
let opType: FileOperationType = fileExists ? .modify(path: path) : .create(path: path)
return self.doOperation(opType, data: data ?? Data(), atomically: atomically, completionHandler: completionHandler)
let operation: FileOperationType = fileExists ? .modify(path: path) : .create(path: path)
return self.doOperation(operation, data: data ?? Data(), atomically: atomically, completionHandler: completionHandler)
}
fileprivate var monitors = [LocalFolderMonitor]()
@@ -579,17 +587,14 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
*/
open func create(symbolicLink path: String, withDestinationPath destPath: String, completionHandler: SimpleCompletionHandler) {
operation_queue.addOperation {
let operation = FileOperationType.link(link: path, target: destPath)
do {
try self.opFileManager.createSymbolicLink(at: self.url(of: path), withDestinationURL: self.url(of: destPath))
completionHandler?(nil)
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: .link(link: path, target: destPath))
}
self.delegateNotify(operation, error: nil)
} catch let e {
completionHandler?(e)
DispatchQueue.main.async {
self.delegate?.fileproviderFailed(self, operation: .link(link: path, target: destPath))
}
self.delegateNotify(operation, error: e)
}
}
}
+10 -6
View File
@@ -201,12 +201,18 @@ open class OneDriveFileProvider: HTTPFileProvider, FileProviderSharing {
var request = URLRequest(url: url)
request.httpMethod = method
request.set(httpAuthentication: credential, with: .oAuth2)
if let dest = correctPath(operation.destination) as NSString?, !dest.hasPrefix("file://") {
switch operation {
case .copy(let source, let dest) where !source.hasPrefix("file://") && !dest.hasPrefix("file://"),
.move(source: let source, destination: let dest):
request.set(contentType: .json)
let cdest = (correctPath(dest) as NSString?)!
var requestDictionary = [String: AnyObject]()
requestDictionary["parentReference"] = ("/drive/\(drive):" + dest.deletingLastPathComponent) as NSString
requestDictionary["name"] = dest.lastPathComponent as NSString
requestDictionary["parentReference"] = ("/drive/\(drive):" + cdest.deletingLastPathComponent) as NSString
requestDictionary["name"] = cdest.lastPathComponent as NSString
request.httpBody = Data(jsonDictionary: requestDictionary)
default:
break
}
return request
@@ -240,9 +246,7 @@ open class OneDriveFileProvider: HTTPFileProvider, FileProviderSharing {
fileprivate func unregisterNotifcation(path: String) {
NotImplemented()
}
}
extension OneDriveFileProvider {
open func publicLink(to path: String, completionHandler: @escaping ((_ link: URL?, _ attribute: FileObject?, _ expiration: Date?, _ error: Error?) -> Void)) {
var request = URLRequest(url: self.url(of: path, modifier: "action.createLink"))
request.httpMethod = "POST"
+2 -2
View File
@@ -77,7 +77,7 @@ open class WebDAVFileProvider: HTTPFileProvider, FileProviderSharing {
- `error`: Error returned by system.
*/
open func contentsOfDirectory(path: String, including: [URLResourceKey], completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
let opType = FileOperationType.fetch(path: path)
let operation = FileOperationType.fetch(path: path)
let url = self.url(of: path).appendingPathComponent("")
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
@@ -86,7 +86,7 @@ open class WebDAVFileProvider: HTTPFileProvider, FileProviderSharing {
request.set(contentType: .xml)
request.httpBody = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n\(WebDavFileObject.propString(including))\n</D:propfind>".data(using: .utf8)
request.setValue(String(request.httpBody!.count), forHTTPHeaderField: "Content-Length")
runDataTask(with: request, operation: opType, completionHandler: { (data, response, error) in
runDataTask(with: request, operation: operation, completionHandler: { (data, response, error) in
var responseError: FileProviderWebDavError?
if let code = (response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
responseError = FileProviderWebDavError(code: rCode, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8), url: url)