Compare commits

...

3 Commits

Author SHA1 Message Date
Amir Abbas Mousavian 3e55cc60f7 Replaced absoluteURL with relative url (resolved #27), improving performance.
- renamed `DropboxFileProvider.copyItem(path:toRemoteURL:) ` to `DropboxFileProvider.copyItem(remoteURL:toPath:)` due to logic
2017-01-31 17:19:45 +03:30
Alek Slater d7ae709cf7 contentURL was missing the trailing slash causing it to fail for all contentURL calls with the dropbox api (#26) 2017-01-31 13:05:20 +03:30
Amir Abbas Mousavian 4f6e3c7bd5 Uncommented CloudFileProvider decription 2017-01-31 02:11:28 +03:30
15 changed files with 134 additions and 103 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#
s.name = "FileProvider"
s.version = "0.11.0"
s.version = "0.11.1"
s.summary = "FileManager replacement for Local and Remote (WebDAV/Dropbox/OneDrive/SMB2) files on iOS and macOS."
# This description is used to generate tags and improve search results.
+2 -2
View File
@@ -603,7 +603,7 @@
799396601D48B7BF00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.11.0;
BUNDLE_VERSION_STRING = 0.11.1;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -633,7 +633,7 @@
799396611D48B7BF00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.11.0;
BUNDLE_VERSION_STRING = 0.11.1;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
+10 -3
View File
@@ -30,7 +30,7 @@ Local and WebDAV providers are fully tested and can be used in production enviro
* For now it has limitation in uploading files up to 150MB.
- [x] **OneDriveFileProvider** A wrapper around OneDrive Web API, works with `onedrive.com` and compatible (business) servers.
* For now it has limitation in uploading files up to 100MB.
- [ ] **CloudFileProvider** A wrapper around app's ubiquitous container to iCloud Drive in iOS 8+ API.
- [x] **CloudFileProvider** A wrapper around app's ubiquitous container to iCloud Drive in iOS 8+ API.
- [ ] **SMBFileProvider** SMB2/3 introduced in 2006, which is a file and printer sharing protocol originated from Microsoft Windows and now is replacing AFP protocol on MacOS.
* Data types and some basic functions are implemented but *main interface is not implemented yet!*
* SMB1/CIFS is depericated and very tricky to be implemented
@@ -112,14 +112,21 @@ let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDo
let documentsProvider = LocalFileProvider(baseURL: documentsURL)
```
Also for using group shared container:
```swift
let documentsProvider = LocalFileProvider(sharedContainerId: "group.yourcompany.appContainer")
// Replace your group identifier with string above
```
You can't change the base url later. and all paths are related to this base url by default.
<!---
To initialize an iCloud Container provider use below code, This will automatically manager creating Documents folder in container:
```swift
let documentsProvider = CloudFileProvider(containerId: nil)
```
--->
For remote file providers authentication may be necessary:
+15 -14
View File
@@ -14,7 +14,7 @@ open class CloudFileProvider: LocalFileProvider {
return "iCloudDrive"
}
/// Actually is readonly
/// Actually is readonly, value is true
override open var isCoorinating: Bool {
get {
return true
@@ -35,7 +35,7 @@ open class CloudFileProvider: LocalFileProvider {
return nil
}
self.containerId = containerId
let baseURL = ubiquityURL.standardized.appendingPathComponent("Documents")
let baseURL = ubiquityURL.standardized.appendingPathComponent("Documents/")
super.init(baseURL: baseURL)
self.isCoorinating = true
@@ -51,7 +51,7 @@ open class CloudFileProvider: LocalFileProvider {
open override func contentsOfDirectory(path: String, completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
dispatch_queue.async {
let pathURL = self.absoluteURL(path)
let pathURL = self.url(of: path)
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: "%K BEGINSWITH %@", NSMetadataItemPathKey, pathURL.path)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
@@ -96,7 +96,7 @@ open class CloudFileProvider: LocalFileProvider {
open override func attributesOfItem(path: String, completionHandler: @escaping ((_ attributes: FileObject?, _ error: Error?) -> Void)) {
dispatch_queue.async {
let pathURL = self.absoluteURL(path)
let pathURL = self.url(of: path)
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemPathKey, pathURL.path)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
@@ -171,7 +171,7 @@ open class CloudFileProvider: LocalFileProvider {
do {
try self.opFileManager.copyItem(at: localFile, to: tmpFile)
let toUrl = self.absoluteURL(toPath)
let toUrl = self.url(of: toPath)
try self.opFileManager.setUbiquitous(true, itemAt: tmpFile, destinationURL: toUrl)
completionHandler?(nil)
DispatchQueue.main.async(execute: {
@@ -195,7 +195,7 @@ open class CloudFileProvider: LocalFileProvider {
let opType = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
do {
try self.opFileManager.startDownloadingUbiquitousItem(at: self.absoluteURL(path))
try self.opFileManager.startDownloadingUbiquitousItem(at: self.url(of: path))
} catch let e {
completionHandler?(e)
DispatchQueue.main.async(execute: {
@@ -228,7 +228,7 @@ open class CloudFileProvider: LocalFileProvider {
open override func searchFiles(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: @escaping ((_ files: [FileObject], _ error: Error?) -> Void)) {
dispatch_queue.async {
let pathURL = self.absoluteURL(path)
let pathURL = self.url(of: path)
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: "(%K BEGINSWITH %@) && (%K LIKE %@)", NSMetadataItemPathKey, pathURL.path, NSMetadataItemFSNameKey, query)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
@@ -302,7 +302,7 @@ open class CloudFileProvider: LocalFileProvider {
//
open override func registerNotifcation(path: String, eventHandler: @escaping (() -> Void)) {
self.unregisterNotifcation(path: path)
let pathURL = self.absoluteURL(path)
let pathURL = self.url(of: path)
let query = NSMetadataQuery()
query.predicate = NSPredicate(format: "(%K BEGINSWITH %@)", NSMetadataItemPathKey, pathURL.path)
query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
@@ -322,7 +322,7 @@ open class CloudFileProvider: LocalFileProvider {
}
open override func unregisterNotifcation(path: String) {
let key = absoluteURL(path)
let key = url(of: path)
guard let (query, observer) = monitors[key] else {
return
}
@@ -333,7 +333,7 @@ open class CloudFileProvider: LocalFileProvider {
}
open override func isRegisteredForNotification(path: String) -> Bool {
return monitors[absoluteURL(path)] != nil
return monitors[url(of: path)] != nil
}
/// may return nil
@@ -352,8 +352,9 @@ open class CloudFileProvider: LocalFileProvider {
}
let path = self.relativePathOf(url: url)
let file = FileObject(absoluteURL: url, name: name, path: path)
let rpath = path.hasPrefix("/") ? path.substring(from: path.index(after: path.startIndex)) : path
let relativeUrl = URL(string: rpath, relativeTo: self.baseURL)
let file = FileObject(url: relativeUrl ?? url, name: name, path: path)
file.size = (attribs[NSMetadataItemFSSizeKey] as? NSNumber)?.int64Value ?? -1
file.creationDate = attribs[NSMetadataItemFSCreationDateKey] as? Date
@@ -369,7 +370,7 @@ open class CloudFileProvider: LocalFileProvider {
open func evictItem(path: String, completionHandler: SimpleCompletionHandler) {
operation_queue.addOperation {
do {
try self.opFileManager.evictUbiquitousItem(at: self.absoluteURL(path))
try self.opFileManager.evictUbiquitousItem(at: self.url(of: path))
completionHandler?(nil)
} catch let e {
completionHandler?(e)
@@ -381,7 +382,7 @@ open class CloudFileProvider: LocalFileProvider {
operation_queue.addOperation {
do {
var expiration: NSDate?
let url = try self.opFileManager.url(forPublishingUbiquitousItemAt: self.absoluteURL(path), expiration: &expiration)
let url = try self.opFileManager.url(forPublishingUbiquitousItemAt: self.url(of: path), expiration: &expiration)
completionHandler(url, nil, expiration as Date?, nil)
} catch let e {
completionHandler(nil, nil, nil, e)
+6 -6
View File
@@ -58,11 +58,11 @@ open class DropboxFileProvider: FileProviderBasicRemote {
self.credential = credential
self.apiURL = URL(string: "https://api.dropboxapi.com/2/")!
self.contentURL = URL(string: "https://content.dropboxapi.com/2")!
self.contentURL = URL(string: "https://content.dropboxapi.com/2/")!
dispatch_queue = DispatchQueue(label: "FileProvider.\(DropboxFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
dispatch_queue = DispatchQueue(label: "FileProvider.\(type(of: self).type)", attributes: DispatchQueue.Attributes.concurrent)
operation_queue = OperationQueue()
operation_queue.name = "FileProvider.\(DropboxFileProvider.type).Operation"
operation_queue.name = "FileProvider.\(type(of: self).type).Operation"
}
@@ -330,13 +330,13 @@ extension DropboxFileProvider {
task.resume()
}
open func copyItem(path: String, toRemoteURL destURL: URL, completionHandler: @escaping ((_ jobId: String?, _ attribute: DropboxFileObject?, _ error: Error?) -> Void)) {
open func copyItem(remoteURL: URL, to toPath: String, completionHandler: @escaping ((_ jobId: String?, _ attribute: DropboxFileObject?, _ error: Error?) -> Void)) {
let url = URL(string: "files/save_url", relativeTo: apiURL)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestDictionary = ["path": correctPath(path)! as NSString, "url" : destURL.absoluteString as NSString]
let requestDictionary = ["path": correctPath(toPath)! as NSString, "url" : remoteURL.absoluteString as NSString]
request.httpBody = dictionaryToJSON(requestDictionary)?.data(using: .utf8)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
var dbError: FileProviderDropboxError?
@@ -344,7 +344,7 @@ extension DropboxFileProvider {
var fileObject: DropboxFileObject?
if let response = response as? HTTPURLResponse {
let code = FileProviderHTTPErrorCode(rawValue: response.statusCode)
dbError = code != nil ? FileProviderDropboxError(code: code!, path: path, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
dbError = code != nil ? FileProviderDropboxError(code: code!, path: toPath, errorDescription: String(data: data ?? Data(), encoding: .utf8)) : nil
if let data = data, let jsonStr = String(data: data, encoding: .utf8), let json = jsonToDictionary(jsonStr) {
jobId = json["async_job_id"] as? String
if let attribDic = json["metadata"] as? [String: AnyObject] {
+1 -1
View File
@@ -20,7 +20,7 @@ public struct FileProviderDropboxError: Error, CustomStringConvertible {
public final class DropboxFileObject: FileObject {
internal init(name: String, path: String) {
super.init(absoluteURL: URL(string: path), name: name, path: path)
super.init(url: URL(string: path) ?? URL(string: "/")!, name: name, path: path)
}
open internal(set) var serverTime: Date? {
+2 -2
View File
@@ -64,7 +64,7 @@ extension LocalFileProvider: ExtendedFileProvider {
(dispatch_queue).async {
var thumbnailImage: ImageClass? = nil
// Check cache
let fileURL = self.absoluteURL(path)
let fileURL = self.url(of: path)
// Create Thumbnail and cache
switch fileURL.pathExtension.lowercased() {
case LocalFileInformationGenerator.videoThumbnailExtensions:
@@ -117,7 +117,7 @@ extension LocalFileProvider: ExtendedFileProvider {
var dic = [String: Any]()
var keys = [String]()
if let getterMethod = getter {
(dic, keys) = getterMethod(self.absoluteURL(path))
(dic, keys) = getterMethod(self.url(of: path))
}
completionHandler(dic, keys, nil)
+10 -5
View File
@@ -16,20 +16,25 @@ open class FileObject {
self.allValues = allValues
}
internal init(absoluteURL: URL? = nil, name: String, path: String) {
internal init(url: URL, name: String, path: String) {
self.allValues = [String: Any]()
self.absoluteURL = absoluteURL
self.url = url
self.name = name
self.path = path
}
/// url to access the resource, not supported by Dropbox provider
open internal(set) var absoluteURL: URL? {
@available(*, deprecated, message: "Use FileObject.url.absoluteURL instead.")
open var absoluteURL: URL? {
return url?.absoluteURL
}
open internal(set) var url: URL? {
get {
return allValues["NSURLAbsoluteURLKey"] as? URL
return allValues["NSURLFileURLKey"] as? URL
}
set {
allValues["NSURLAbsoluteURLKey"] = newValue
allValues["NSURLFileURLKey"] = newValue
}
}
+6 -2
View File
@@ -230,6 +230,10 @@ extension FileProviderBasic {
}
public func relativePathOf(url: URL) -> String {
if url.baseURL == self.baseURL {
return url.relativePath.removingPercentEncoding!
}
guard let baseURL = self.baseURL else { return url.absoluteString }
return url.standardizedFileURL.absoluteString.replacingOccurrences(of: baseURL.absoluteString, with: "/").removingPercentEncoding!
}
@@ -264,7 +268,7 @@ extension FileProviderBasic {
}
var i = number ?? 2
let similiar = contents.map {
$0.absoluteURL?.lastPathComponent ?? $0.name
$0.url?.lastPathComponent ?? $0.name
}.filter {
$0.hasPrefix(result)
}
@@ -280,7 +284,7 @@ extension FileProviderBasic {
}
internal func throwError(_ path: String, code: FoundationErrorEnum) -> NSError {
let fileURL = self.absoluteURL(path)
let fileURL = self.url(of: path)
let domain: String
switch code {
case is URLError:
+21 -21
View File
@@ -64,9 +64,9 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
self.credential = nil
self.isCoorinating = false
dispatch_queue = DispatchQueue(label: "FileProvider.\(LocalFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
dispatch_queue = DispatchQueue(label: "FileProvider.\(type(of: self).type)", attributes: DispatchQueue.Attributes.concurrent)
operation_queue = OperationQueue()
operation_queue.name = "FileProvider.\(LocalFileProvider.type).Operation"
operation_queue.name = "FileProvider.\(type(of: self).type).Operation"
fileProviderManagerDelegate = LocalFileProviderManagerDelegate(provider: self)
opFileManager.delegate = fileProviderManagerDelegate
@@ -81,7 +81,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
open func contentsOfDirectory(path: String, completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
dispatch_queue.async {
do {
let contents = try self.fileManager.contentsOfDirectory(at: self.absoluteURL(path), includingPropertiesForKeys: [.nameKey, .fileSizeKey, .fileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .isHiddenKey, .volumeIsReadOnlyKey], options: .skipsSubdirectoryDescendants)
let contents = try self.fileManager.contentsOfDirectory(at: self.url(of: path), includingPropertiesForKeys: [.nameKey, .fileSizeKey, .fileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .isHiddenKey, .volumeIsReadOnlyKey], options: .skipsSubdirectoryDescendants)
let filesAttributes = contents.flatMap({ (fileURL) -> LocalFileObject? in
let path = self.relativePathOf(url: fileURL)
return LocalFileObject(fileWithPath: path, relativeTo: self.baseURL)
@@ -111,7 +111,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func create(folder folderName: String, at atPath: String, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.create(path: (atPath as NSString).appendingPathComponent(folderName) + "/")
let url = self.absoluteURL(atPath).appendingPathComponent(folderName)
let url = self.url(of: atPath).appendingPathComponent(folderName)
let operationHandler: (URL) -> Void = { url in
do {
@@ -148,7 +148,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func create(file fileName: String, at atPath: String, contents data: Data?, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.create(path: (atPath as NSString).appendingPathComponent(fileName))
let url = self.absoluteURL(atPath).appendingPathComponent(fileName, isDirectory: false)
let url = self.url(of: atPath).appendingPathComponent(fileName, isDirectory: false)
let operationHandler: (URL) -> Void = { url in
let success = self.opFileManager.createFile(atPath: url.path, contents: data, attributes: nil)
@@ -185,8 +185,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func moveItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.move(source: path, destination: toPath)
let sourceUrl = self.absoluteURL(path)
let destUrl = self.absoluteURL(toPath)
let sourceUrl = self.url(of: path)
let destUrl = self.url(of: toPath)
let sourceIntent = NSFileAccessIntent.writingIntent(with: sourceUrl, options: .forDeleting)
let destIntent = NSFileAccessIntent.writingIntent(with: destUrl, options: .forReplacing)
@@ -230,8 +230,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func copyItem(path: String, to toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.copy(source: path, destination: toPath)
let sourceUrl = self.absoluteURL(path)
let destUrl = self.absoluteURL(toPath)
let sourceUrl = self.url(of: path)
let destUrl = self.url(of: toPath)
let sourceIntent = NSFileAccessIntent.readingIntent(with: sourceUrl, options: .withoutChanges)
let destIntent = NSFileAccessIntent.writingIntent(with: destUrl, options: .forDeleting)
@@ -274,7 +274,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func removeItem(path: String, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.remove(path: path)
let url = self.absoluteURL(path)
let url = self.url(of: path)
let operationHandler: (URL) -> Void = { url in
do {
@@ -318,7 +318,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
let opType = FileOperationType.copy(source: localFile.absoluteString, destination: toPath)
operation_queue.addOperation {
do {
try self.opFileManager.copyItem(at: localFile, to: self.absoluteURL(toPath))
try self.opFileManager.copyItem(at: localFile, to: self.url(of: toPath))
completionHandler?(nil)
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: opType)
@@ -338,7 +338,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
let opType = FileOperationType.copy(source: path, destination: toLocalURL.absoluteString)
operation_queue.addOperation {
do {
try self.opFileManager.copyItem(at: self.absoluteURL(path), to: toLocalURL)
try self.opFileManager.copyItem(at: self.url(of: path), to: toLocalURL)
completionHandler?(nil)
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: opType)
@@ -356,7 +356,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func contents(path: String, completionHandler: @escaping ((_ contents: Data?, _ error: Error?) -> Void)) -> OperationHandle? {
let opType = FileOperationType.fetch(path: path)
let url = self.absoluteURL(path)
let url = self.url(of: path)
let operationHandler: (URL) -> Void = { url in
let data = self.fileManager.contents(atPath: url.path)
@@ -387,7 +387,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
}
let opType = FileOperationType.fetch(path: path)
let url = self.absoluteURL(path)
let url = self.url(of: path)
let operationHandler: (URL) -> Void = { url in
guard self.fileManager.fileExists(atPath: url.path) && !url.fileIsDirectory else {
@@ -426,7 +426,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
@discardableResult
open func writeContents(path: String, contents data: Data, atomically: Bool, overwrite: Bool, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let opType = FileOperationType.modify(path: path)
let url = self.absoluteURL(path)
let url = self.url(of: path)
var options: Data.WritingOptions = []
if atomically {
options.insert(.atomic)
@@ -469,7 +469,7 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
open func searchFiles(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: @escaping ((_ files: [FileObject], _ error: Error?) -> Void)) {
dispatch_queue.async {
let iterator = self.fileManager.enumerator(at: self.absoluteURL(path), includingPropertiesForKeys: nil, options: recursive ? [] : [.skipsSubdirectoryDescendants, .skipsPackageDescendants]) { (url, e) -> Bool in
let iterator = self.fileManager.enumerator(at: self.url(of: path), includingPropertiesForKeys: nil, options: recursive ? [] : [.skipsSubdirectoryDescendants, .skipsPackageDescendants]) { (url, e) -> Bool in
completionHandler([], e)
return true
}
@@ -491,12 +491,12 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor {
open func registerNotifcation(path: String, eventHandler: @escaping (() -> Void)) {
self.unregisterNotifcation(path: path)
let absurl = self.absoluteURL(path)
let isdir = (try? absurl.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false) ?? false
let dirurl = self.url(of: path)
let isdir = (try? dirurl.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false) ?? false
if !isdir {
return
}
let monitor = LocalFolderMonitor(url: absurl) {
let monitor = LocalFolderMonitor(url: dirurl) {
eventHandler()
}
monitor.start()
@@ -532,7 +532,7 @@ public extension LocalFileProvider {
public func create(symbolicLink path: String, withDestinationPath destPath: String, completionHandler: SimpleCompletionHandler) {
operation_queue.addOperation {
do {
try self.opFileManager.createSymbolicLink(at: self.absoluteURL(path), withDestinationURL: self.absoluteURL(destPath))
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))
@@ -549,7 +549,7 @@ public extension LocalFileProvider {
public func destination(ofSymbolicLink path: String, completionHandler: @escaping (_ url: URL?, _ error: Error?) -> Void) {
dispatch_queue.async {
do {
let destPath = try self.opFileManager.destinationOfSymbolicLink(atPath: self.absoluteURL(path).path)
let destPath = try self.opFileManager.destinationOfSymbolicLink(atPath: self.url(of: path).path)
let destUrl = URL(fileURLWithPath: destPath)
completionHandler(destUrl, nil)
} catch let e{
+14 -14
View File
@@ -9,32 +9,32 @@
import Foundation
public final class LocalFileObject: FileObject {
internal init(absoluteURL: URL, name: String, path: String) {
super.init(absoluteURL: absoluteURL, name: name, path: path)
internal override init(url: URL, name: String, path: String) {
super.init(url: url, name: name, path: path)
}
public convenience init? (fileWithPath path: String, relativeTo relativeURL: URL?) {
let fileURL: URL
if let relativeURL = relativeURL {
fileURL = relativeURL.appendingPathComponent(path)
var rpath = path.replacingOccurrences(of: relativeURL?.absoluteString ?? "", with: "")
if path.hasPrefix("/") {
rpath.remove(at: rpath.startIndex)
}
if rpath.isEmpty {
fileURL = relativeURL ?? URL(fileURLWithPath: path)
} else {
fileURL = URL(fileURLWithPath: path)
}
do {
let values = try fileURL.resourceValues(forKeys: [.nameKey, .fileSizeKey, .fileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .fileResourceTypeKey, .isHiddenKey, .isWritableKey])
self.init(absoluteURL: fileURL, name: values.name ?? fileURL.lastPathComponent, path: path)
for (key, value) in values.allValues {
self.allValues[key.rawValue] = value
if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) {
fileURL = URL(fileURLWithPath: rpath, relativeTo: relativeURL)
} else {
fileURL = relativeURL?.appendingPathComponent(path) ?? URL(fileURLWithPath: path)
}
} catch {
return nil
}
self.init(fileWithURL: fileURL)
}
public convenience init?(fileWithURL fileURL: URL) {
do {
let values = try fileURL.resourceValues(forKeys: [.nameKey, .fileSizeKey, .fileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .fileResourceTypeKey, .isHiddenKey, .isWritableKey, .typeIdentifierKey])
self.init(absoluteURL: fileURL, name: values.name ?? fileURL.lastPathComponent, path: fileURL.path)
self.init(url: fileURL, name: values.name ?? fileURL.lastPathComponent, path: fileURL.path)
for (key, value) in values.allValues {
self.allValues[key.rawValue] = value
}
+3 -3
View File
@@ -53,7 +53,7 @@ open class OneDriveFileProvider: FileProviderBasicRemote {
}
public init? (credential: URLCredential?, serverURL: URL? = nil, drive: String = "root", cache: URLCache? = nil) {
self.baseURL = serverURL ?? URL(string: "https://api.onedrive.com")
self.baseURL = (serverURL ?? URL(string: "https://api.onedrive.com/")!).appendingPathComponent("")
self.drive = drive
self.isPathRelative = true
self.currentPath = ""
@@ -61,9 +61,9 @@ open class OneDriveFileProvider: FileProviderBasicRemote {
self.validatingCache = true
self.cache = cache
self.credential = credential
dispatch_queue = DispatchQueue(label: "FileProvider.\(OneDriveFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
dispatch_queue = DispatchQueue(label: "FileProvider.\(type(of: self).type)", attributes: DispatchQueue.Attributes.concurrent)
operation_queue = OperationQueue()
operation_queue.name = "FileProvider.\(DropboxFileProvider.type).Operation"
operation_queue.name = "FileProvider.\(type(of: self).type).Operation"
}
deinit {
+8 -6
View File
@@ -19,8 +19,13 @@ public struct FileProviderOneDriveError: Error, CustomStringConvertible {
}
public final class OneDriveFileObject: FileObject {
internal init(name: String, path: String) {
super.init(absoluteURL: URL(string: path), name: name, path: path)
internal init(baseURL: URL?, name: String, path: String) {
var rpath = path
if path.hasPrefix("/") {
rpath.remove(at: rpath.startIndex)
}
let url = URL(string: rpath, relativeTo: baseURL) ?? URL(string: path)!
super.init(url: url, name: name, path: path)
}
@@ -199,10 +204,7 @@ internal extension OneDriveFileProvider {
guard let name = json["name"] as? String else { return nil }
guard let path = (json["parentReference"] as? NSDictionary)?["path"] as? String else { return nil }
let lPath = path.replacingOccurrences(of: "/drive/\(drive):", with: "/", options: .anchored, range: nil)
let fileObject = OneDriveFileObject(name: name, path: lPath)
if let webURL = json["webUrl"] as? String, let absolluteURL = URL(string: webURL) {
fileObject.absoluteURL = absolluteURL
}
let fileObject = OneDriveFileObject(baseURL: self.baseURL, name: name, path: lPath)
fileObject.size = (json["size"] as? NSNumber)?.int64Value ?? -1
fileObject.modifiedDate = resolve(dateString: json["lastModifiedDateTime"] as? String ?? "")
fileObject.creationDate = resolve(dateString: json["createdDateTime"] as? String ?? "")
+3 -3
View File
@@ -25,10 +25,10 @@ class SMBFileProvider: FileProvider, FileProviderMonitor {
guard baseURL.uw_scheme.lowercased() == "smb" else {
return nil
}
self.baseURL = baseURL
dispatch_queue = DispatchQueue(label: "FileProvider.\(SMBFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
self.baseURL = baseURL.appendingPathComponent("")
dispatch_queue = DispatchQueue(label: "FileProvider.\(type(of: self).type)", attributes: DispatchQueue.Attributes.concurrent)
operation_queue = OperationQueue()
operation_queue.name = "FileProvider.\(SMBFileProvider.type).Operation"
operation_queue.name = "FileProvider.\(type(of: self).type).Operation"
self.credential = credential
}
+32 -20
View File
@@ -9,8 +9,8 @@
import Foundation
public final class WebDavFileObject: FileObject {
internal init(absoluteURL: URL, name: String, path: String) {
super.init(absoluteURL: absoluteURL, name: name, path: path)
internal override init(url: URL, name: String, path: String) {
super.init(url: url, name: name, path: path)
}
open internal(set) var contentType: String {
@@ -73,16 +73,16 @@ open class WebDAVFileProvider: FileProviderBasicRemote {
if !["http", "https"].contains(baseURL.uw_scheme.lowercased()) {
return nil
}
self.baseURL = baseURL
self.baseURL = baseURL.appendingPathComponent("")
self.isPathRelative = true
self.currentPath = ""
self.useCache = false
self.validatingCache = true
self.cache = cache
self.credential = credential
dispatch_queue = DispatchQueue(label: "FileProvider.\(WebDAVFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
dispatch_queue = DispatchQueue(label: "FileProvider.\(type(of: self).type)", attributes: DispatchQueue.Attributes.concurrent)
operation_queue = OperationQueue()
operation_queue.name = "FileProvider.\(DropboxFileProvider.type).Operation"
operation_queue.name = "FileProvider.\(type(of: self).type).Operation"
}
deinit {
@@ -91,7 +91,7 @@ open class WebDAVFileProvider: FileProviderBasicRemote {
open func contentsOfDirectory(path: String, completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
let opType = FileOperationType.fetch(path: path)
let url = absoluteURL(path)
let url = self.url(of: path).appendingPathComponent("")
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
request.setValue("1", forHTTPHeaderField: "Depth")
@@ -118,7 +118,7 @@ open class WebDAVFileProvider: FileProviderBasicRemote {
}
open func attributesOfItem(path: String, completionHandler: @escaping ((_ attributes: FileObject?, _ error: Error?) -> Void)) {
let url = absoluteURL(path)
let url = self.url(of: path)
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
request.setValue("1", forHTTPHeaderField: "Depth")
@@ -178,7 +178,7 @@ extension WebDAVFileProvider: FileProviderOperations {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
return nil
}
let url = absoluteURL((atPath as NSString).appendingPathComponent(folderName) + "/")
let url = self.url(of: atPath).appendingPathComponent(folderName, isDirectory: true)
var request = URLRequest(url: url)
request.httpMethod = "MKCOL"
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
@@ -200,7 +200,7 @@ extension WebDAVFileProvider: FileProviderOperations {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
return nil
}
let url = absoluteURL(path).appendingPathComponent(fileName)
let url = self.url(of: path).appendingPathComponent(fileName)
var request = URLRequest(url: url)
request.httpMethod = "PUT"
let task = session.uploadTask(with: request, from: data, completionHandler: { (data, response, error) in
@@ -244,10 +244,10 @@ extension WebDAVFileProvider: FileProviderOperations {
}
func doOperation(operation opType: FileOperationType, overwrite: Bool? = nil, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
let sourceURL = absoluteURL(opType.source!)
let sourceURL = self.url(of:opType.source!)
var request = URLRequest(url: sourceURL)
if let dest = opType.destination {
request.setValue(absoluteURL(dest).absoluteString, forHTTPHeaderField: "Destination")
request.setValue(url(of:dest).absoluteString, forHTTPHeaderField: "Destination")
}
switch opType {
case .copy:
@@ -294,7 +294,7 @@ extension WebDAVFileProvider: FileProviderOperations {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
return nil
}
let url = absoluteURL(toPath)
let url = self.url(of:toPath)
var request = URLRequest(url: url)
request.httpMethod = "PUT"
let task = session.uploadTask(with: request, fromFile: localFile, completionHandler: { (data, response, error) in
@@ -316,7 +316,7 @@ extension WebDAVFileProvider: FileProviderOperations {
guard fileOperationDelegate?.fileProvider(self, shouldDoOperation: opType) ?? true == true else {
return nil
}
let url = absoluteURL(path)
let url = self.url(of:path)
let request = URLRequest(url: url)
let task = session.downloadTask(with: request, completionHandler: { (sourceFileURL, response, error) in
var responseError: FileProviderWebDavError?
@@ -344,7 +344,7 @@ extension WebDAVFileProvider: FileProviderReadWrite {
@discardableResult
public func contents(path: String, offset: Int64, length: Int, completionHandler: @escaping ((_ contents: Data?, _ error: Error?) -> Void)) -> OperationHandle? {
let opType = FileOperationType.fetch(path: path)
let url = absoluteURL(path)
let url = self.url(of: path)
var request = URLRequest(url: url)
request.httpMethod = "GET"
if length > 0 {
@@ -370,7 +370,7 @@ extension WebDAVFileProvider: FileProviderReadWrite {
return nil
}
// FIXME: lock destination before writing process
let url = atomically ? absoluteURL(path).appendingPathExtension("tmp") : absoluteURL(path)
let url = atomically ? self.url(of: path).appendingPathExtension("tmp") : self.url(of: path)
var request = URLRequest(url: url)
request.httpMethod = "PUT"
if !overwrite {
@@ -379,7 +379,7 @@ extension WebDAVFileProvider: FileProviderReadWrite {
let task = session.uploadTask(with: request, from: data, 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, url: self.absoluteURL(path))
responseError = FileProviderWebDavError(code: rCode, url: self.url(of: path))
}
defer {
self.delegateNotify(opType, error: responseError ?? error)
@@ -398,7 +398,7 @@ extension WebDAVFileProvider: FileProviderReadWrite {
}
public func searchFiles(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: @escaping ((_ files: [FileObject], _ error: Error?) -> Void)) {
let url = absoluteURL(path)
let url = self.url(of: path)
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
//request.setValue("1", forHTTPHeaderField: "Depth")
@@ -504,7 +504,19 @@ internal extension WebDAVFileProvider {
}
}
let href = node[hreftag].value
if let href = href, let hrefURL = URL(string: href) {
if let href = href {
let phrefURL: URL?
var relativePath = href.replacingOccurrences(of: self.baseURL?.absoluteString ?? "", with: "/")
if relativePath.hasPrefix("http://") || relativePath.hasPrefix("http://") {
phrefURL = URL(string: href)
} else {
if relativePath.hasPrefix("/") {
relativePath.remove(at: relativePath.startIndex)
}
phrefURL = URL(string: relativePath, relativeTo: self.baseURL) ?? self.baseURL
}
//let hrefURL = URL(string: href)
guard let hrefURL = phrefURL else { return nil }
var status: Int?
let statusDesc = (node[statustag].string).components(separatedBy: " ")
if statusDesc.count > 2 {
@@ -539,10 +551,10 @@ internal extension WebDAVFileProvider {
fileprivate func mapToFileObject(_ davResponse: DavResponse) -> WebDavFileObject {
var href = davResponse.href
if href.baseURL == nil {
href = absoluteURL(href.path)
href = url(of: href.path)
}
let name = davResponse.prop["displayname"] ?? (davResponse.hrefString.removingPercentEncoding! as NSString).lastPathComponent
let fileObject = WebDavFileObject(absoluteURL: href, name: name, path: href.path)
let fileObject = WebDavFileObject(url: href, name: name, path: href.path)
fileObject.size = Int64(davResponse.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
fileObject.creationDate = self.resolve(dateString: davResponse.prop["creationdate"] ?? "")
fileObject.modifiedDate = self.resolve(dateString: davResponse.prop["getlastmodified"] ?? "")