Skip to content

Nextcloud Thumbnails #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 116 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
06c24d6
Added test
amosavian Nov 2, 2017
bf75db8
Update project settings
amosavian Nov 2, 2017
fe0ff89
Fix error
amosavian Nov 2, 2017
783e58c
Fixed Test project settings, test for Dropbox and OneDrive
amosavian Nov 2, 2017
d0b4d13
Updated travis to test
amosavian Nov 2, 2017
f3d049f
Fixed travis test scheme name
amosavian Nov 3, 2017
76e0865
Fix Dropbox attributesOfItem, fix test cases
amosavian Nov 4, 2017
f99d40c
Fix #70 (WebDAV folder), Better URLRequest header interface
amosavian Nov 14, 2017
df781db
Fixed typo in WebDAV
amosavian Nov 16, 2017
7c25bcd
Fix #72 (WebDAV result contains space)
amosavian Dec 1, 2017
4636632
Probable fix #76 , deinit to cleanup providers
amosavian Dec 24, 2017
2603800
Update project settings
amosavian Dec 25, 2017
0fb3fe5
Fix. #71, Temp workaround for StreamTask issue
amosavian Dec 26, 2017
b2b82ab
Fix #74 (SPM issue)
amosavian Dec 26, 2017
3f09c6e
Fix SPM Error
amosavian Dec 26, 2017
d29826c
Fix FTP provider crashes and errors on uploading and downloading
amosavian Dec 27, 2017
3c87dfb
Fixed FTP errors to bypass test cases and build error on macOS
amosavian Dec 27, 2017
f20bcf7
Fix Swift 3 compile error
amosavian Dec 27, 2017
bd77c6e
Fix StreamTask read data bug
amosavian Dec 29, 2017
fec0346
Added Tests for FTP
amosavian Dec 29, 2017
611366b
Updated project settings version to 0.22
amosavian Dec 30, 2017
9b8db9e
Fix #79 , Optimization and refactoring
amosavian Jan 5, 2018
a393198
Add Beerpay's badge
amosavian Jan 16, 2018
19f9113
iCloud provider refactor
amosavian Jan 31, 2018
634a40c
bugfix. searchFiles "including" param was being ignored
Feb 12, 2018
729d9b9
Merge pull request #83 from jper92/master
amosavian Feb 12, 2018
8cc6bf5
Refactored HTTP provider upload methods, few improvements and refactors
amosavian Feb 12, 2018
5868766
OneDrive to support upload session, removing 4MB limit. Improved Docu…
amosavian Feb 12, 2018
e6b8e60
Probable fix #82 (iCloud overwrite file when uploading)
amosavian Feb 12, 2018
516144e
Added Concepts and Design markdown
amosavian Feb 13, 2018
7e8bc05
Capitilize DESIGN.md
amosavian Feb 13, 2018
50bbe7f
Fixed Dropbox issue
amosavian Feb 18, 2018
1bf42b4
Updated SMB types, Fix #84 (FTP must fail to init without scheme)
amosavian Feb 23, 2018
fd89a04
Fixed FTP/SSL issue, Fixed error descriptions for HTTP and FTP
amosavian Feb 24, 2018
09cb343
Fixed OneDrive provider
amosavian Feb 26, 2018
173fba5
Fixed OneDrive upload bug
amosavian Feb 26, 2018
8e617c5
Woraround overriding bug in Swift for url(of:), Initial support for L…
amosavian Mar 1, 2018
f384d26
Added sample code file
amosavian Mar 2, 2018
be38e27
Addded discardableResult
amosavian Mar 2, 2018
90f846c
Fixed: OneDrive operations may fail, Made linux-ready changes.
amosavian Mar 6, 2018
a3a584c
isReachable returns error (#87), Updating version
amosavian Mar 6, 2018
4b0fffc
Fix Test building error
amosavian Mar 6, 2018
a6550b0
Fixed utf8 filenames issue in OneDrive
amosavian Mar 7, 2018
2690551
Fixed FTP/TLS, Support FTP listing on Windows servers
amosavian Mar 8, 2018
8f0cbf8
Support FTP EPSV mode, property to set data connection TLS
amosavian Mar 8, 2018
b39c1c4
Fixed FTP issues. (Partial fix #88)
amosavian Mar 12, 2018
37ce9c9
FTP provider fallbacks from EPSV to PASV if extended is not implmented
amosavian Mar 13, 2018
6c34a4e
Updated version, removed obsoleted properties
amosavian Mar 27, 2018
fc75c85
Fixed warnings on Swift 4.1, LocalFileMonitor is now public
amosavian Mar 31, 2018
090baa3
Fix Swift 4.0 compile error
amosavian Mar 31, 2018
a089cbc
Fixed Swift 3 build error
amosavian Apr 1, 2018
ad9768a
Secure encoding enabled, Fixed podspec
amosavian Apr 7, 2018
bcc774d
Fix podspec error
amosavian Apr 7, 2018
9d19768
Added test for NSCoding, fixed archiving
amosavian Apr 8, 2018
bd2f2b3
Addded progressive read to FTP and HTTP providers
amosavian Apr 16, 2018
3040215
Fixed race conditions, Possible fix #79
amosavian Apr 22, 2018
4202f5e
FPStreamTask returning real error instead of timeout
amosavian Apr 22, 2018
f2cd571
Fixed LocalFileMonitor dir not refreshing, Fixed FTP connection refus…
amosavian Apr 25, 2018
e5e5faa
Fixed iCloud download/upload progress report, Fix #93
amosavian May 3, 2018
f22af8d
Fixed possible leak in iCloud provider when uploading file
amosavian May 3, 2018
e4fc6b2
Updated to version 0.24.1, Pods Swift version to 4.1
amosavian May 3, 2018
ccb7961
Minor performance improvement on iCloud file progress monitor
amosavian May 3, 2018
e72d7ff
Fixed podspec Swift version
amosavian May 3, 2018
399d755
Add FileProviderSymbolicLink protocol, resolving symlink return FileO…
amosavian May 11, 2018
5e49202
Fix Travis swift 4.0 build
amosavian May 12, 2018
b946d51
Fixed LocalFileObject init issue, symlink tests
amosavian May 12, 2018
7a3c4a2
Removed AnyObject casts
amosavian May 19, 2018
e2520ff
Possible fix #94, local symbolic links respect ~
amosavian May 26, 2018
f5c6403
Fixing #95 (ftp store completion handler latency)
amosavian May 30, 2018
7a5cef4
Updated readme to mention AMSMB2 project.
amosavian May 30, 2018
7530556
Silence warnings of Swift 4.2
amosavian Jun 6, 2018
057bf1a
Fix compile error
amosavian Jun 6, 2018
ba9cad8
Merge branch 'fix-issue-95'
amosavian Jun 6, 2018
50f0d33
Improved performance of thumbnail generating dramatically
amosavian Jun 12, 2018
91f2610
Fix PDF thumbnail generating, Faster UIImage scaling
amosavian Jun 14, 2018
cf6e6f9
Probable fix #99 (double delegate call), better linux support
amosavian Jun 18, 2018
7b21605
Amend finxing #99
amosavian Jun 21, 2018
f1f7955
Fix #105 FTP downloads corrupt file
amosavian Jul 7, 2018
fb389c1
Fix #102 & #103 (FTP write issue), Fix fileSize overflow on 32bit device
amosavian Jul 7, 2018
311fcc5
Switching to Stream, Fixed FPStreamTask would remain open
amosavian Jul 7, 2018
5e3db16
FTPdownload to use Stream, Fix FTP upload truncated
amosavian Jul 10, 2018
e2572d2
Fix #109, refactoring
amosavian Jul 19, 2018
38fb3fc
Fix remote session crash, minor fixes
amosavian Jul 26, 2018
76aee40
Undo for all providers, encapsulated error creating
amosavian Aug 5, 2018
b597244
Fix #112 (crash on progress report)
amosavian Aug 18, 2018
08d4766
Swift 4.2, fixed warnings, fixed tests
bscothern Oct 16, 2018
5c33683
updated .travis.yml to use xcode10
bscothern Oct 16, 2018
26a9e2d
updated podspec to use Swift 4.2
bscothern Oct 16, 2018
36c600e
updated FileObject's hash implementation
bscothern Oct 16, 2018
ab1da39
Merge pull request #126 from bscothern/swift_4.2
amosavian Oct 16, 2018
1fd724c
Added connect to self-signed certificate FTPS server
sasaki-945 Nov 9, 2018
92f0970
Convert a boolean value to enum for connecting to self-signed certifi…
sasaki-945 Nov 14, 2018
3f59178
Merge pull request #130 from sasaki-945/master
amosavian Nov 14, 2018
59ba5b7
Fixed bugs in FTP provider fallbacks from EPSV to PASV
sasaki-945 Nov 15, 2018
9cbe0fc
Fixed bugs in FTPS, `ftpUserPass` was called twice
sasaki-945 Nov 15, 2018
d6d777f
Fixed a blocked stream handle event during UI control
sasaki-945 Nov 16, 2018
933ef9b
Fixed a truncated uploaded file
sasaki-945 Nov 16, 2018
8a5edc5
Fixed a timeout error not notified
sasaki-945 Nov 16, 2018
9d5ac10
Merge pull request #131 from sasaki-945/master
amosavian Nov 17, 2018
967a5a0
Merge pull request #133 from sasaki-945/issue#111
amosavian Nov 17, 2018
d97f6c0
To keep it compatible to Swift 3/4.0
sasaki-945 Nov 19, 2018
004966a
Fixed a timeout error occurred when ftpList an empty directory
sasaki-945 Nov 19, 2018
d462b5d
Add missed commit - `[933ef9b] Fixed a truncated uploaded file`
sasaki-945 Nov 19, 2018
504ca76
Fixed a multiple error callback on `recursiveList`
sasaki-945 Nov 19, 2018
d050ceb
Added `filePath` argument on FileProviderFTPError
sasaki-945 Nov 19, 2018
737cd7a
Fixed a bug, cannot be canceled if canceled before login
sasaki-945 Nov 19, 2018
d1ac332
Merge pull request #132 from sasaki-945/bug-fix
amosavian Nov 19, 2018
7c7763d
Merge pull request #134 from sasaki-945/issue#113
amosavian Nov 19, 2018
83eb97a
Merge pull request #135 from sasaki-945/master
amosavian Nov 19, 2018
b9c1729
Added FTP SSL/TLS session resumption/reuse support
sasaki-945 Nov 20, 2018
cb42552
Merge pull request #136 from sasaki-945/master
amosavian Nov 20, 2018
90706f1
Fixed bug: cannot be transferred file 4KB or less
sasaki-945 Dec 10, 2018
9384264
Merge pull request #139 from sasaki-945/master
amosavian Dec 16, 2018
abf68a6
Updated to Swift 5.0, Removed Swift 3 support
amosavian Apr 4, 2019
183382a
Implement Nextcloud thumbnails
skjiisa Aug 29, 2020
716988a
Make WebDAV thumbnail support check case insensitive
skjiisa Aug 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

22 changes: 10 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
language: objective-c
osx_image: xcode9
osx_image: xcode10.2
xcode_project: $PROJECTNAME.xcodeproj
env:
global:
Expand All @@ -8,21 +8,19 @@ env:
- IOS_FRAMEWORK_SCHEME="$PROJECTNAME iOS"
- MACOS_FRAMEWORK_SCHEME="$PROJECTNAME OSX"
- TVOS_FRAMEWORK_SCHEME="$PROJECTNAME tvOS"
- TEST_FRAMEWORK_SCHEME="$PROJECTNAMETests"
- IOS_SDK=iphonesimulator
- MACOS_SDK=macosx
- TVOS_SDK=appletvsimulator
matrix:
- DESTINATION="OS=11.0,name=iPad Pro (10.5-inch)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="YES"
- DESTINATION="OS=11.0,name=iPhone 8" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="YES" CARTHAGEDEPLOY="NO"
- DESTINATION="OS=11.0,name=iPhone 6" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"

- DESTINATION="OS=11.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
# - DESTINATION="OS=10.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"

- DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD="NO" CARTHAGEDEPLOY="NO"
- DESTINATION="OS=12.2,name=iPad Pro (10.5-inch)" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" CARTHAGEDEPLOY="YES"
- DESTINATION="OS=12.2,name=iPhone 8" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" POD="YES"
- DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK"
- DESTINATION="arch=x86_64" SCHEME="FilesProviderTests" SDK="$MACOS_SDK" RUN_TESTS="YES"
- DESTINATION="OS=12.2,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK"
before_install:
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-document --quiet
- gem install cocoapods --no-document --quiet
# - gem install xcpretty-travis-formatter

script:
Expand Down Expand Up @@ -78,4 +76,4 @@ deploy:
# repo: amosavian/$PROJECTNAME
repo: amosavian/FileProvider
tags: true
condition: "$CARTHAGEDEPLOY = YES"
condition: "$CARTHAGEDEPLOY = YES"
273 changes: 273 additions & 0 deletions Docs/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
![File Provider](fileprovider.png)

# Concepts and Design

## Protocols and base classes

Every provider class conforms to some of the protocols each defines which operations are doable by a particular provider.
This allows developers to work with any provider class and to use a simple downcast to
intended protocol via `as?` optional keyword and call intended method.

### FileProviderBasic

This protocols consists basic variables necessary for all providers and functions to query contents and status of provider.

`type` static property should return a string which is usually provider's name.
Value can be usedfor display purposes and to compare two different instances' type.

`baseURL` determines root url of provider instance.
Some providers doesn't map url to files thus this variable is set to nil. `url(of:)` default implementation
uses this url to create a url which points to specified path.

`dispatch_queue` and `operation_queue` are dispatch and operation queues used to have async operation.
As a rule of thumb, file operations are done in operation queue and querying are done by dispatch queue.
Some objects and classes like `NSFileCoordinator` uses OperationQueue for async operations.

`delegate` is a used to inform controller about operation status/progress to update UI.
Avoid calling delegate methods directly and use `delegateNotify()` method in your implementation instead.

`credential` property stores user and password necessary to access provider.
Local provider would ignore it.

If listing query is paginated `contentsOfDirectory()` and `searchFiles()` may return both truncated
list array and error in case 2nd page can't be retrieved.
Thus it's safe to check `error` first to ensure list is complete. Truncated result is usable until full list is retrieved.

`storageProperties()` returns `VolumeObject` see below for more information.

When implementing `searchFiles()`, check `fileObject.mapPredicate()` using `query.evaluate(with:)`.
You may use `query` parameter to create a search string if provider supports search functionality.

Practically, `searchFiles(path: path, recursive: false, query: NSPredicate(format: "TRUEPREDICATE"))` should be equal with `contentsOfDirectory()` method.
Consequently, if provider enlisting and search backend are same (e.g. iCloud, OneDrive or Google)
implement `contentsOfDirectory()` as a wrapper around `searchFiles()`,
otherwise implement'em independently for optimization reason.

Avoid `isReachable()` to check connectivity and reachability.
Instead do operation and allow it o fail if there is a connection problem.
It may be deprecated at any time.

`url(of:)` and `relativePathOf(url:)` have default implementation which build a url using `baseURL` property.
In case that `baseURL` is `nil`, it will wrap path inside a `URL` instance.
You may override them if more functionality is needed (e.g. OneDrive) or appending path to baseURL can't be mapped to file url directly.

### FileProviderBasicRemote

Adds a `session` and `cache` object for providers that need internet connection and `URLSession` object.
If your provider is a HTTP based api, subclass `HTTPFileProvider` class otherwise
(e.g. FTP or SMB) conform it to this protocol.

### FileProviderOperations

This protocol encapsulates methods for copying, moving, renaming, removing and downloading/uploading files.

If your provider is a subclass of `HTTPFileProvider`, you may implement
`request(for:, overwrite:, attributes:)` abstract method which handles default implementation for these methods.
In this case, you need to create a `URLRequest` object based on `operation` parameter,
usually done a switch case statement.
See [`WebDAVFileProvder`](Sources/WebDAVFileProvider.swift) and [`OneDriveFileProvider`](Sources/OneDriveFileProvider) classes to see an example.

### FileProviderReadWrite

This protocol declares three methods to read and write files.

You must care about memory when using these functions. If you must handle big data,
write it to a temporary file and use `copyItem(localFile:, to:)` or `copyItem(path:, toLocalURL:)` methods accordingly.

### FileProviderMonitor

This protocol allows developer to update UI when file list is changed.
It's not implemented for all providers and some providers like FTP and WebDAV don't support such functionality.

If you are implementing it for a HTTP-based provider,
use `longpoolSession` to create a monitor request to avoid expiring requests frequently.

Implementation details vary based on provider specifications.

### FileProvideUndoable

Implementing this protocol is a little hard as you must save operation inside `undoManager` for any operation.


### FileProviderSharing

`publicLink(to:, completionHandler:)` method allows user to share file with other people.
Not all providers support this functionality and implementation details vary based on provider specification.

### ExtendedFileProvider

This protocol provides a way to fetch files' thumbnail and metadata.
Providers which have endpoint to get meta data (like Dropbox) implements this protocol.
Due to extensive network overload of fetching thumbnail,
It's recommended to check file using `thumbnailOfFileSupported(path)` method
to find out either provider supports thumbnail generation for specified file or not.
These methods only check file extension as a indicator and won't check file using provider.
A `true` result does not indicate that the file really has a thumbnail or not.

Implementation of `thumbnailOfFile(path:, dimension:)` must provide a NSImage/UIImage with size
according to `dimension` parameter. If server supports requesting thumbnail with specified size,
implementation would pass requested dimension to server,
otherwise implementation must resize image using `ExtendedFileProvider.scaleDown(image:, toSize:)` method to resize image.

`ExtendedFileProvider.convertToImage(pdfURL:, page:)` and `ExtendedFileProvider.convertToImage(pdfPage:)` methods can convert pdf file into an image.
Please note `pdfURL` parameter must be a local file url.

`propertiesOfFile()` method will extract meta data of specified file and return it as a dictionary orders by `keys` parameter.
Keys may vary according to file type, e.g. EXIF data for an image or ID3 tags for a music file.

To extend thumbnail generation behavior for local file to types which are not supported by Apple platform,
you may change `LocalFileInformationGenerator` struct static properties.
Some methods in this struct are unimplemented to allow developer to use third-party libraries
to provide meta data and thumbnail for other types of file.

### FileProvider

This protocol does not define any method, but indicates that class conforms to `FileProviderBasic `,
`FileProviderOperations`, `FileProviderReadWrite` and `NSCopying` protocols.

### FileOperationType

This enum holds operation type and associated information like source and destination path.
Developer is exposed to this enum in delegate methods.
Internally it's extensively used to refactor operation methods and to store operation info in
related `URLSessionTask` inside `taskDescription` property.

As a associated enum, it can not be bridged to Objective-C.

### FileObject

`FileObject` class stores file properties in a dictionary with `URLResourceKey` as key type.
All other properties are computed variables and simply cast value to a strict swift type.

Provider will create and return instance of `FileObject` class or its descendants in `contentsOfDirectory()`, `attributesOfItem()` and `searchFiles()` methods.
Provider **must** set `name` and `path` properties.

`path`'s value can be a unix-style hierarchal path or other ways to point a file supported by server.
Some providers like Dropbox and OneDrive define accessing to file by id or revision.
As a convention, these alternative paths are structured like `type:identifier` e.g. `rev:abcd1234` or `id:abcd1234`.
Google only allows to address file with `id:abcd1234` and does not provide unix-style path.

- **Important:** Never rely on `path` last component to extract file name, instead use `name` property.
Providers like `Google` have only file id in path thus using `path.lastPathComponent` to display file name may lead to confusion and improper result.

### VolumeObject

`VolumeObject` class is identical to `FileObject` structurally but only uses `URLResourceKey`'s keys which begin with `volume`.
An implementation of provider must return this enumerated in `storageProperties()` with properties like total size and free space of storage.

There is not correspondent key in storage for `usage` property,
indeed it's calculated by subtracting available space from total space.

## Progress handling

Almost all methods return a `Progress` instance which encapsulates progress fraction and a way to cancel entire operation.
It's upon your provider's implementation to update progress `totalUnitCount` and `completedUnitCount` properties and assign a cancellation handler to Progress object.
Cancellation handler may call `Operation`'s or `URLSessionTask`'s `cancel()` method to interrupt operation.

A typical progress handling in this library is like this:

```swift
// totalUnitCount must be set to file size for downloading/uploading operation.
// totalUnitCount must be set to 1 for a simple remote file operation.
let progress = Progress(totalUnitCount: size)
// allow updating progress inside URLSession's delegate methods
progress.setUserInfoObject(operation, forKey: .fileProvderOperationTypeKey)
// kind must be set to .file for downloading/uploading operation.
progress.kind = .file
progress.setUserInfoObject(Progress.FileOperationKind.downloading, forKey: .fileOperationKindKey)
// progres.cancel() will call task.cancel() method.
progress.cancellationHandler = { [weak task] in
task?.cancel()
}
// Set .startingTimeKey to calculate estimated remaining time and speed in delegate.
progress.setUserInfoObject(Date(), forKey: .startingTimeKey)
```

Please note `.fileProvderOperationTypeKey` and `.startingTimeKey` are custom user info assigned to progress
to allow updating progress inside URLSession's delegate methods and calculating estimated remaining time and speed.
Your implementation must set these user info objects if you are using `SessionDelegate` object.

You may update cancellation handler if another task is added.

## Error handling

This library doesn't manipulate errors returned by Foundation methods and uses `URLError` and `CococaError` to report error as far as there is a corresponding defined error.
You can use `urlError(_ :, code:)` and `cocoaError(_:, code:)` convenience methods to create error object.

For HTTP providers, `FileProviderHTTPError` protocol defines a way to encapsulate HTTP status code and returned description by server.
You may declare a struct conforming to `FileProviderHTTPError` with an initializer to interpret server response.
`serverError(with:, path:, data:)` must be implemented in `HTTPFileProvider` subclasses and will be called by HTTP provider default implementation to digest error.

**NEVER** define a custom enum for errors. Instead use Foundation errors like `URLError` and `CococaError` as
they provide comprehensive localized description for error.
Alternatively use `FileProviderHTTPError` conforming struct for HTTP providers.

## Implementing HTTP-based Custom Provider

This library provide `HTTPFileProvider` abstract class to easily implement provider which connects to a cloud/server that
uses http protocol for connection.
That's almost all REST and web based providers like Dropbox, Box, Google Drive, etc.

`HTTPFileProvider` encapsulates much of downloading/uploading logic and provides `paginated` method
to allow enlisting/searching files in providers which return result in progressively. (e.g. Dropbox and OneDrive)

By subclassing `HTTPFileProvider` class, you must override half a dozen of methods, mainly querying methods.
Your implementation may cause a **crash** if you fail to override these methods.

### Methods and properties to override

`type` static property, which returns name of provider.

`init?(coder:)` decodes and initialize instance using `NSCoder`.
Your implementation must read `aDecoder` correspondent keys and initialize a new object using your provider's initilizer.

`copy(with:)` method must create a new instance and assign properties from source (`self`) to copied object.

`contentsOfDirectory()` and `searchFiles()` methods must send listing query to server and decode json/xml response into a `FileObject`.
Providers may subclass `FileObject` and implement an initializer to encapsulate decoding logic.
If server response is paginated, use `paginated()` method. See below and inline help to find how to use it.

`attributesOfItem()` must send file attribute fetching query to server and decode response into a `FileObject` or its descendants instance.

`storageProperties()` does querying account/cloud quota and encapsulates it into a `VolumeObject` instance.
You don't need to subclass `VolumeObject`.
If your server does not support such functionality, simply call completion handler with `nil` as result.

`request(for:, overwrite:, attributes:)` creates a `URLRequest` for requested operation.
It will be called by create, copy/move and remove functions.
You may set `httpMethod` and `httpBody` and header values of request regarding operation type and associated variables.

- **Important:** NEVER forget to call `urlrequest.setValue(authentication: credential, with:)` to set provider's credential
if server uses OAuth/OAuth2 authentication method.
You may need to set other http headers according to server specifications.

- **Important**: `copyItem(path:, toLocalURL:)` and `copyItem(localFile:, to:)` methods will call `request(for:)` method with
source/destination property set to a local file url, begins with `file://`.
You must handle these separately.
See `WebDAVProvider` [source](Sources/WebDAVFileProvider.swift) as an example.

`serverError(with:, path:, data:)` method will digest http status code and server response data to create an error conforming to `FileProviderHTTPError` protocol.

### Optional overridable methods

`isReachable()` default implementation tries to fetch storage properties and will return true if result is non-nil.
You may need to override this method if server does not support `storageProperties()` or there is a more optimized way to check reachability.

`copyItem(localFile:, to:)` and `writeContents(path:, contents:)` can be overrided if server requires upload session.
See `OneDriveProvider`'s [source](Sources/OneDriveProvider) to see how create and handle an upload session.

### Paginated enlisting

`paginated()` method defines an easy way to communicate to servers which list responses are paginated.
Here is method signature:

`pageHandler` closure gets server response as `Data`, decodes it and returns `FileObject` array or an error,
and if there is another sequel page, passes token of new page (a string tha can be a id or url) to `newToken`.
If there is no more sequel page, `newToken` must be nil.

This token will be delivered to `requestHandler` closure which returns a `URLRequest` according to token.
A nil token indicates it's the first page.
`completionHandler` is the closure which user passed to `contentsOfDirectory()` or `searchFiles()` methods.

`pageHandler` must update `progress` by adding the number of new files enlisted to `completedUnitCount` property.
This closure may filter results according to `query` parameter, using `query.evaluate(with:)`.
Loading