Updated Readme
WebDAV delegate calling
This commit is contained in:
@@ -1 +1,153 @@
|
||||
# FileProvider
|
||||
# FileProvider
|
||||
|
||||
This Swift library provide a swifty way to deal with local and remote files and directories in same way. This library provides implementaion of WebDav and SMB/CIFS (incomplete) and local files.
|
||||
|
||||
All functions are async recalls and it wont block your main thread.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy Source folder to your project!
|
||||
|
||||
## Usage
|
||||
|
||||
Each provider has a specific class which conforms to FileProvider protocol and share same syntax
|
||||
|
||||
### Providers
|
||||
|
||||
For now this providers are supported:
|
||||
|
||||
**LocalFileProvider :** a wrapper for NSFileManager with some additions like searching and reading a portion of file
|
||||
|
||||
**WebDAVFileProvider :** WebDAV protocol is usual file transmission system on Macs
|
||||
|
||||
**SMBFileProvider :** SMB/CIFS and SMB2/3 are file and printer sharing protocol which is originated from Windows and SMB2/3 is now replacing AFP protocol on MacOS too. I Implemented data types and some basic functions but main interface is not implemented yet!
|
||||
|
||||
### Initialization
|
||||
|
||||
For LocalFileProvider if you want to deal with `Documents` folder
|
||||
|
||||
let documentsFileProvider = LocalFileProvider()
|
||||
|
||||
is equal to:
|
||||
|
||||
let documentPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true);
|
||||
let documentsURL = NSURL(fileURLWithPath: documentPath);
|
||||
let documentsFileProvider = LocalFileProvider(baseURL: documentsURL)
|
||||
|
||||
You can't change the base url later. and all paths are related to this base url by default.
|
||||
|
||||
For remote file providers authentication may be necessary:
|
||||
|
||||
let credential = NSURLCredential(user: "user", password: "pass", persistence: NSURLCredentialPersistence.Permanent)
|
||||
let webdavProvider = WebDAVFileProvider(baseURL: "http://www.example.com/dav", credential: credential)
|
||||
|
||||
For interaction with UI, set delegate variable of `FileProvider` object
|
||||
|
||||
### Delegate
|
||||
|
||||
For updating User interface please consider using delegate method instead of completion handlers. Delegate methods are guaranteed to run in main thread to avoid bugs.
|
||||
|
||||
override func viewDidLoad() {
|
||||
documentsFileProvider.delegate = self
|
||||
}
|
||||
|
||||
func fileproviderCreateModifyNotify(fileProvider: LocalFileProvider, path: String) {
|
||||
NSLog("File \(path) modified")
|
||||
}
|
||||
|
||||
func fileproviderCopyNotify(fileProvider: LocalFileProvider, fromPath: String, toPath: String) {
|
||||
NSLog("File \(path) copied")
|
||||
}
|
||||
|
||||
func fileproviderMoveNotify(fileProvider: LocalFileProvider, fromPath: String, toPath: String) {
|
||||
NSLog("File \(path) moved")
|
||||
}
|
||||
|
||||
func fileproviderRemoveNotify(fileProvider: LocalFileProvider, path: String) {
|
||||
NSLog("File \(path) deleted")
|
||||
}
|
||||
|
||||
Use completion handlers for error handling or result processing as far as possible.
|
||||
|
||||
### Directory contents and file attributes
|
||||
|
||||
There is a `FileObject` class which holds file attributes like size and creation date. You can retrieve information of files inside a directory or get information of a file directly
|
||||
|
||||
documentsFileProvider.attributesOfItemAtPath(path: "/file.txt", completionHandler: {
|
||||
(attributes: LocalFileObject?, error: ErrorType?) -> Void} in
|
||||
if let attributes = attributes {
|
||||
print("File Size: \(attributes.size)")
|
||||
print("Creation Date: \(attributes.createdDate)")
|
||||
print("Modification Date: \(modifiedDate)")
|
||||
print("Is Read Only: \(isReadOnly)")
|
||||
}
|
||||
)
|
||||
|
||||
documentsFileProvider.contentsOfDirectoryAtPath(path: "/", completionHandler: {
|
||||
(contents: [LocalFileObject], error: ErrorType?) -> Void} in
|
||||
for file in contents {
|
||||
print("Name: \(attributes.name)")
|
||||
print("Size: \(attributes.size)")
|
||||
print("Creation Date: \(attributes.createdDate)")
|
||||
print("Modification Date: \(modifiedDate)")
|
||||
}
|
||||
)
|
||||
|
||||
### Change current directory
|
||||
|
||||
documentsFileProvider.currentPath = "/New Folder"
|
||||
// now path is ~/Documents/New Folder
|
||||
|
||||
### Creating File and Folders
|
||||
|
||||
Creating new directory:
|
||||
|
||||
documentsFileProvider.createFolder(folderName: "new folder", atPath: "/", completionHandler: nil)
|
||||
|
||||
Creating new file from data stream:
|
||||
|
||||
let data = "hello world!".dataUsingEncoding(NSUTF8StringEncoding)
|
||||
let file = FileObject(absoluteURL: NSURL(), name: "old.txt", size: -1, createdDate: NSDate(), modifiedDate: NSDate(), fileType: .Regular, isHidden: false, isReadOnly: true)
|
||||
documentsFileProvider.createFile(fileAttribs: file, atPath: "/", contents: data, completionHandler: nil)
|
||||
|
||||
### Copy and Move/Rename Files
|
||||
|
||||
// Copy file old.txt to new.txt in current path
|
||||
documentsFileProvider.copyItemAtPath(path: "new folder/old.txt", toPath: "new.txt", overwrite: false, completionHandler: nil)
|
||||
|
||||
// Move file old.txt to new.txt in current path
|
||||
documentsFileProvider.moveItemAtPath(path: "new folder/old.txt", toPath: "new.txt", overwrite: false, completionHandler: nil)
|
||||
|
||||
### Delete Files
|
||||
|
||||
documentsFileProvider.removeItemAtPath(path: "new.txt", completionHandler: nil)
|
||||
|
||||
Caution: This method will not delete directories with content.
|
||||
|
||||
|
||||
### Retrieve Content of File
|
||||
|
||||
THere is two method for this purpose, one of them loads entire file into NSData and another can load a portion of file.
|
||||
|
||||
documentsFileProvider.contentsAtPath(path: "old.txt:, completionHandler: {
|
||||
(contents: NSData?, error: ErrorType?) -> Void
|
||||
if let contents = contents {
|
||||
print(String(data: contents, encoding: NSUTF8StringEncoding)) // "hello world!"
|
||||
}
|
||||
})
|
||||
|
||||
If you want to retrieve a portion of file you should can `contentsAtPath` method with offset and length arguments. Please note first byte of file has offset: 0.
|
||||
|
||||
documentsFileProvider.contentsAtPath(path: "old.txt:, offset: 2, length: 5, completionHandler: {
|
||||
(contents: NSData?, error: ErrorType?) -> Void
|
||||
if let contents = contents {
|
||||
print(String(data: contents, encoding: NSUTF8StringEncoding)) // "llo w"
|
||||
}
|
||||
})
|
||||
|
||||
### Write Data To Files
|
||||
|
||||
let data = "What's up Newyork!".dataUsingEncoding(NSUTF8StringEncoding)
|
||||
documentsFileProvider.writeContentsAtPath(path: "old, contents data: data, atomically: true, completionHandler: nil)
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ class LocalFileProvider: FileProvider {
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCreateModifyNotify(self, path: atPath)
|
||||
})
|
||||
} else {
|
||||
completionHandler?(error: self.throwError(atPath, code: NSURLError.CannotCreateFile))
|
||||
}
|
||||
}
|
||||
@@ -267,8 +268,4 @@ extension LocalFileProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extendedAttributes(path: String) -> FileExtendedAttributes {
|
||||
return FileExtendedAttributes(fileURL: self.absoluteURL(path))
|
||||
}
|
||||
}
|
||||
@@ -115,56 +115,56 @@ class SMBFileProvider: NSObject, FileProvider, NSStreamDelegate {
|
||||
|
||||
func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObjectClass], error: ErrorType?) -> Void)) {
|
||||
dispatch_async(dispatch_queue) {
|
||||
|
||||
self.NotImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObjectClass?, error: ErrorType?) -> Void)) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func createFile(fileAttribs: FileObject, atPath: String, contents data: NSData?, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func moveItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func copyItemAtPath(path: String, toPath: String, overwrite: Bool = false, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func removeItemAtPath(path: String, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func contentsAtPath(path: String, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool, completionHandler: SimpleCompletionHandler) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
|
||||
func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObjectClass) -> Void)?, completionHandler: ((files: [FileObjectClass], error: ErrorType?) -> Void)) {
|
||||
|
||||
NotImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,9 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
return
|
||||
}
|
||||
completionHandler?(error: error)
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCreateModifyNotify(self, path: atPath)
|
||||
})
|
||||
}.resume()
|
||||
}
|
||||
|
||||
@@ -177,6 +180,9 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
request.HTTPMethod = "PUT"
|
||||
session.uploadTaskWithRequest(request, fromData: data) { (data, response, error) in
|
||||
completionHandler?(error: error)
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCreateModifyNotify(self, path: path)
|
||||
})
|
||||
}.resume()
|
||||
}
|
||||
|
||||
@@ -191,8 +197,12 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
request.setValue("F", forHTTPHeaderField: "Overwrite")
|
||||
}
|
||||
session.dataTaskWithRequest(request) { (data, response, error) in
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) where code != .OK {
|
||||
if code == .MultiStatus, let data = data {
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) {
|
||||
if code == .OK {
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderMoveNotify(self, fromPath: path, toPath: toPath)
|
||||
})
|
||||
} else if code == .MultiStatus, let data = data {
|
||||
let xresponses = self.parseXMLResponse(data)
|
||||
for xresponse in xresponses {
|
||||
if xresponse.status >= 300 {
|
||||
@@ -202,6 +212,9 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
} else {
|
||||
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderMoveNotify(self, fromPath: path, toPath: toPath)
|
||||
})
|
||||
return
|
||||
}
|
||||
completionHandler?(error: error)
|
||||
@@ -219,14 +232,21 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
request.setValue("F", forHTTPHeaderField: "Overwrite")
|
||||
}
|
||||
session.dataTaskWithRequest(request) { (data, response, error) in
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) where code != .OK {
|
||||
if code == .MultiStatus, let data = data {
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) {
|
||||
if code == .OK {
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCopyNotify(self, fromPath: path, toPath: toPath)
|
||||
})
|
||||
} else if code == .MultiStatus, let data = data {
|
||||
let xresponses = self.parseXMLResponse(data)
|
||||
for xresponse in xresponses {
|
||||
if xresponse.status >= 300 {
|
||||
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
|
||||
}
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCopyNotify(self, fromPath: path, toPath: toPath)
|
||||
})
|
||||
} else {
|
||||
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
|
||||
}
|
||||
@@ -243,14 +263,21 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
request.HTTPMethod = "DELETE"
|
||||
request.setValue(baseURL?.absoluteString, forHTTPHeaderField: "Host")
|
||||
session.dataTaskWithRequest(request) { (data, response, error) in
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) where code != .OK {
|
||||
if code == .MultiStatus, let data = data {
|
||||
if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) {
|
||||
if code == .OK {
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderRemoveNotify(self, path: path)
|
||||
})
|
||||
} else if code == .MultiStatus, let data = data {
|
||||
let xresponses = self.parseXMLResponse(data)
|
||||
for xresponse in xresponses {
|
||||
if xresponse.status >= 300 {
|
||||
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
|
||||
}
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderRemoveNotify(self, path: path)
|
||||
})
|
||||
} else {
|
||||
completionHandler?(error: FileProviderWebDavError(code: code, url: url))
|
||||
}
|
||||
@@ -265,6 +292,9 @@ class WebDAVFileProvider: NSObject, FileProvider {
|
||||
request.HTTPMethod = "PUT"
|
||||
session.uploadTaskWithRequest(request, fromFile: localFile) { (data, response, error) in
|
||||
completionHandler?(error: error)
|
||||
dispatch_async(dispatch_get_main_queue(), {
|
||||
self.delegate?.fileproviderCreateModifyNotify(self, path: toPath)
|
||||
})
|
||||
}.resume()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user