Skip to content

Commit 802d449

Browse files
authored
fix: update Swift protobuf codegen to match SDK runtime (#2052)
2 parents f1b2fe2 + 724d7f4 commit 802d449

3 files changed

Lines changed: 45 additions & 18 deletions

File tree

‎install.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ if [[ -z $DISABLE_SWIFT ]]; then
6767
if command -v swift &> /dev/null
6868
then
6969
echo "Installing swift protoc plugin"
70-
git clone --depth 1 --branch 1.22.0 https://github.com/apple/swift-protobuf $PROTOC_DIR/.swift-protobuf
70+
git clone --depth 1 --branch "${PROTO_SWIFT_VERSION}" https://github.com/apple/swift-protobuf $PROTOC_DIR/.swift-protobuf
7171
(cd $PROTOC_DIR/.swift-protobuf && swift build -c release)
7272
ln -s $PROTOC_DIR/.swift-protobuf/.build/release/protoc-gen-swift $PROTOC_DIR/bin/protoc-gen-swift
7373
else

‎tools/protoc-gen-swift-twirp/generator/template.goswift‎

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,67 @@ import {{.Path}};
55

66
{{range .Services}}
77
class {{.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
}

‎versions.sh‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ export PROTO_TWIRP_VERSION=v8.1.2
1212
export PROTO_GO_VERSION=v1.28.1
1313
export PROTO_VTPROTO_VERSION=v0.3.0
1414
export PROTO_LINT_VERSION=v0.39.0
15+
# Must match the SwiftProtobuf runtime version that the consuming Swift SDKs
16+
# link against (see stream-video-swift Package.swift). Generating with an older
17+
# protoc-gen-swift emits code that trips Swift 6 concurrency checking
18+
# (`static var allCases`, non-Sendable `_StorageClass`) and deprecated APIs
19+
# (`init(serializedData:)`).
20+
export PROTO_SWIFT_VERSION=1.38.1

0 commit comments

Comments
 (0)