From 88598968fdcf404b67f2c43acb66eeb491507803 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 22 Mar 2024 14:36:52 -0700 Subject: [PATCH] chore: amplify network package --- .../xcschemes/Amplify-Package.xcscheme | 19 +++++ .../APIKeyAuthInterceptor.swift | 7 +- .../AuthTokenInterceptor.swift | 2 +- .../IAMAuthInterceptor.swift | 5 +- .../AWSGraphQLSubscriptionTaskRunner.swift | 40 +++++++++-- .../AppSyncRealTimeClientFactory.swift | 11 +-- .../AmplifyAWSServiceConfiguration.swift | 2 +- ...reLargeNumberModelsSubscriptionTests.swift | 1 + .../AppSyncRealTimeClient+HandleRequest.swift | 1 + .../AppSyncRealTimeClient.swift | 69 +++++++------------ .../AppSyncRealTimeRequest.swift | 16 +++-- .../AppSyncRealTimeRequestAuth.swift | 25 ++++++- .../AppSyncRealTimeResponse.swift | 1 + .../AppSyncRealTimeSubscription.swift | 10 +-- .../AppSyncRequestInterceptor.swift | 3 +- .../AppSyncSubscriptionEvent.swift | 3 +- .../AppSyncWebSocketClientProtocol.swift | 4 +- .../Network}/AppSyncRealTimeClient/README.md | 0 .../WebSocket/AmplifyNetworkMonitor.swift | 0 .../Sources/Network}/WebSocket/README.md | 0 .../Network}/WebSocket/RetryWithJitter.swift | 0 .../Network}/WebSocket/WebSocketClient.swift | 0 .../Network}/WebSocket/WebSocketEvent.swift | 0 .../WebSocket/WebSocketInterceptor.swift | 0 .../WebSocketNetworkMonitorProtocol.swift | 0 .../WebSocket/LocalWebSocketServer.swift | 0 .../WebSocket/RetryWithJitterTests.swift | 0 .../WebSocket/WebSocketClientTests.swift | 0 Package.swift | 21 +++++- 29 files changed, 158 insertions(+), 82 deletions(-) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift (99%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeClient.swift (89%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift (91%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift (80%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift (97%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift (95%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift (79%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift (86%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift (85%) rename AmplifyPlugins/{API/Sources/AWSAPIPlugin => Internal/Sources/Network}/AppSyncRealTimeClient/README.md (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/AmplifyNetworkMonitor.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/README.md (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/RetryWithJitter.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/WebSocketClient.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/WebSocketEvent.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/WebSocketInterceptor.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCore => Internal/Sources/Network}/WebSocket/WebSocketNetworkMonitorProtocol.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCoreTests => Internal/Tests/NetworkTests}/WebSocket/LocalWebSocketServer.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCoreTests => Internal/Tests/NetworkTests}/WebSocket/RetryWithJitterTests.swift (100%) rename AmplifyPlugins/{Core/AWSPluginsCoreTests => Internal/Tests/NetworkTests}/WebSocket/WebSocketClientTests.swift (100%) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Amplify-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Amplify-Package.xcscheme index 6970be959c..08c2c9efc2 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Amplify-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Amplify-Package.xcscheme @@ -741,6 +741,16 @@ ReferencedContainer = "container:"> + + + + + + + + diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/APIKeyAuthInterceptor.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/APIKeyAuthInterceptor.swift index f52ded490e..671e0627c7 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/APIKeyAuthInterceptor.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/APIKeyAuthInterceptor.swift @@ -8,7 +8,7 @@ import Foundation import Amplify -@_spi(WebSocket) import AWSPluginsCore +@_spi(WebSocket) @_spi(AppSyncRTC) import AmplifyNetwork class APIKeyAuthInterceptor { private let apiKey: String @@ -31,7 +31,10 @@ extension APIKeyAuthInterceptor: WebSocketInterceptor { extension APIKeyAuthInterceptor: AppSyncRequestInterceptor { func interceptRequest(event: AppSyncRealTimeRequest, url: URL) async -> AppSyncRealTimeRequest { - let host = AppSyncRealTimeClientFactory.appSyncApiEndpoint(url).host! + guard let host = AppSyncRealTimeClientFactory.appSyncApiEndpoint(url).host else { + return event + } + guard case .start(let request) = event else { return event } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/AuthTokenInterceptor.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/AuthTokenInterceptor.swift index b0f19ffd78..99db676356 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/AuthTokenInterceptor.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/AuthTokenInterceptor.swift @@ -7,7 +7,7 @@ import Foundation import Amplify -@_spi(WebSocket) import AWSPluginsCore +@_spi(WebSocket) @_spi(AppSyncRTC) import AmplifyNetwork /// General purpose authenticatication subscriptions interceptor for providers whose only /// requirement is to provide an authentication token via the "Authorization" header diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift index c3d33320c2..e8ff9cc7c2 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift @@ -6,10 +6,11 @@ // import Foundation -@_spi(WebSocket) import AWSPluginsCore import Amplify import AWSClientRuntime import ClientRuntime +import AWSPluginsCore +@_spi(WebSocket) @_spi(AppSyncRTC) import AmplifyNetwork class IAMAuthInterceptor { @@ -114,7 +115,7 @@ extension IAMAuthInterceptor: AppSyncRequestInterceptor { return .start(.init( id: request.id, data: request.data, - auth: authHeader.map { .iam($0) } + auth: authHeader.map { AppSyncRealTimeRequestAuth.iam($0) } )) } } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLSubscriptionTaskRunner.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLSubscriptionTaskRunner.swift index 3e70654298..8c78cb10ca 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLSubscriptionTaskRunner.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLSubscriptionTaskRunner.swift @@ -9,6 +9,7 @@ import Amplify import Foundation import AWSPluginsCore import Combine +@_spi(AppSyncRTC) import AmplifyNetwork public class AWSGraphQLSubscriptionTaskRunner: InternalTaskRunner, InternalTaskAsyncThrowingSequence, InternalTaskThrowingChannel { public typealias Request = GraphQLOperationRequest @@ -140,8 +141,8 @@ public class AWSGraphQLSubscriptionTaskRunner: InternalTaskRunner, case .unsubscribed: send(GraphQLSubscriptionEvent.connection(.disconnected)) finish() - case .error(let errors): - fail(toAPIError(errors, type: R.self)) + case .error(let payload): + fail(toAPIError(decodeAppSyncRealTimeResponseError(payload), type: R.self)) } } @@ -320,8 +321,8 @@ final public class AWSGraphQLSubscriptionOperation: GraphQLSubscri dispatchInProcess(data: GraphQLSubscriptionEvent.connection(.disconnected)) dispatch(result: .successfulVoid) finish() - case .error(let errors): - dispatch(result: .failure(toAPIError(errors, type: R.self))) + case .error(let payload): + dispatch(result: .failure(toAPIError(decodeAppSyncRealTimeResponseError(payload), type: R.self))) finish() } } @@ -402,5 +403,36 @@ fileprivate func toAPIError(_ errors: [Error], type: R.Type) -> AP errors.first ) } +} + +fileprivate func decodeAppSyncRealTimeResponseError(_ data: JSONValue?) -> [Error] { + let knownAppSyncRealTimeRequestErorrs = + decodeAppSyncRealTimeRequestError(data) + .filter { !$0.isUnknown } + if knownAppSyncRealTimeRequestErorrs.isEmpty { + let graphQLErrors = decodeGraphQLErrors(data) + return graphQLErrors.isEmpty + ? [APIError.operationError("Failed to decode AppSync error response", "", nil)] + : graphQLErrors + } else { + return knownAppSyncRealTimeRequestErorrs + } +} + +fileprivate func decodeGraphQLErrors(_ data: JSONValue?) -> [GraphQLError] { + do { + return try GraphQLErrorDecoder.decodeAppSyncErrors(data) + } catch { + print("Failed to decode errors: \(error)") + return [] + } +} +fileprivate func decodeAppSyncRealTimeRequestError(_ data: JSONValue?) -> [AppSyncRealTimeRequest.Error] { + guard let errorsJson = data?.errors else { + print("No 'errors' field found in response json") + return [] + } + let errors = errorsJson.asArray ?? [errorsJson] + return errors.compactMap(AppSyncRealTimeRequest.parseResponseError(error:)) } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift index b97459c0e1..7c2e585e1a 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift @@ -9,7 +9,9 @@ import Foundation import Amplify import Combine -@_spi(WebSocket) import AWSPluginsCore +import AWSPluginsCore +@_spi(WebSocket) @_spi(AppSyncRTC) import AmplifyNetwork + protocol AppSyncRealTimeClientFactoryProtocol { func getAppSyncRealTimeClient( @@ -21,13 +23,6 @@ protocol AppSyncRealTimeClientFactoryProtocol { ) async throws -> AppSyncRealTimeClientProtocol } -protocol AppSyncRealTimeClientProtocol { - func connect() async throws - func disconnectWhenIdel() async - func disconnect() async - func subscribe(id: String, query: String) async throws -> AnyPublisher - func unsubscribe(id: String) async throws -} actor AppSyncRealTimeClientFactory: AppSyncRealTimeClientFactoryProtocol { struct MapperCacheKey: Hashable { diff --git a/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift b/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift index ac6db525d2..ca8f6cdbf9 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/ServiceConfiguration/AmplifyAWSServiceConfiguration.swift @@ -15,7 +15,7 @@ import Amplify public class AmplifyAWSServiceConfiguration { /// - Tag: AmplifyAWSServiceConfiguration.amplifyVersion - public static let amplifyVersion = "2.28.0" + public static let amplifyVersion = "2.27.3" /// - Tag: AmplifyAWSServiceConfiguration.platformName public static let platformName = "amplify-swift" diff --git a/AmplifyPlugins/DataStore/Tests/DataStoreHostApp/AWSDataStorePluginIntegrationTests/DataStoreLargeNumberModelsSubscriptionTests.swift b/AmplifyPlugins/DataStore/Tests/DataStoreHostApp/AWSDataStorePluginIntegrationTests/DataStoreLargeNumberModelsSubscriptionTests.swift index cc09f0f40d..cc0fc9fbe6 100644 --- a/AmplifyPlugins/DataStore/Tests/DataStoreHostApp/AWSDataStorePluginIntegrationTests/DataStoreLargeNumberModelsSubscriptionTests.swift +++ b/AmplifyPlugins/DataStore/Tests/DataStoreHostApp/AWSDataStorePluginIntegrationTests/DataStoreLargeNumberModelsSubscriptionTests.swift @@ -10,6 +10,7 @@ import XCTest import Combine import Amplify @testable import AWSAPIPlugin +@_spi(AppSyncRTC) import AmplifyNetwork class DataStoreLargeNumberModelsSubscriptionTests: SyncEngineIntegrationTestBase { diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift similarity index 99% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift index d3eee7a753..4e8808c7ea 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient+HandleRequest.swift @@ -10,6 +10,7 @@ import Foundation import Combine import Amplify +@_spi(AppSyncRTC) extension AppSyncRealTimeClient { /** Submit an AppSync request to real-time server. diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient.swift similarity index 89% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient.swift index c8bf7efcab..205a038d44 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeClient.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeClient.swift @@ -7,15 +7,24 @@ import Foundation -import Amplify import Combine -@_spi(WebSocket) import AWSPluginsCore +import Amplify + +@_spi(AppSyncRTC) +public protocol AppSyncRealTimeClientProtocol { + func connect() async throws + func disconnectWhenIdel() async + func disconnect() async + func subscribe(id: String, query: String) async throws -> AnyPublisher + func unsubscribe(id: String) async throws +} /** The AppSyncRealTimeClient conforms to the AppSync real-time WebSocket protocol. ref: https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html */ -actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { +@_spi(AppSyncRTC) +public actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { static let jsonEncoder = JSONEncoder() static let jsonDecoder = JSONDecoder() @@ -50,7 +59,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { /// Writable data stream convert WebSocketEvent to AppSyncRealTimeResponse internal let subject = PassthroughSubject() - var isConnected: Bool { + public var isConnected: Bool { self.state.value == .connected } @@ -61,7 +70,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { - requestInterceptor: Interceptor for decocating AppSyncRealTimeRequest - webSocketClient: WebSocketClient for reading/writing to connection */ - init( + public init( endpoint: URL, requestInterceptor: AppSyncRequestInterceptor, webSocketClient: AppSyncWebSocketClientProtocol @@ -84,7 +93,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { /** Connecting to remote AppSync real-time server. */ - func connect() async throws { + public func connect() async throws { switch self.state.value { case .connecting, .connected: log.debug("[AppSyncRealTimeClient] client is already connecting or connected") @@ -116,7 +125,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { /** Disconnect only when there are no subscriptions exist. */ - func disconnectWhenIdel() async { + public func disconnectWhenIdel() async { if self.subscriptions.isEmpty { log.debug("[AppSyncRealTimeClient] no subscription exist, client is trying to disconnect") await disconnect() @@ -128,7 +137,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { /** Disconnect from AppSync real-time server. */ - func disconnect() async { + public func disconnect() async { guard self.state.value != .disconnecting else { log.debug("[AppSyncRealTimeClient] client already disconnecting") return @@ -152,7 +161,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { - Returns: A never fail data stream for AppSyncSubscriptionEvent. */ - func subscribe(id: String, query: String) async throws -> AnyPublisher { + public func subscribe(id: String, query: String) async throws -> AnyPublisher { log.debug("[AppSyncRealTimeClient] Received subscription request id: \(id), query: \(query)") let subscription = AppSyncRealTimeSubscription(id: id, query: query, appSyncRealTimeClient: self) subscriptions[id] = subscription @@ -201,7 +210,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { - Parameters: - id: unique identifier of the subscription. */ - func unsubscribe(id: String) async throws { + public func unsubscribe(id: String) async throws { defer { log.debug("[AppSyncRealTimeClient] deleted subscription with id: \(id)") subscriptions.removeValue(forKey: id) @@ -283,7 +292,7 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { .map { response -> AppSyncSubscriptionEvent? in switch response.type { case .connectionError, .error: - return .error(Self.decodeAppSyncRealTimeResponseError(response.payload)) + return response.payload.map { .error($0) } case .data: return response.payload.map { .data($0) } default: @@ -294,38 +303,6 @@ actor AppSyncRealTimeClient: AppSyncRealTimeClientProtocol { .eraseToAnyPublisher() } - private static func decodeAppSyncRealTimeResponseError(_ data: JSONValue?) -> [Error] { - let knownAppSyncRealTimeRequestErorrs = - Self.decodeAppSyncRealTimeRequestError(data) - .filter { !$0.isUnknown } - if knownAppSyncRealTimeRequestErorrs.isEmpty { - let graphQLErrors = Self.decodeGraphQLErrors(data) - return graphQLErrors.isEmpty - ? [APIError.operationError("Failed to decode AppSync error response", "", nil)] - : graphQLErrors - } else { - return knownAppSyncRealTimeRequestErorrs - } - } - - private static func decodeGraphQLErrors(_ data: JSONValue?) -> [GraphQLError] { - do { - return try GraphQLErrorDecoder.decodeAppSyncErrors(data) - } catch { - log.debug("[AppSyncRealTimeClient] Failed to decode errors: \(error)") - return [] - } - } - - private static func decodeAppSyncRealTimeRequestError(_ data: JSONValue?) -> [AppSyncRealTimeRequest.Error] { - guard let errorsJson = data?.errors else { - log.error("[AppSyncRealTimeClient] No 'errors' field found in response json") - return [] - } - let errors = errorsJson.asArray ?? [errorsJson] - return errors.compactMap(AppSyncRealTimeRequest.parseResponseError(error:)) - } - private func bindCancellableToConnection(_ cancellable: AnyCancellable) { cancellable.store(in: &cancellablesBindToConnection) } @@ -434,15 +411,15 @@ extension Publisher where Output == AppSyncRealTimeSubscription.State, Failure = } extension AppSyncRealTimeClient: DefaultLogger { - static var log: Logger { + public static var log: Logger { Amplify.Logging.logger(forCategory: CategoryType.api.displayName, forNamespace: String(describing: self)) } - nonisolated var log: Logger { Self.log } + public nonisolated var log: Logger { Self.log } } extension AppSyncRealTimeClient: Resettable { - func reset() async { + public func reset() async { subject.send(completion: .finished) cancellables = Set() cancellablesBindToConnection = Set() diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift similarity index 91% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift index 19599820b4..a08855d6ee 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequest.swift @@ -7,18 +7,24 @@ import Foundation -import Combine import Amplify +@_spi(AppSyncRTC) public enum AppSyncRealTimeRequest { case connectionInit case start(StartRequest) case stop(String) public struct StartRequest { - let id: String - let data: String - let auth: AppSyncRealTimeRequestAuth? + public let id: String + public let data: String + public let auth: AppSyncRealTimeRequestAuth? + + public init(id: String, data: String, auth: AppSyncRealTimeRequestAuth?) { + self.id = id + self.data = data + self.auth = auth + } } var id: String? { @@ -78,7 +84,7 @@ extension AppSyncRealTimeRequest { case unauthorized case unknown(message: String? = nil, causedBy: Swift.Error? = nil, payload: [String: Any]?) - var isUnknown: Bool { + public var isUnknown: Bool { if case .unknown = self { return true } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift similarity index 80% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift index 87e01b1842..68db7f9de3 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeRequestAuth.swift @@ -8,6 +8,7 @@ import Foundation +@_spi(AppSyncRTC) public enum AppSyncRealTimeRequestAuth { case authToken(AuthToken) case apiKey(ApiKey) @@ -16,12 +17,23 @@ public enum AppSyncRealTimeRequestAuth { public struct AuthToken { let host: String let authToken: String + + public init(host: String, authToken: String) { + self.host = host + self.authToken = authToken + } } public struct ApiKey { let host: String let apiKey: String let amzDate: String + + public init(host: String, apiKey: String, amzDate: String) { + self.host = host + self.apiKey = apiKey + self.amzDate = amzDate + } } public struct IAM { @@ -29,18 +41,25 @@ public enum AppSyncRealTimeRequestAuth { let authToken: String let securityToken: String let amzDate: String + + public init(host: String, authToken: String, securityToken: String, amzDate: String) { + self.host = host + self.authToken = authToken + self.securityToken = securityToken + self.amzDate = amzDate + } } public struct URLQuery { let header: AppSyncRealTimeRequestAuth let payload: String - init(header: AppSyncRealTimeRequestAuth, payload: String = "{}") { + public init(header: AppSyncRealTimeRequestAuth, payload: String = "{}") { self.header = header self.payload = payload } - func withBaseURL(_ url: URL, encoder: JSONEncoder? = nil) -> URL { + public func withBaseURL(_ url: URL, encoder: JSONEncoder? = nil) -> URL { let jsonEncoder: JSONEncoder = encoder ?? JSONEncoder() guard let headerJsonData = try? jsonEncoder.encode(header) else { return url @@ -53,7 +72,7 @@ public enum AppSyncRealTimeRequestAuth { urlComponents.queryItems = [ URLQueryItem(name: "header", value: headerJsonData.base64EncodedString()), - URLQueryItem(name: "payload", value: try? payload.base64EncodedString()) + URLQueryItem(name: "payload", value: payload.data(using: .utf8)?.base64EncodedString()) ] return urlComponents.url ?? url diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift similarity index 97% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift index dfec371035..c6a0616047 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeResponse.swift @@ -8,6 +8,7 @@ import Foundation import Amplify +@_spi(AppSyncRTC) public struct AppSyncRealTimeResponse { public let id: String? diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift similarity index 95% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift index d7e4c6ef42..5517057306 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRealTimeSubscription.swift @@ -9,15 +9,15 @@ import Foundation import Combine import Amplify -@_spi(WebSocket) import AWSPluginsCore /** AppSyncRealTimeSubscription reprensents one realtime subscription to AppSync realtime server. */ -actor AppSyncRealTimeSubscription { +@_spi(AppSyncRTC) +public actor AppSyncRealTimeSubscription { static let jsonEncoder = JSONEncoder() - enum State { + public enum State { case none case subscribing case subscribed @@ -121,9 +121,9 @@ actor AppSyncRealTimeSubscription { } extension AppSyncRealTimeSubscription: DefaultLogger { - static var log: Logger { + public static var log: Logger { Amplify.Logging.logger(forCategory: CategoryType.api.displayName, forNamespace: String(describing: self)) } - nonisolated var log: Logger { Self.log } + nonisolated public var log: Logger { Self.log } } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift similarity index 79% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift index 92414ea28c..b94c16ae70 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncRequestInterceptor.swift @@ -8,6 +8,7 @@ import Foundation -protocol AppSyncRequestInterceptor { +@_spi(AppSyncRTC) +public protocol AppSyncRequestInterceptor { func interceptRequest(event: AppSyncRealTimeRequest, url: URL) async -> AppSyncRealTimeRequest } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift similarity index 86% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift index ec86c53e6a..00404601ab 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncSubscriptionEvent.swift @@ -9,10 +9,11 @@ import Foundation import Amplify +@_spi(AppSyncRTC) public enum AppSyncSubscriptionEvent { case subscribing case subscribed case data(JSONValue) case unsubscribed - case error([Error]) + case error(JSONValue) } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift similarity index 85% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift index d7d9cadc29..570ca71689 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift +++ b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/AppSyncWebSocketClientProtocol.swift @@ -8,9 +8,9 @@ import Foundation import Combine -@_spi(WebSocket) import AWSPluginsCore -protocol AppSyncWebSocketClientProtocol: AnyObject { +@_spi(AppSyncRTC) +public protocol AppSyncWebSocketClientProtocol: AnyObject { var isConnected: Bool { get async } var publisher: AnyPublisher { get async } diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/README.md b/AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/README.md similarity index 100% rename from AmplifyPlugins/API/Sources/AWSAPIPlugin/AppSyncRealTimeClient/README.md rename to AmplifyPlugins/Internal/Sources/Network/AppSyncRealTimeClient/README.md diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/AmplifyNetworkMonitor.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/AmplifyNetworkMonitor.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/README.md b/AmplifyPlugins/Internal/Sources/Network/WebSocket/README.md similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/README.md rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/README.md diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/RetryWithJitter.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/RetryWithJitter.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/RetryWithJitter.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/RetryWithJitter.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketClient.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketClient.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketEvent.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketEvent.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketEvent.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketEvent.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketInterceptor.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketInterceptor.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketInterceptor.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketInterceptor.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketNetworkMonitorProtocol.swift b/AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketNetworkMonitorProtocol.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketNetworkMonitorProtocol.swift rename to AmplifyPlugins/Internal/Sources/Network/WebSocket/WebSocketNetworkMonitorProtocol.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/LocalWebSocketServer.swift b/AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/LocalWebSocketServer.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/LocalWebSocketServer.swift rename to AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/LocalWebSocketServer.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/RetryWithJitterTests.swift b/AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/RetryWithJitterTests.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/RetryWithJitterTests.swift rename to AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/RetryWithJitterTests.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift b/AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/WebSocketClientTests.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift rename to AmplifyPlugins/Internal/Tests/NetworkTests/WebSocket/WebSocketClientTests.swift diff --git a/Package.swift b/Package.swift index 77f5211f2a..da9b806838 100644 --- a/Package.swift +++ b/Package.swift @@ -115,7 +115,8 @@ let apiTargets: [Target] = [ name: "AWSAPIPlugin", dependencies: [ .target(name: "Amplify"), - .target(name: "AWSPluginsCore") + .target(name: "AWSPluginsCore"), + .target(name: "AmplifyNetwork") ], path: "AmplifyPlugins/API/Sources/AWSAPIPlugin", exclude: [ @@ -315,6 +316,23 @@ let internalPinpointTargets: [Target] = [ ) ] +let internalNetworkingTargets: [Target] = [ + .target( + name: "AmplifyNetwork", + dependencies: [ + .target(name: "Amplify") + ], + path: "AmplifyPlugins/Internal/Sources/Network" + ), + .testTarget( + name: "AmplifyNetworkUnitTests", + dependencies: [ + "AmplifyNetwork" + ], + path: "AmplifyPlugins/Internal/Tests/NetworkTests" + ) +] + let analyticsTargets: [Target] = [ .target( name: "AWSPinpointAnalyticsPlugin", @@ -443,6 +461,7 @@ let targets: [Target] = amplifyTargets + analyticsTargets + pushNotificationsTargets + internalPinpointTargets + + internalNetworkingTargets + predictionsTargets + loggingTargets