Skip to content

Commit d27c996

Browse files
committed
Release candidate for 1.5.x
1 parent 0c5cfa6 commit d27c996

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+2041
-326
lines changed

Package.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ let package = Package(
1313
products: [
1414
.library(
1515
name: "Appwrite",
16-
targets: ["Appwrite", "AppwriteModels", "JSONCodable"]
16+
targets: [
17+
"Appwrite",
18+
"AppwriteEnums",
19+
"AppwriteModels",
20+
"JSONCodable"
21+
]
1722
),
1823
],
1924
dependencies: [
2025
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"),
21-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0")
26+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"),
2227
],
2328
targets: [
2429
.target(
@@ -27,6 +32,7 @@ let package = Package(
2732
.product(name: "AsyncHTTPClient", package: "async-http-client"),
2833
.product(name: "NIOWebSocket", package: "swift-nio"),
2934
"AppwriteModels",
35+
"AppwriteEnums",
3036
"JSONCodable"
3137
]
3238
),
@@ -36,6 +42,9 @@ let package = Package(
3642
"JSONCodable"
3743
]
3844
),
45+
.target(
46+
name: "AppwriteEnums"
47+
),
3948
.target(
4049
name: "JSONCodable"
4150
),

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
88
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)
99

10-
**This SDK is compatible with Appwrite server version 1.4.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
10+
**This SDK is compatible with Appwrite server version 1.5.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-apple/releases).**
1111

1212
Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Apple SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)
1313

@@ -31,7 +31,7 @@ Add the package to your `Package.swift` dependencies:
3131

3232
```swift
3333
dependencies: [
34-
.package(url: "[email protected]:appwrite/sdk-for-apple.git", from: "4.0.2"),
34+
.package(url: "[email protected]:appwrite/sdk-for-apple.git", from: "5.0.0-rc.2"),
3535
],
3636
```
3737

Sources/Appwrite/Client.swift

Lines changed: 77 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import Foundation
66
import AsyncHTTPClient
77
@_exported import AppwriteModels
88

9+
typealias CookieListener = (_ existing: [String], _ new: [String]) -> Void
10+
911
let DASHDASH = "--"
1012
let CRLF = "\r\n"
1113

@@ -14,32 +16,32 @@ open class Client {
1416
// MARK: Properties
1517
public static var chunkSize = 5 * 1024 * 1024 // 5MB
1618

17-
open var endPoint = "https://HOSTNAME/v1"
19+
open var endPoint = "https://cloud.appwrite.io/v1"
1820

1921
open var endPointRealtime: String? = nil
2022

2123
open var headers: [String: String] = [
22-
"content-type": "",
24+
"content-type": "application/json",
2325
"x-sdk-name": "Apple",
2426
"x-sdk-platform": "client",
2527
"x-sdk-language": "apple",
26-
"x-sdk-version": "4.0.2",
27-
"X-Appwrite-Response-Format": "1.4.0"
28+
"x-sdk-version": "5.0.0-rc.2",
29+
"x-appwrite-response-format": "1.4.0"
2830
]
2931

30-
open var config: [String: String] = [:]
32+
internal var config: [String: String] = [:]
33+
34+
internal var selfSigned: Bool = false
3135

32-
open var selfSigned: Bool = false
36+
internal var http: HTTPClient
3337

34-
open var http: HTTPClient
38+
internal static var cookieListener: CookieListener? = nil
3539

36-
private static let boundaryChars =
37-
"abcdefghijklmnopqrstuvwxyz1234567890"
40+
private static let boundaryChars = "abcdefghijklmnopqrstuvwxyz1234567890"
3841

3942
private static let boundary = randomBoundary()
4043

41-
private static var eventLoopGroupProvider =
42-
HTTPClient.EventLoopGroupProvider.createNew
44+
private static var eventLoopGroupProvider = HTTPClient.EventLoopGroupProvider.singleton
4345

4446
// MARK: Methods
4547

@@ -80,7 +82,6 @@ open class Client {
8082
decompression: .enabled(limit: .none)
8183
)
8284
)
83-
8485
}
8586

8687
deinit {
@@ -134,6 +135,21 @@ open class Client {
134135
return self
135136
}
136137

138+
///
139+
/// Set Session
140+
///
141+
/// The user session to authenticate with
142+
///
143+
/// @param String value
144+
///
145+
/// @return Client
146+
///
147+
open func setSession(_ value: String) -> Client {
148+
config["session"] = value
149+
_ = addHeader(key: "X-Appwrite-Session", value: value)
150+
return self
151+
}
152+
137153

138154
///
139155
/// Set self signed
@@ -295,64 +311,56 @@ open class Client {
295311
withSink bufferSink: ((ByteBuffer) -> Void)? = nil,
296312
converter: ((Any) -> T)? = nil
297313
) async throws -> T {
298-
func complete(with response: HTTPClientResponse) async throws -> T {
299-
switch response.status.code {
300-
case 0..<400:
301-
if response.headers["Set-Cookie"].count > 0 {
302-
UserDefaults.standard.set(
303-
response.headers["Set-Cookie"],
304-
forKey: URL(string: request.url)!.host! + "-cookies"
305-
)
306-
}
307-
switch T.self {
308-
case is Bool.Type:
309-
return true as! T
310-
case is ByteBuffer.Type:
311-
return try await response.body.collect(upTo: Int.max) as! T
312-
default:
313-
let data = try await response.body.collect(upTo: Int.max)
314-
if data.readableBytes == 0 {
315-
return true as! T
316-
}
317-
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
314+
let response = try await http.execute(
315+
request,
316+
timeout: .seconds(30)
317+
)
318318

319-
return converter?(dict!) ?? dict! as! T
320-
}
319+
switch response.status.code {
320+
case 0..<400:
321+
if response.headers["Set-Cookie"].count > 0 {
322+
let domain = URL(string: request.url)!.host!
323+
let existing = UserDefaults.standard.stringArray(forKey: domain)
324+
let new = response.headers["Set-Cookie"]
325+
326+
Client.cookieListener?(existing ?? [], new)
327+
328+
UserDefaults.standard.set(new, forKey: domain)
329+
}
330+
switch T.self {
331+
case is Bool.Type:
332+
return true as! T
333+
case is ByteBuffer.Type:
334+
return try await response.body.collect(upTo: Int.max) as! T
321335
default:
322-
var message = ""
323-
var data = try await response.body.collect(upTo: Int.max)
324-
var type = ""
325-
326-
do {
327-
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
328-
329-
message = dict?["message"] as? String ?? response.status.reasonPhrase
330-
type = dict?["type"] as? String ?? ""
331-
} catch {
332-
message = data.readString(length: data.readableBytes)!
336+
let data = try await response.body.collect(upTo: Int.max)
337+
if data.readableBytes == 0 {
338+
return true as! T
333339
}
340+
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
334341

335-
throw AppwriteError(
336-
message: message,
337-
code: Int(response.status.code),
338-
type: type
339-
)
342+
return converter?(dict!) ?? dict! as! T
343+
}
344+
default:
345+
var message = ""
346+
var data = try await response.body.collect(upTo: Int.max)
347+
var type = ""
348+
349+
do {
350+
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
351+
352+
message = dict?["message"] as? String ?? response.status.reasonPhrase
353+
type = dict?["type"] as? String ?? ""
354+
} catch {
355+
message = data.readString(length: data.readableBytes)!
340356
}
341-
}
342357

343-
if bufferSink == nil {
344-
let response = try await http.execute(
345-
request,
346-
timeout: .seconds(30)
358+
throw AppwriteError(
359+
message: message,
360+
code: Int(response.status.code),
361+
type: type
347362
)
348-
return try await complete(with: response)
349363
}
350-
351-
let response = try await http.execute(
352-
request,
353-
timeout: .seconds(30)
354-
)
355-
return try await complete(with: response)
356364
}
357365

358366
func chunkedUpload<T>(
@@ -411,7 +419,7 @@ open class Client {
411419
while offset < size {
412420
let slice = (input.data as! ByteBuffer).getSlice(at: offset, length: Client.chunkSize)
413421
?? (input.data as! ByteBuffer).getSlice(at: offset, length: Int(size - offset))
414-
422+
415423
params[paramName] = InputFile.fromBuffer(slice!, filename: input.filename, mimeType: input.mimeType)
416424
headers["content-range"] = "bytes \(offset)-\(min((offset + Client.chunkSize) - 1, size - 1))/\(size)"
417425

@@ -466,7 +474,12 @@ open class Client {
466474
|| param is [Bool: Any] {
467475
encodedParams[key] = param
468476
} else {
469-
encodedParams[key] = try! (param as! Encodable).toJson()
477+
let value = try! (param as! Encodable).toJson()
478+
479+
let range = value.index(value.startIndex, offsetBy: 1)..<value.index(value.endIndex, offsetBy: -1)
480+
let substring = value[range]
481+
482+
encodedParams[key] = substring
470483
}
471484
}
472485

@@ -603,24 +616,3 @@ extension Client {
603616
return device
604617
}
605618
}
606-
607-
extension Client {
608-
609-
public enum HTTPStatus: Int {
610-
case unknown = -1
611-
case ok = 200
612-
case created = 201
613-
case accepted = 202
614-
case movedPermanently = 301
615-
case found = 302
616-
case badRequest = 400
617-
case notAuthorized = 401
618-
case paymentRequired = 402
619-
case forbidden = 403
620-
case notFound = 404
621-
case methodNotAllowed = 405
622-
case notAcceptable = 406
623-
case internalServerError = 500
624-
case notImplemented = 501
625-
}
626-
}

Sources/Appwrite/Extensions/HTTPClientRequest+Cookies.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extension HTTPClientRequest {
1717

1818
extension HTTPHeaders {
1919
public mutating func addDomainCookies(for domain: String) {
20-
guard let cookies = UserDefaults.standard.stringArray(forKey: "\(domain)-cookies") else {
20+
guard let cookies = UserDefaults.standard.stringArray(forKey: domain) else {
2121
return
2222
}
2323
for cookie in cookies {

Sources/Appwrite/OAuth/WebAuthComponent.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,12 @@ public class WebAuthComponent {
9292
cookie += "; secure"
9393
}
9494

95-
UserDefaults.standard.set([cookie], forKey: "\(domain)-cookies")
95+
let existing = UserDefaults.standard.stringArray(forKey: domain)
96+
let new = [cookie]
97+
98+
Client.cookieListener?(existing ?? [], new)
99+
100+
UserDefaults.standard.set(new, forKey: domain)
96101

97102
WebAuthComponent.onCallback(
98103
scheme: components.scheme!,

Sources/Appwrite/OS.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#if canImport(Darwin)
2+
import Foundation
3+
import UserNotifications
4+
5+
#if os(iOS) || os(tvOS)
6+
import UIKit
7+
public typealias Application = UIApplication
8+
#elseif os(macOS)
9+
import AppKit
10+
public typealias Application = NSApplication
11+
#elseif os(watchOS)
12+
import WatchKit
13+
public typealias Application = WKApplication
14+
#endif
15+
16+
public enum OSPermission {
17+
case notifications
18+
}
19+
20+
public class OS {
21+
public static func requestPermission(
22+
_ application: Application,
23+
_ permission: OSPermission,
24+
onGranted: @escaping () -> Void = {},
25+
onDenied: @escaping () -> Void = {}
26+
) {
27+
switch(permission) {
28+
case .notifications:
29+
requestNotificationPermission(
30+
application,
31+
onGranted: onGranted,
32+
onDenied: onDenied
33+
)
34+
}
35+
}
36+
37+
private static func requestNotificationPermission(
38+
_ application: Application,
39+
onGranted: @escaping () -> Void = {},
40+
onDenied: @escaping () -> Void = {}
41+
) {
42+
let options: UNAuthorizationOptions = [.alert, .badge, .sound]
43+
44+
UNUserNotificationCenter.current().requestAuthorization(
45+
options: options,
46+
completionHandler: { granted, error in
47+
DispatchQueue.main.async {
48+
if (granted) {
49+
onGranted()
50+
application.registerForRemoteNotifications()
51+
}
52+
else {
53+
onDenied()
54+
}
55+
}
56+
}
57+
)
58+
}
59+
}
60+
#endif

0 commit comments

Comments
 (0)