Skip to content

Commit d4ef1d7

Browse files
committed
Extract AsposeBarcodeCloudClient nested types into dedicated files
1 parent a1f1a0e commit d4ef1d7

4 files changed

Lines changed: 207 additions & 198 deletions

File tree

Sources/AsposeBarcodeCloud/AsposeBarcodeCloudClient.swift

Lines changed: 0 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,6 @@ import Foundation
33
import FoundationNetworking
44
#endif
55

6-
public enum AsposeBarcodeCloudClientError: Error, CustomStringConvertible, @unchecked Sendable {
7-
case missingCredentials
8-
case invalidTokenURL(String)
9-
case invalidTokenResponse
10-
case tokenRequestFailed(statusCode: Int, body: String?)
11-
case transportError(Error)
12-
13-
public var description: String {
14-
switch self {
15-
case .missingCredentials:
16-
return "Access token or clientId/clientSecret are required"
17-
case let .invalidTokenURL(url):
18-
return "Invalid token URL: \(url)"
19-
case .invalidTokenResponse:
20-
return "Token response does not contain access_token"
21-
case let .tokenRequestFailed(statusCode, body):
22-
if let body = body, !body.isEmpty {
23-
return "Token request failed with status \(statusCode): \(body)"
24-
}
25-
return "Token request failed with status \(statusCode)"
26-
case let .transportError(error):
27-
return error.localizedDescription
28-
}
29-
}
30-
}
31-
32-
public final class AsposeBarcodeCloudConfiguration: @unchecked Sendable {
33-
public static let defaultHost = "https://api.aspose.cloud/v4.0"
34-
public static let defaultTokenURL = "https://id.aspose.cloud/connect/token"
35-
public static let defaultSdkName = "swift sdk"
36-
public static let defaultSdkVersion = "26.4.0"
37-
38-
public var host: String
39-
public var tokenURL: String
40-
public var accessToken: String?
41-
public var clientId: String?
42-
public var clientSecret: String?
43-
public var sdkName: String
44-
public var sdkVersion: String
45-
public var timeoutInterval: TimeInterval
46-
47-
public init(
48-
accessToken: String? = nil,
49-
clientId: String? = nil,
50-
clientSecret: String? = nil,
51-
host: String = AsposeBarcodeCloudConfiguration.defaultHost,
52-
tokenURL: String = AsposeBarcodeCloudConfiguration.defaultTokenURL,
53-
sdkName: String = AsposeBarcodeCloudConfiguration.defaultSdkName,
54-
sdkVersion: String = AsposeBarcodeCloudConfiguration.defaultSdkVersion,
55-
timeoutInterval: TimeInterval = 300
56-
) {
57-
self.accessToken = accessToken
58-
self.clientId = clientId
59-
self.clientSecret = clientSecret
60-
self.host = host
61-
self.tokenURL = tokenURL
62-
self.sdkName = sdkName
63-
self.sdkVersion = sdkVersion
64-
self.timeoutInterval = timeoutInterval
65-
}
66-
67-
public func makeTokenRequest() throws -> URLRequest {
68-
guard let clientId = clientId, !clientId.isEmpty,
69-
let clientSecret = clientSecret, !clientSecret.isEmpty else {
70-
throw AsposeBarcodeCloudClientError.missingCredentials
71-
}
72-
73-
guard let url = URL(string: tokenURL) else {
74-
throw AsposeBarcodeCloudClientError.invalidTokenURL(tokenURL)
75-
}
76-
77-
var components = URLComponents()
78-
components.queryItems = [
79-
URLQueryItem(name: "grant_type", value: "client_credentials"),
80-
URLQueryItem(name: "client_id", value: clientId),
81-
URLQueryItem(name: "client_secret", value: clientSecret),
82-
]
83-
84-
var request = URLRequest(url: url)
85-
request.httpMethod = "POST"
86-
request.timeoutInterval = timeoutInterval
87-
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
88-
request.httpBody = components.percentEncodedQuery?.data(using: .utf8)
89-
return request
90-
}
91-
}
92-
936
public typealias AsposeBarcodeCloudTokenFetcher = @Sendable (
947
AsposeBarcodeCloudConfiguration,
958
@escaping @Sendable (Result<String, AsposeBarcodeCloudClientError>) -> Void
@@ -218,114 +131,3 @@ public final class AsposeBarcodeCloudClient: @unchecked Sendable {
218131
}.resume()
219132
}
220133
}
221-
222-
final class BarcodeAuthInterceptor: OpenAPIInterceptor, @unchecked Sendable {
223-
private let configuration: AsposeBarcodeCloudConfiguration
224-
private let tokenFetcher: AsposeBarcodeCloudTokenFetcher
225-
private let state: OpenAPIMutex<State>
226-
227-
private struct State {
228-
var token: String?
229-
var inFlightFetch: Bool
230-
var pendingWaiters: [@Sendable (Result<String, AsposeBarcodeCloudClientError>) -> Void]
231-
}
232-
233-
init(
234-
configuration: AsposeBarcodeCloudConfiguration,
235-
tokenFetcher: @escaping AsposeBarcodeCloudTokenFetcher
236-
) {
237-
self.configuration = configuration
238-
self.tokenFetcher = tokenFetcher
239-
let initialToken = configuration.accessToken.flatMap { $0.isEmpty ? nil : $0 }
240-
self.state = OpenAPIMutex(State(
241-
token: initialToken,
242-
inFlightFetch: false,
243-
pendingWaiters: []
244-
))
245-
}
246-
247-
func intercept<T>(
248-
urlRequest: URLRequest,
249-
urlSession: URLSessionProtocol,
250-
requestBuilder: RequestBuilder<T>,
251-
completion: @Sendable @escaping (Result<URLRequest, any Error>) -> Void
252-
) {
253-
guard requestBuilder.requiresAuthentication else {
254-
completion(.success(urlRequest))
255-
return
256-
}
257-
258-
ensureToken { result in
259-
switch result {
260-
case let .success(token):
261-
var modified = urlRequest
262-
modified.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
263-
completion(.success(modified))
264-
case let .failure(error):
265-
completion(.failure(error))
266-
}
267-
}
268-
}
269-
270-
func retry<T>(
271-
urlRequest: URLRequest,
272-
urlSession: URLSessionProtocol,
273-
requestBuilder: RequestBuilder<T>,
274-
data: Data?,
275-
response: URLResponse?,
276-
error: any Error,
277-
completion: @Sendable @escaping (OpenAPIInterceptorRetry) -> Void
278-
) {
279-
completion(.dontRetry)
280-
}
281-
282-
func ensureToken(completion: @escaping @Sendable (Result<String, AsposeBarcodeCloudClientError>) -> Void) {
283-
enum Action {
284-
case immediate(Result<String, AsposeBarcodeCloudClientError>)
285-
case wait
286-
case startFetch
287-
}
288-
289-
var action: Action = .wait
290-
state.withValue { state in
291-
if let token = state.token, !token.isEmpty {
292-
action = .immediate(.success(token))
293-
return
294-
}
295-
state.pendingWaiters.append(completion)
296-
if state.inFlightFetch {
297-
action = .wait
298-
} else {
299-
state.inFlightFetch = true
300-
action = .startFetch
301-
}
302-
}
303-
304-
switch action {
305-
case let .immediate(result):
306-
completion(result)
307-
case .wait:
308-
break
309-
case .startFetch:
310-
tokenFetcher(configuration) { [weak self] result in
311-
self?.deliverToken(result)
312-
}
313-
}
314-
}
315-
316-
private func deliverToken(_ result: Result<String, AsposeBarcodeCloudClientError>) {
317-
var waiters: [@Sendable (Result<String, AsposeBarcodeCloudClientError>) -> Void] = []
318-
state.withValue { state in
319-
state.inFlightFetch = false
320-
if case let .success(token) = result {
321-
state.token = token
322-
self.configuration.accessToken = token
323-
}
324-
waiters = state.pendingWaiters
325-
state.pendingWaiters.removeAll()
326-
}
327-
for waiter in waiters {
328-
waiter(result)
329-
}
330-
}
331-
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Foundation
2+
3+
public enum AsposeBarcodeCloudClientError: Error, CustomStringConvertible, @unchecked Sendable {
4+
case missingCredentials
5+
case invalidTokenURL(String)
6+
case invalidTokenResponse
7+
case tokenRequestFailed(statusCode: Int, body: String?)
8+
case transportError(Error)
9+
10+
public var description: String {
11+
switch self {
12+
case .missingCredentials:
13+
return "Access token or clientId/clientSecret are required"
14+
case let .invalidTokenURL(url):
15+
return "Invalid token URL: \(url)"
16+
case .invalidTokenResponse:
17+
return "Token response does not contain access_token"
18+
case let .tokenRequestFailed(statusCode, body):
19+
if let body = body, !body.isEmpty {
20+
return "Token request failed with status \(statusCode): \(body)"
21+
}
22+
return "Token request failed with status \(statusCode)"
23+
case let .transportError(error):
24+
return error.localizedDescription
25+
}
26+
}
27+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Foundation
2+
#if canImport(FoundationNetworking)
3+
import FoundationNetworking
4+
#endif
5+
6+
public final class AsposeBarcodeCloudConfiguration: @unchecked Sendable {
7+
public static let defaultHost = "https://api.aspose.cloud/v4.0"
8+
public static let defaultTokenURL = "https://id.aspose.cloud/connect/token"
9+
public static let defaultSdkName = "swift sdk"
10+
public static let defaultSdkVersion = "26.4.0"
11+
12+
public var host: String
13+
public var tokenURL: String
14+
public var accessToken: String?
15+
public var clientId: String?
16+
public var clientSecret: String?
17+
public var sdkName: String
18+
public var sdkVersion: String
19+
public var timeoutInterval: TimeInterval
20+
21+
public init(
22+
accessToken: String? = nil,
23+
clientId: String? = nil,
24+
clientSecret: String? = nil,
25+
host: String = AsposeBarcodeCloudConfiguration.defaultHost,
26+
tokenURL: String = AsposeBarcodeCloudConfiguration.defaultTokenURL,
27+
sdkName: String = AsposeBarcodeCloudConfiguration.defaultSdkName,
28+
sdkVersion: String = AsposeBarcodeCloudConfiguration.defaultSdkVersion,
29+
timeoutInterval: TimeInterval = 300
30+
) {
31+
self.accessToken = accessToken
32+
self.clientId = clientId
33+
self.clientSecret = clientSecret
34+
self.host = host
35+
self.tokenURL = tokenURL
36+
self.sdkName = sdkName
37+
self.sdkVersion = sdkVersion
38+
self.timeoutInterval = timeoutInterval
39+
}
40+
41+
public func makeTokenRequest() throws -> URLRequest {
42+
guard let clientId = clientId, !clientId.isEmpty,
43+
let clientSecret = clientSecret, !clientSecret.isEmpty else {
44+
throw AsposeBarcodeCloudClientError.missingCredentials
45+
}
46+
47+
guard let url = URL(string: tokenURL) else {
48+
throw AsposeBarcodeCloudClientError.invalidTokenURL(tokenURL)
49+
}
50+
51+
var components = URLComponents()
52+
components.queryItems = [
53+
URLQueryItem(name: "grant_type", value: "client_credentials"),
54+
URLQueryItem(name: "client_id", value: clientId),
55+
URLQueryItem(name: "client_secret", value: clientSecret),
56+
]
57+
58+
var request = URLRequest(url: url)
59+
request.httpMethod = "POST"
60+
request.timeoutInterval = timeoutInterval
61+
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
62+
request.httpBody = components.percentEncodedQuery?.data(using: .utf8)
63+
return request
64+
}
65+
}

0 commit comments

Comments
 (0)