updated readme, copyright - broke FileProvider protocol

This commit is contained in:
Amir Abbas Mousavian
2016-07-06 12:44:57 +04:30
parent 0dab051a2e
commit cf0b324dfa
8 changed files with 191 additions and 140 deletions
+68 -33
View File
@@ -1,48 +1,66 @@
# FileProvider (experimental)
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.
>This Swift library provide a swifty way to deal with local and remote files and directories in same way.
[![Swift Version][swift-image]][swift-url]
[![Build Status][travis-image]][travis-url]
[![License][license-image]][license-url]
[![Platform](https://img.shields.io/badge/Platform-iOS%2C%20OSX-lightgray.svg)]()
[![codebeat badge](https://codebeat.co/badges/7b359f48-78eb-4647-ab22-56262a827517)](https://codebeat.co/projects/github-com-amosavian-fileprovider)
<!---
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/EZSwiftExtensions.svg)](https://img.shields.io/cocoapods/v/LFAlertController.svg)
--->
This library provides implementaion of WebDav and SMB/CIFS (incomplete) and local files.
All functions are async calls and it wont block your main thread.
## Features
- [x] **LocalFileProvider** a wrapper for `NSFileManager` with some additions like searching and reading a portion of file
- [x] **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 IBM & Microsoft and SMB2/3 is now replacing AFP protocol on MacOS. I Implemented data types and some basic functions but *main interface is not implemented yet!*
- [ ] **DropboxFileProvider**
- [ ] **FTPFileProvider**
- [ ] **AmazonS3FileProvider**
## Requirements
- **Swift 2.2**
- iOS 7.0 , OSX 10.9
- XCode 7.3
## Installation
#### Manually
Copy Source folder to your project!
### Cocoapods / Carthage / Swift Package Manager
#### Git clone
Use this command on terminal to get a clone:
I will add when project is completed is ready to use in production envioronment
### Git clone
To have latest updates with ease, use this command on terminal to get a clone:
git clone https://github.com/amosavian/FileProvider FileProvider
You can update your library using this command in FileProvider folder:
#### Submodule into your project
Use this command if you have a git based project in your projects directory:
git pull
### Submodule into your project
if you have a git based project, use this command in your projects directory:
git submodule add https://github.com/amosavian/FileProvider FileProvider
#### Cocoapods / Carthage / Swift Package Manager
I will add when project is completed is ready to use in production envioronment
### Manually
Copy Source folder to your project and voila!
## 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. I Implemented data types and some basic functions but *main interface is not implemented yet!*
**FTPFileProvider :** not implemented yet!
**DropboxFileProvider :** not implemented yet!
Your pull requests are welcomed!
### Initialization
For LocalFileProvider if you want to deal with `Documents` folder
@@ -191,12 +209,29 @@ If you want to retrieve a portion of file you should can `contentsAtPath` method
let data = "What's up Newyork!".dataUsingEncoding(NSUTF8StringEncoding)
documentsFileProvider.writeContentsAtPath(path: "old.txt", contents data: data, atomically: true, completionHandler: nil)
### Monitoring FIle Changes
### TODO List
## Contribute
- [ ] TCPSocket test (using telnet)
- [ ] SMB2 protocol support using TCPSocketClient
- [ ] FTP/FTPS protocol support using TCPSocketClient
- [ ] Dropbox support
- [ ] Amazon S3 support
- [ ] SMB1 protocol implementation
We would love for you to contribute to **FileProvider**, check the `LICENSE` file for more info.
## Meta
Amir-Abbas Mousavia – [@amosavian](https://twitter.com/amosavian)
Distributed under the MIT license. See `LICENSE` for more information.
[https://github.com/yourname/github-link](https://github.com/dbader/)
[swift-image]:https://img.shields.io/badge/swift-2.3-green.svg
[swift-url]: https://swift.org/
[license-image]: https://img.shields.io/badge/License-MIT-blue.svg
[license-url]: LICENSE
<!---
[travis-image]: https://img.shields.io/travis/dbader/node-datadog-metrics/master.svg?style=flat-square
[travis-url]: https://travis-ci.org/dbader/node-datadog-metrics
--->
[codebeat-image]: https://codebeat.co/badges/c19b47ea-2f9d-45df-8458-b2d952fe9dad
[codebeat-url]: https://codebeat.co/projects/github-com-vsouza-awesomeios-com
+58 -12
View File
@@ -1,9 +1,9 @@
//
// FileProvider.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 3/28/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -11,7 +11,7 @@ import Foundation
import UIKit
#endif
#if (OSX)
import Cocoa
import AppKit
#endif
public enum FileType: String {
@@ -96,7 +96,7 @@ public class FileObject {
public typealias SimpleCompletionHandler = ((error: ErrorType?) -> Void)?
public protocol FileProvider: class {
public protocol FileProviderBasic: class {
var type: String { get }
var isPathRelative: Bool { get }
var baseURL: NSURL? { get }
@@ -110,7 +110,9 @@ public protocol FileProvider: class {
*/
func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObject], error: ErrorType?) -> Void))
func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObject?, error: ErrorType?) -> Void))
}
public protocol FileProviderOperations: FileProviderBasic {
func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler)
func createFile(fileAttribs: FileObject, atPath: String, contents data: NSData?, completionHandler: SimpleCompletionHandler)
func moveItemAtPath(path: String, toPath: String, overwrite: Bool, completionHandler: SimpleCompletionHandler)
@@ -119,18 +121,26 @@ public protocol FileProvider: class {
func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler)
func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler)
}
public protocol FileProviderReadWrite: FileProviderBasic {
func contentsAtPath(path: String, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void))
func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void))
func writeContentsAtPath(path: String, contents data: NSData, atomically: Bool, completionHandler: SimpleCompletionHandler)
func searchFilesAtPath(path: String, recursive: Bool, query: String, foundItemHandler: ((FileObject) -> Void)?, completionHandler: ((files: [FileObject], error: ErrorType?) -> Void))
}
public protocol FileProviderMonitor: FileProviderBasic {
func registerNotifcation(path: String, eventHandler: (() -> Void))
func unregisterNotifcation(path: String)
}
extension FileProvider {
public protocol FileProvider: FileProviderBasic, FileProviderOperations, FileProviderReadWrite {
}
extension FileProviderBasic {
var bareCurrentPath: String {
return currentPath.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: ". /"))
}
@@ -170,6 +180,42 @@ extension FileProvider {
internal func NotImplemented() {
assert(false, "method not implemented")
}
internal func resolveRFCDate(httpDateString: String) -> NSDate? {
let dateFor: NSDateFormatter = NSDateFormatter()
dateFor.locale = NSLocale(localeIdentifier: "en_US")
dateFor.dateFormat = "EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"
if let rfc1123 = dateFor.dateFromString(httpDateString) {
return rfc1123
}
dateFor.dateFormat = "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"
if let rfc850 = dateFor.dateFromString(httpDateString) {
return rfc850
}
dateFor.dateFormat = "EEE MMM d HH':'mm':'ss yyyy"
if let asctime = dateFor.dateFromString(httpDateString) {
return asctime
}
//self.init()
return nil
}
internal func jsonToDictionary(jsonString: String) -> [String: AnyObject]? {
guard let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding) else {
return nil
}
if let dic = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject] {
return dic
}
return nil
}
internal func dictionaryToJSON(dictionary: [String: AnyObject]) -> String? {
if let data = try? NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions()) {
return String(data: data, encoding: NSUTF8StringEncoding)
}
return nil
}
}
#if (iOS)
@@ -194,9 +240,9 @@ public enum FileOperation {
}
public protocol FileProviderDelegate {
func fileproviderSucceed(fileProvider: FileProvider, operation: FileOperation)
func fileproviderFailed(fileProvider: FileProvider, operation: FileOperation)
func fileproviderProgress(fileProvider: FileProvider, operation: FileOperation, progress: Float)
func fileproviderSucceed(fileProvider: FileProviderOperations, operation: FileOperation)
func fileproviderFailed(fileProvider: FileProviderOperations, operation: FileOperation)
func fileproviderProgress(fileProvider: FileProviderOperations, operation: FileOperation, progress: Float)
}
+4 -4
View File
@@ -1,9 +1,9 @@
//
// LocalFileProvider.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 3/29/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -17,7 +17,7 @@ public final class LocalFileObject: FileObject {
}
}
public class LocalFileProvider: FileProvider {
public class LocalFileProvider: FileProvider, FileProviderMonitor {
public let type = "NSFileManager"
public var isPathRelative: Bool = true
public var baseURL: NSURL? = LocalFileProvider.defaultBaseURL()
+15 -22
View File
@@ -1,9 +1,9 @@
//
// SMB2Types.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 4/15/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -12,12 +12,12 @@ import Foundation
struct SMB2 {
struct Header: FileProviderSMBHeader { // 64 bytes
// header is always \u{fe}SMB
var protocolID: UInt32
let protocolID: UInt32
static let protocolConst: UInt32 = 0x424d53fe
var size: UInt16
var creditCharge: UInt16
let size: UInt16
let creditCharge: UInt16
// error messages from the server to the client
var status: UInt32
let status: UInt32
enum StatusSeverity: UInt8 {
case Success = 0, Information, Warning, Error
}
@@ -25,32 +25,25 @@ struct SMB2 {
let severity = StatusSeverity(rawValue: UInt8(status >> 30))!
return (severity, status & 0x20000000 != 0, UInt16((status & 0x0FFF0000) >> 16), UInt16(status & 0x0000FFFF))
}
private var _command: UInt16
private let _command: UInt16
var command: Command {
get {
return Command(rawValue: _command) ?? .INVALID
}
set {
_command = newValue.rawValue
}
}
var creditRequestResponse: UInt16
var flags: Flags
let creditRequestResponse: UInt16
let flags: Flags
var nextCommand: UInt32
var messageId: UInt64
private var reserved: UInt32
var treeId: UInt32
let messageId: UInt64
private let reserved: UInt32
let treeId: UInt32
var asyncId: UInt64 {
get {
return UInt64(reserved) + (UInt64(treeId) << 32)
}
set {
reserved = UInt32(newValue & 0xffffffff)
treeId = UInt32(newValue >> 32)
}
}
var sessionId: UInt64
var signature: (UInt64, UInt64)
let sessionId: UInt64
let signature: (UInt64, UInt64)
init(command: Command, status: NTStatus = .SUCCESS, creditCharge: UInt16 = 0, creditRequestResponse: UInt16, flags: Flags = [], nextCommand: UInt32 = 0, messageId: UInt64, treeId: UInt32, sessionId: UInt64, signature: (UInt64, UInt64) = (0, 0)) {
self.protocolID = self.dynamicType.protocolConst
+5 -5
View File
@@ -1,9 +1,9 @@
//
// SMBTransmitter.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 4/10/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -45,7 +45,7 @@ class SMBProtocolClient: TCPSocketClient {
} catch _ {
return nil
}
self.waitForResponse()
self.waitUntilResponse()
let response = try? SMBProtocolClient.digestSMB2Message(dataReceived)
return response??.message as? SMB2.NegotiateResponse
}
@@ -218,7 +218,7 @@ struct SMBTime {
}
protocol FileProviderSMBHeader {
var protocolID: UInt32 { get set }
var protocolID: UInt32 { get }
static var protocolConst: UInt32 { get }
}
+4 -4
View File
@@ -1,14 +1,14 @@
//
// SambaFileProvider.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 3/29/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
class SMBFileProvider: FileProvider {
class SMBFileProvider: FileProvider, FileProviderMonitor {
var type: String = "Samba"
var isPathRelative: Bool = true
var baseURL: NSURL?
+24 -13
View File
@@ -1,9 +1,9 @@
//
// SocketTransmitter.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 4/9/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -39,7 +39,7 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
public let secureConnection: Bool
/// server's ports which is value between 1 to 65535
private let port: UInt32
private var connected = false
private var open = false
/**
* - parameter baseURL: a url with valid scheme, dns or ip host and ports
@@ -126,14 +126,14 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
switch (eventCode) {
case NSStreamEvent.ErrorOccurred:
connected = false
open = false
case NSStreamEvent.EndEncountered:
break
case NSStreamEvent.None:
break
case NSStreamEvent.OpenCompleted:
let activeStatus: [NSStreamStatus] = [.Open, .Reading, .Writing, .AtEnd]
connected = activeStatus.contains(inputStream?.streamStatus ?? .NotOpen) && activeStatus.contains(outputStream?.streamStatus ?? .NotOpen)
open = activeStatus.contains(inputStream?.streamStatus ?? .NotOpen) && activeStatus.contains(outputStream?.streamStatus ?? .NotOpen)
case NSStreamEvent.HasBytesAvailable:
var buffer = [UInt8](count: 2048, repeatedValue: 0)
if ( aStream == inputStream) {
@@ -165,13 +165,16 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
*/
public func send(data data: NSData?) throws {
if self.outputStream?.hasSpaceAvailable ?? false {
guard let outputStream = outputStream else {
return
}
if outputStream.hasSpaceAvailable ?? false {
if let data = data {
dataToBeSent.appendData(data)
}
if dataToBeSent.length > 0 {
let bytesWritten = self.outputStream?.write(UnsafePointer(dataToBeSent.bytes), maxLength: dataToBeSent.length) ?? -1
let bytesWritten = outputStream.write(UnsafePointer(dataToBeSent.bytes), maxLength: dataToBeSent.length) ?? -1
if bytesWritten > 0 {
let range = NSRange(location: 0, length: bytesWritten)
dataToBeSent.replaceBytesInRange(range, withBytes: nil, length: 0)
@@ -187,14 +190,23 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
}
}
/**
* Clears entire send and receive buffer
*/
public func flush() {
dataToBeSent.length = 0
dataReceived.length = 0
}
/**
* Put's thread in sleep until all data is sent
* **Note:** Don't call this method from main thread
*/
internal func waitForSendDataPurge() {
internal func waitUntillDataSent() {
if NSThread.isMainThread() {
assertionFailure("waitForSendDataPurge() method can't be called from main thread")
assert(false, "waitUntillDataSent() method can't be called from main thread")
}
while true {
if dataToBeSent.length == 0 {
@@ -213,9 +225,9 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
* - returns: A Bool value indicates all response loaded from server successfullt
*/
internal func waitForResponse() -> Bool {
internal func waitUntilResponse() -> Bool {
if NSThread.isMainThread() {
assertionFailure("waitForResponse() method can't be called from main thread")
assert(false, "waitUntilResponse() method can't be called from main thread")
}
var finished = false
while !finished {
@@ -230,7 +242,6 @@ public class TCPSocketClient: NSObject, NSStreamDelegate {
}
NSRunLoop.currentRunLoop().runUntilDate(NSDate(timeIntervalSinceNow: 0.1));
NSThread.currentThread()
NSThread.sleepForTimeInterval(0.1)
}
return false
+13 -47
View File
@@ -1,9 +1,9 @@
//
// WebDAVFileProvider.swift
// ExtDownloader
// FileProvider
//
// Created by Amir Abbas Mousavian on 4/6/95.
// Copyright © 1395 Mousavian. All rights reserved.
// Created by Amir Abbas Mousavian.
// Copyright © 2016 Mousavian. Distributed under MIT license.
//
import Foundation
@@ -407,8 +407,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
task.resume()
}
public func registerNotifcation(path: String, eventHandler: (() -> Void)) {
NotImplemented()
private func registerNotifcation(path: String, eventHandler: (() -> Void)) {
/* There is no unified api for monitoring WebDAV server content change/update
* Microsoft Exchange uses SUBSCRIBE method, Apple uses push notification system.
* while both is unavailable in a mobile platform.
@@ -416,8 +415,8 @@ public class WebDAVFileProvider: NSObject, FileProvider {
* with previous results
*/
}
public func unregisterNotifcation(path: String) {
NotImplemented()
private func unregisterNotifcation(path: String) {
}
// TODO: implements methods for lock mechanism
}
@@ -507,53 +506,20 @@ internal extension WebDAVFileProvider {
return result
}
func DavResponseToFileObject(davResponse: DavResponse) -> WebDavFileObject {
let href = davResponse.href
private func DavResponseToFileObject(davResponse: DavResponse) -> WebDavFileObject {
var href = davResponse.href
if href.baseURL == nil {
href = absoluteURL(href.path ?? "")
}
let name = davResponse.prop["displayname"] ?? (davResponse.hrefString.stringByRemovingPercentEncoding! as NSString).lastPathComponent
let size = Int64(davResponse.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveHTTPDate(davResponse.prop["creationdate"] ?? "")
let modifiedDate = self.resolveHTTPDate(davResponse.prop["getlastmodified"] ?? "")
let createdDate = self.resolveRFCDate(davResponse.prop["creationdate"] ?? "")
let modifiedDate = self.resolveRFCDate(davResponse.prop["getlastmodified"] ?? "")
let contentType = davResponse.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = davResponse.prop["getetag"]
return WebDavFileObject(absoluteURL: href, name: name, size: size, contentType: contentType, createdDate: createdDate, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: false, entryTag: entryTag)
}
func resolveHTTPDate(httpDateString: String) -> NSDate? {
let dateFor: NSDateFormatter = NSDateFormatter()
dateFor.locale = NSLocale(localeIdentifier: "en_US")
dateFor.dateFormat = "EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"
if let rfc1123 = dateFor.dateFromString(httpDateString) {
return rfc1123
}
dateFor.dateFormat = "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"
if let rfc850 = dateFor.dateFromString(httpDateString) {
return rfc850
}
dateFor.dateFormat = "EEE MMM d HH':'mm':'ss yyyy"
if let asctime = dateFor.dateFromString(httpDateString) {
return asctime
}
//self.init()
return nil
}
func jsonToDictionary(jsonString: String) -> [String: AnyObject]? {
guard let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding) else {
return nil
}
if let dic = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject] {
return dic
}
return nil
}
func dictionaryToJSON(dictionary: [String: AnyObject]) -> String? {
if let data = try? NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions()) {
return String(data: data, encoding: NSUTF8StringEncoding)
}
return nil
}
}
// MARK: URLSession delegate