@@ -6,6 +6,8 @@ import Foundation
66import AsyncHTTPClient
77@_exported import AppwriteModels
88
9+ typealias CookieListener = ( _ existing: [ String ] , _ new: [ String ] ) -> Void
10+
911let DASHDASH = " -- "
1012let CRLF = " \r \n "
1113
@@ -19,34 +21,35 @@ open class Client {
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 " : " Swift " ,
2426 " x-sdk-platform " : " server " ,
2527 " x-sdk-language " : " swift " ,
26- " x-sdk-version " : " 4.1.0 " ,
27- " X-Appwrite-Response-Format " : " 1.4.0 "
28+ " x-sdk-version " : " 5.0.0-rc.1 " ,
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
4648 public init ( ) {
4749 http = Client . createHTTP ( )
4850 addUserAgentHeader ( )
4951 addOriginHeader ( )
52+ NotificationHandler . shared. client = self
5053 }
5154
5255 private static func createHTTP(
@@ -149,6 +152,51 @@ open class Client {
149152 return self
150153 }
151154
155+ ///
156+ /// Set Session
157+ ///
158+ /// The user session to authenticate with
159+ ///
160+ /// @param String value
161+ ///
162+ /// @return Client
163+ ///
164+ open func setSession( _ value: String ) -> Client {
165+ config [ " session " ] = value
166+ _ = addHeader ( key: " X-Appwrite-Session " , value: value)
167+ return self
168+ }
169+
170+ ///
171+ /// Set ForwardedFor
172+ ///
173+ /// The IP address of the client that made the request
174+ ///
175+ /// @param String value
176+ ///
177+ /// @return Client
178+ ///
179+ open func setForwardedFor( _ value: String ) -> Client {
180+ config [ " forwardedfor " ] = value
181+ _ = addHeader ( key: " X-Forwarded-For " , value: value)
182+ return self
183+ }
184+
185+ ///
186+ /// Set ForwardedUserAgent
187+ ///
188+ /// The user agent string of the client that made the request
189+ ///
190+ /// @param String value
191+ ///
192+ /// @return Client
193+ ///
194+ open func setForwardedUserAgent( _ value: String ) -> Client {
195+ config [ " forwardeduseragent " ] = value
196+ _ = addHeader ( key: " X-Forwarded-User-Agent " , value: value)
197+ return self
198+ }
199+
152200
153201 ///
154202 /// Set self signed
@@ -196,6 +244,19 @@ open class Client {
196244 return self
197245 }
198246
247+ ///
248+ /// Set push provider ID.
249+ ///
250+ /// @param String endpoint
251+ ///
252+ /// @return this
253+ ///
254+ open func setPushProviderId( _ providerId: String ) -> Client {
255+ NotificationHandler . shared. providerId = providerId
256+
257+ return self
258+ }
259+
199260 ///
200261 /// Add header
201262 ///
@@ -310,64 +371,56 @@ open class Client {
310371 withSink bufferSink: ( ( ByteBuffer ) -> Void ) ? = nil ,
311372 converter: ( ( Any ) -> T ) ? = nil
312373 ) async throws -> T {
313- func complete( with response: HTTPClientResponse ) async throws -> T {
314- switch response. status. code {
315- case 0 ..< 400 :
316- if response. headers [ " Set-Cookie " ] . count > 0 {
317- UserDefaults . standard. set (
318- response. headers [ " Set-Cookie " ] ,
319- forKey: URL ( string: request. url) !. host! + " -cookies "
320- )
321- }
322- switch T . self {
323- case is Bool . Type :
324- return true as! T
325- case is ByteBuffer . Type :
326- return try await response. body. collect ( upTo: Int . max) as! T
327- default :
328- let data = try await response. body. collect ( upTo: Int . max)
329- if data. readableBytes == 0 {
330- return true as! T
331- }
332- let dict = try JSONSerialization . jsonObject ( with: data) as? [ String : Any ]
374+ let response = try await http. execute (
375+ request,
376+ timeout: . seconds( 30 )
377+ )
333378
334- return converter ? ( dict!) ?? dict! as! T
335- }
379+ switch response. status. code {
380+ case 0 ..< 400 :
381+ if response. headers [ " Set-Cookie " ] . count > 0 {
382+ let domain = URL ( string: request. url) !. host!
383+ let existing = UserDefaults . standard. stringArray ( forKey: domain)
384+ let new = response. headers [ " Set-Cookie " ]
385+
386+ Client . cookieListener ? ( existing ?? [ ] , new)
387+
388+ UserDefaults . standard. set ( new, forKey: domain)
389+ }
390+ switch T . self {
391+ case is Bool . Type :
392+ return true as! T
393+ case is ByteBuffer . Type :
394+ return try await response. body. collect ( upTo: Int . max) as! T
336395 default :
337- var message = " "
338- var data = try await response. body. collect ( upTo: Int . max)
339- var type = " "
340-
341- do {
342- let dict = try JSONSerialization . jsonObject ( with: data) as? [ String : Any ]
343-
344- message = dict ? [ " message " ] as? String ?? response. status. reasonPhrase
345- type = dict ? [ " type " ] as? String ?? " "
346- } catch {
347- message = data. readString ( length: data. readableBytes) !
396+ let data = try await response. body. collect ( upTo: Int . max)
397+ if data. readableBytes == 0 {
398+ return true as! T
348399 }
400+ let dict = try JSONSerialization . jsonObject ( with: data) as? [ String : Any ]
349401
350- throw AppwriteError (
351- message: message,
352- code: Int ( response. status. code) ,
353- type: type
354- )
402+ return converter ? ( dict!) ?? dict! as! T
355403 }
356- }
404+ default :
405+ var message = " "
406+ var data = try await response. body. collect ( upTo: Int . max)
407+ var type = " "
357408
358- if bufferSink == nil {
359- let response = try await http. execute (
360- request,
361- timeout: . seconds( 30 )
409+ do {
410+ let dict = try JSONSerialization . jsonObject ( with: data) as? [ String : Any ]
411+
412+ message = dict ? [ " message " ] as? String ?? response. status. reasonPhrase
413+ type = dict ? [ " type " ] as? String ?? " "
414+ } catch {
415+ message = data. readString ( length: data. readableBytes) !
416+ }
417+
418+ throw AppwriteError (
419+ message: message,
420+ code: Int ( response. status. code) ,
421+ type: type
362422 )
363- return try await complete ( with: response)
364423 }
365-
366- let response = try await http. execute (
367- request,
368- timeout: . seconds( 30 )
369- )
370- return try await complete ( with: response)
371424 }
372425
373426 func chunkedUpload< T> (
@@ -426,7 +479,7 @@ open class Client {
426479 while offset < size {
427480 let slice = ( input. data as! ByteBuffer ) . getSlice ( at: offset, length: Client . chunkSize)
428481 ?? ( input. data as! ByteBuffer ) . getSlice ( at: offset, length: Int ( size - offset) )
429-
482+
430483 params [ paramName] = InputFile . fromBuffer ( slice!, filename: input. filename, mimeType: input. mimeType)
431484 headers [ " content-range " ] = " bytes \( offset) - \( min ( ( offset + Client. chunkSize) - 1 , size - 1 ) ) / \( size) "
432485
@@ -481,7 +534,12 @@ open class Client {
481534 || param is [ Bool : Any ] {
482535 encodedParams [ key] = param
483536 } else {
484- encodedParams [ key] = try ! ( param as! Encodable ) . toJson ( )
537+ let value = try ! ( param as! Encodable ) . toJson ( )
538+
539+ let range = value. index ( value. startIndex, offsetBy: 1 ) ..< value. index ( value. endIndex, offsetBy: - 1 )
540+ let substring = value [ range]
541+
542+ encodedParams [ key] = substring
485543 }
486544 }
487545
@@ -618,24 +676,3 @@ extension Client {
618676 return device
619677 }
620678}
621-
622- extension Client {
623-
624- public enum HTTPStatus : Int {
625- case unknown = - 1
626- case ok = 200
627- case created = 201
628- case accepted = 202
629- case movedPermanently = 301
630- case found = 302
631- case badRequest = 400
632- case notAuthorized = 401
633- case paymentRequired = 402
634- case forbidden = 403
635- case notFound = 404
636- case methodNotAllowed = 405
637- case notAcceptable = 406
638- case internalServerError = 500
639- case notImplemented = 501
640- }
641- }
0 commit comments