Skip to content

Support for multiple server regions

Compare
Choose a tag to compare
@tmpit tmpit released this 27 May 14:51
· 61 commits to master since this release

Migration instructions:

The API of the SDK has been slightly modernized and most of the methods and parameter names have been changed to comply with modern Swift syntax. Also some classes and structs have been removed from the public API. For details, please refer to the release notes below.

Clients that have let the SDK automatically manage the OAuth access token storage should only need to update method / property invocations and handle the new OAuth.User struct during authorization. Please refer to the changes to the PCloud and OAuth namespaces in the release notes below.

However, if you are manually managing the storage of the OAuth access token, instead of relying on the SDK, please expand the block below.

Read if you are manually managing the storage of the OAuth access token

One of the major changes to the API is the addition of the OAuth.User struct. Creating a PCloudClient from the PCloud namespace will now require that you pass a OAuth.User value. This will require some additional work for those of you that manually manage the storage of the OAuth access token, because you will need to convert that token to the OAuth.User value in order to continue using the SDK as before.
The OAuth.User struct is defined as follows:

public struct User: Codable, Equatable {
    public let id: UInt64
    public let token: String
    public let serverRegionId: UInt
    public let httpAPIHostName: String
}

For token you can use the access token.
For serverRegionId, use 1. This is the US server region id.
For httpAPIHostName use "api.pcloud.com". This is the same API host used by the SDK up until v3.
For id, use the user id you've acquired alongside the access token. If you haven't actually persisted the user id (although you really really should have), there is a temporary solution for you. As of v3.0.0, the SDK does not actually use the user id for anything apart a key for storing a OAuth.User value in the keychain. So for now you can use a placeholder value for an identifier. However, this may change in the future and it is strongly recommended that you obtain your user id via the PCloudAPI.UserInfo API method and persist it ASAP. Also, while you are using a placeholder identifier, you must not use OAuth to store your OAuth.User value.

Release notes:

Added:

  • Support for multiple server regions
  • Authentication via ASWebAuthenticationSession

Fixed:

  • Missing .nib file when attempting to authorize in macOS
  • Call.Command.Parameter implementation of Hashable

Public API changes:

Added:
  • APIServerRegion
Removed:
  • Atomic
  • Keychain
  • Lock
  • Result (the SDK is now using Swift.Result)
  • HTTPMethod
  • User.Metadata conformance to Equatable and Hashable
  • File.Metadata conformance to Equatable and Hashable
  • File.Media conformance to Equatable
  • FileLink.Metadata conformance to Equatable and Hashable
  • Call.Request conformance to Equatable
  • Upload.Request.Body conformance to Equatable
  • Upload.Request conformance to Equatable
Updated:
PCloud

Mainly you will need to handle the new User struct in authorization callbacks. Also, if you were using the createClient() function, you will now need to pass a User there.

- static func authorize(controller: UIViewController, _ completionBlock: @escaping (OAuth.Result) -> Void)
+ static func authorize(with controller: UIViewController, _ completionBlock: @escaping (OAuth.Result) -> Void)

- static func authorize(controller: NSViewController, _ completionBlock: @escaping (OAuth.Result) -> Void)
+ static func authorize(with controller: NSViewController, _ completionBlock: @escaping (OAuth.Result) -> Void)

- static func setup(appKey: String)
+ static func setUp(withAppKey appKey: String)

- static func initializeClient(accessToken: String)
+ static func initializeSharedClient(with user: OAuth.User)

- static func clearClient()
+ static func clearSharedClient()

- static func createClient(accessToken: String)
+ static func createClient(with user: OAuth.User)

- static func authorize(view: OAuthAuthorizationFlowView, completionBlock: @escaping (OAuth.Result) -> Void)
+ static func authorize(with view: OAuthAuthorizationFlowView, completionBlock: @escaping (OAuth.Result) -> Void)
OAuth

Mainly you will need to handle the new User struct in authorization callbacks. Other than that, if you were using any of the methods manipulating the token in the keychain, you will need to switch to their direct replacements that work with the User struct. The getAnyUser() and getUser(withId:) methods will properly migrate the token in the keychain if there is one the first time you call them so you will not need to reauthenticate.

+ struct User

- Result.success(token: String, userId: UInt64)
+ Result.success(User)

+ static func performAuthorizationFlow(with anchor: ASPresentationAnchor, appKey: String, completionBlock: @escaping (Result) -> Void)
		
- static func performAuthorizationFlow(view: OAuthAuthorizationFlowView, appKey: String, storeToken: @escaping (String, UInt64) -> Void, _ completionBlock: @escaping (Result) -> Void)
+ static func performAuthorizationFlow(with view: OAuthAuthorizationFlowView, appKey: String, completionBlock: @escaping (Result) -> Void)

- static func getAnyToken() -> String?
+ static func getAnyUser() -> User?

- static func getToken(forUser userId: UInt64) -> String?
+ static func getUser(withId id: UInt64) -> User?

- static func storeToken(_ token: String, forUser userId: UInt64)
+ static func store(_ user: User)

- static func deleteToken(forUser userId: UInt64)
+ static func deleteUser(withId id: UInt64)

- static func deleteAllTokens()
+ static func deleteAllUsers()
CallOperation
- func addCompletionBlock(queue: DispatchQueue?, _ block: @escaping (Call.Response) -> Void) -> Self
+ func addCompletionBlock(with queue: DispatchQueue?, _ block: @escaping (Call.Response) -> Void) -> Self
UploadOperation
- func addProgressBlock(queue: DispatchQueue?, _ block: @escaping (Int64, Int64) -> Void) -> Self
+ func addProgressBlock(with queue: DispatchQueue?, _ block: @escaping (Int64, Int64) -> Void) -> Self

- func addCompletionBlock(queue: DispatchQueue?, _ block: @escaping (Upload.Response) -> Void) -> Self
+ func addCompletionBlock(with queue: DispatchQueue?, _ block: @escaping (Upload.Response) -> Void) -> Self
DownloadOperation
- func addProgressBlock(queue: DispatchQueue?, _ block: @escaping (Int64, Int64) -> Void) -> Self
+ func addProgressBlock(with queue: DispatchQueue?, _ block: @escaping (Int64, Int64) -> Void) -> Self

- func addCompletionBlock(queue: DispatchQueue?, _ block: @escaping (Download.Response) -> Void) -> Self
+ func addCompletionBlock(with queue: DispatchQueue?, _ block: @escaping (Download.Response) -> Void) -> Self
URLSessionBasedNetworkOperation

The API of URLSessionBasedNetworkOperation is no longer public with the exception of public protocol conformances.

URLSessionBasedNetworkOperationUtilities
- static func createCallOperationBuilder(scheme: Scheme, session: URLSession, delegate: URLSessionEventHub) -> (Call.Request) -> CallOperation
+ static func createCallOperationBuilder(with scheme: URLScheme, session: URLSession, delegate: URLSessionEventHub) -> (Call.Request) -> CallOperation

- static func createUploadOperationBuilder(scheme: Scheme, session: URLSession, delegate: URLSessionEventHub) -> (Upload.Request) -> UploadOperation
+ static func createUploadOperationBuilder(with scheme: URLScheme, session: URLSession, delegate: URLSessionEventHub) -> (Upload.Request) -> UploadOperation

- static func createDownloadOperationBuilder(session: URLSession, delegate: URLSessionEventHub) -> (Download.Request) -> DownloadOperation
+ static func createDownloadOperationBuilder(with session: URLSession, delegate: URLSessionEventHub) -> (Download.Request) -> DownloadOperation
URLSessionTaskBuilder
- static func createDataTask(request: Call.Request, session: URLSession, scheme: Scheme) -> URLSessionDataTask
+ static func createDataTask(with request: Call.Request, session: URLSession, scheme: URLScheme) -> URLSessionDataTask

- static func createUploadTask(request: Upload.Request, session: URLSession, scheme: Scheme) -> URLSessionUploadTask
+ static func createUploadTask(with request: Upload.Request, session: URLSession, scheme: URLScheme) -> URLSessionUploadTask

- static func createDownloadTask(request: Download.Request, session: URLSession) -> URLSessionDownloadTask
+ static func createDownloadTask(with request: Download.Request, session: URLSession) -> URLSessionDownloadTask

- static func buildHTTPHeaderFields(cookiesDictionary: [String: String], resourceAddress: URL) -> [String: String]
- static func encode(_ value: String) -> String
- static func encode(_ value: Bool) -> String
- static func encode(_ value: UInt64) -> String
- static func rawQueryComponent(from parameter: Call.Command.Parameter) -> String
- static func percentEncodedQueryComponent(from parameter: Call.Command.Parameter) -> String
- static func query(from parameters: [Call.Command.Parameter], addingPercentEncoding encode: Bool) -> String
- static func url(scheme: String, host: String, commandName: String, query: String? = nil) -> URL
- static func buildURL(withScheme scheme: String, host: String, commandName: String, percentEncodedQuery: String? = nil) -> URL
PCloudAPICallTaskBuilder
- static func createTask(resourceAddress: URL, downloadTag: String? = nil, timeoutInterval: TimeInterval? = nil, destination: @escaping (URL) throws -> URL) -> DownloadTask
+ static func createTask(with resourceAddress: URL, downloadTag: String? = nil, timeoutInterval: TimeInterval? = nil, destination: @escaping (URL) throws -> URL) -> DownloadTask
CharacterSet
- static func urlQueryParameterAllowedCharacterSetRFC3986() -> CharacterSet
- Scheme
+ URLScheme