@@ -5,46 +5,67 @@ import {{.Path}};
55
66{{range .Services}}
77class {{.ClassName}}: @unchecked Sendable {
8- private let httpClient: HTTPClient
9- let hostname: String
10- var token: String
11- let apiKey: String
8+ private let httpClient: HTTPClient
9+ let hostname: String
10+ var token: String
11+ let apiKey: String
1212 let syncQueue = DispatchQueue(label: "{{.ClassName}}", qos: .userInitiated)
13- let pathPrefix: String = "/{{.Package}}.{{.Name}}/"
14- init(httpClient: HTTPClient, apiKey: String, hostname: String, token: String) {
13+ let pathPrefix: String = "/{{.Package}}.{{.Name}}/"
14+ var httpConfig = HTTPConfig.default //TODO: move this
15+
16+ init(httpClient: HTTPClient, apiKey: String, hostname: String, token: String) {
1517 self.httpClient = httpClient
16- self.hostname = hostname
17- self.token = token
18+ self.hostname = hostname
19+ self.token = token
1820 self.apiKey = apiKey
19- }
21+ }
2022 {{range .Methods}}
21- func {{.Name}}({{.InputArg}}: {{.InputType}}) async throws -> {{.OutputType}} {
23+ func {{.Name}}({{.InputArg}}: {{.InputType}}) async throws -> {{.OutputType}} {
2224 return try await execute(request: {{.InputArg}}, path: "{{.Path}}")
23- }
25+ }
2426 {{end}}
2527 func update(userToken: String) {
2628 syncQueue.async { [weak self] in
2729 self?.token = userToken
2830 }
2931 }
3032
31- private func execute<Request: ProtoModel, Response: ProtoModel >(request: Request, path: String) async throws -> Response {
33+ private func execute<Request: ProtoModel, Response: ProtoModelResponse >(request: Request, path: String, retries: Int = 0 ) async throws -> Response {
3234 let requestData = try request.serializedData()
33- var request = try makeRequest(for: path)
34- request.httpBody = requestData
35- let responseData = try await httpClient.execute(request: request)
36- let response = try Response.init(serializedData: responseData)
35+ var urlRequest = try makeRequest(for: path)
36+ urlRequest.httpBody = requestData
37+ let responseData = try await httpClient.execute(request: urlRequest)
38+ let response = try Response.init(serializedBytes: responseData)
39+ if response.hasError {
40+ if response.error.shouldRetry && retries < httpConfig.maxRetries {
41+ let delay = httpConfig.retryStrategy.getDelayAfterTheFailure()
42+ let delayNanoseconds = UInt64(delay * 1_000_000_000)
43+ log.debug("Delaying retry for \(delay) seconds")
44+ try await Task.sleep(nanoseconds: delayNanoseconds)
45+ log.debug("Retrying request for path \(path)")
46+ return try await execute(request: request, path: path, retries: retries + 1)
47+ } else {
48+ httpConfig.retryStrategy.resetConsecutiveFailures()
49+ throw NSError(
50+ domain: "stream",
51+ code: response.error.code.rawValue,
52+ userInfo: ["message": response.error.message]
53+ )
54+ }
55+ }
56+ httpConfig.retryStrategy.resetConsecutiveFailures()
3757 return response
3858 }
3959
4060 private func makeRequest(for path: String) throws -> URLRequest {
41- let url = hostname + pathPrefix + path + "?api_key=\(apiKey)"
61+ let url = hostname + pathPrefix + path + "?api_key=\(apiKey)"
4262 guard let url = URL(string: url) else {
4363 throw NSError(domain: "stream", code: 123)
4464 }
4565 var request = URLRequest(url: url)
4666 request.setValue("application/protobuf", forHTTPHeaderField: "Content-Type")
4767 request.setValue("Bearer \(token)", forHTTPHeaderField: "authorization")
68+ request.setValue(SystemEnvironment.sdkIdentifier, forHTTPHeaderField: "X-Stream-Client")
4869 request.httpMethod = "POST"
4970 return request
5071 }
0 commit comments