Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add async OIDCAuthProvider protocol #119

Merged
merged 12 commits into from
Apr 17, 2023
4 changes: 4 additions & 0 deletions AppSyncRealTimeClient.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
5CFF723E283C1AF5001D5471 /* RealtimeConnectionProviderAsyncTestBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFF723C283C1AF5001D5471 /* RealtimeConnectionProviderAsyncTestBase.swift */; };
978409B82739C7BE002362A7 /* AppSyncURLHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978409B72739C7BE002362A7 /* AppSyncURLHelper.swift */; };
978409BA2739C7E1002362A7 /* AppSyncURLHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978409B92739C7E1002362A7 /* AppSyncURLHelperTests.swift */; };
B4AEC68C29E8A14F00D693CD /* InterceptableConnection+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AEC68B29E8A14F00D693CD /* InterceptableConnection+Default.swift */; };
DCFE701B5D1380E566694A48 /* Pods_AppSyncRealTimeClient_AppSyncRealTimeClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E662A46AB2C93EE316F784C /* Pods_AppSyncRealTimeClient_AppSyncRealTimeClientTests.framework */; };
FA67507824D3244A005A1345 /* MockWebsocketProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA67507724D3244A005A1345 /* MockWebsocketProvider.swift */; };
FA67507B24D338CB005A1345 /* Error+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA67507A24D338C6005A1345 /* Error+Extension.swift */; };
Expand Down Expand Up @@ -242,6 +243,7 @@
A843B4589131E0D2DB13ADC7 /* Pods-HostApp-AppSyncRealTimeClientIntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp-AppSyncRealTimeClientIntegrationTests.debug.xcconfig"; path = "Target Support Files/Pods-HostApp-AppSyncRealTimeClientIntegrationTests/Pods-HostApp-AppSyncRealTimeClientIntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
B07A87133C24AA78AF59093C /* Pods-AppSyncRealTimeClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppSyncRealTimeClient.debug.xcconfig"; path = "Target Support Files/Pods-AppSyncRealTimeClient/Pods-AppSyncRealTimeClient.debug.xcconfig"; sourceTree = "<group>"; };
B4A642C2C000E0D0B568A4A9 /* Pods-AppSyncRTCSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppSyncRTCSample.release.xcconfig"; path = "Target Support Files/Pods-AppSyncRTCSample/Pods-AppSyncRTCSample.release.xcconfig"; sourceTree = "<group>"; };
B4AEC68B29E8A14F00D693CD /* InterceptableConnection+Default.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "InterceptableConnection+Default.swift"; sourceTree = "<group>"; };
BBF14AA5E9A4D036CA87B952 /* Pods-AppSyncRTCSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppSyncRTCSample.debug.xcconfig"; path = "Target Support Files/Pods-AppSyncRTCSample/Pods-AppSyncRTCSample.debug.xcconfig"; sourceTree = "<group>"; };
C73EA796F50FB0196FDF4865 /* Pods-AppSyncRealTimeClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppSyncRealTimeClient.release.xcconfig"; path = "Target Support Files/Pods-AppSyncRealTimeClient/Pods-AppSyncRealTimeClient.release.xcconfig"; sourceTree = "<group>"; };
E65A19C826699DA299A49284 /* Pods-HostApp-AppSyncRealTimeClientIntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp-AppSyncRealTimeClientIntegrationTests.release.xcconfig"; path = "Target Support Files/Pods-HostApp-AppSyncRealTimeClientIntegrationTests/Pods-HostApp-AppSyncRealTimeClientIntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -386,6 +388,7 @@
217F39AC2406E98300F1A0B3 /* ConnectionProviderError.swift */,
21D38B8D240A3C2300EC2A8D /* ConnectionProviderFactory.swift */,
217F39AB2406E98300F1A0B3 /* InterceptableConnection.swift */,
B4AEC68B29E8A14F00D693CD /* InterceptableConnection+Default.swift */,
5C5609ED2821E6FC0002ACF5 /* InterceptableConnectionAsync.swift */,
);
path = ConnectionProvider;
Expand Down Expand Up @@ -1231,6 +1234,7 @@
219BFF4927A3B238000FC148 /* ConnectivityMonitor.swift in Sources */,
FAB7E91224D2644E00DF1EA1 /* RealtimeConnectionProvider+StaleConnection.swift in Sources */,
217F39D32406E98400F1A0B3 /* RealtimeConnectionProvider.swift in Sources */,
B4AEC68C29E8A14F00D693CD /* InterceptableConnection+Default.swift in Sources */,
217F39D12406E98400F1A0B3 /* AppSyncConnectionRequest.swift in Sources */,
5C5609EE2821E6FC0002ACF5 /* InterceptableConnectionAsync.swift in Sources */,
217F39DD2406E98400F1A0B3 /* AppSyncSubscriptionConnection+Connection.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,48 @@ extension RealtimeConnectionProvider: ConnectionInterceptable {
connectionInterceptors.append(interceptor)
}

public func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
) {
chainInterceptors(
index: 0,
request: request,
endpoint: endpoint,
completion: completion
)
}

private func chainInterceptors(
index: Int,
request: AppSyncConnectionRequest,
endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
) {

guard index < connectionInterceptors.count else {
completion(request)
return
}
let interceptor = connectionInterceptors[index]
interceptor.interceptConnection(request, for: endpoint) { interceptedRequest in
self.chainInterceptors(
index: index + 1,
request: interceptedRequest,
endpoint: endpoint,
completion: completion
)
}
}

// MARK: Deprecated method

public func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL
) -> AppSyncConnectionRequest {
// This is added here for backward compatibility
let finalRequest = connectionInterceptors.reduce(request) { $1.interceptConnection($0, for: endpoint) }
return finalRequest
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,46 @@ extension RealtimeConnectionProvider: MessageInterceptable {
messageInterceptors.append(interceptor)
}

public func interceptMessage(
_ message: AppSyncMessage,
for endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
) {

chainInterceptors(
index: 0,
message: message,
endpoint: endpoint,
completion: completion
)
}

private func chainInterceptors(
index: Int,
message: AppSyncMessage,
endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
) {

guard index < messageInterceptors.count else {
completion(message)
return
}
let interceptor = messageInterceptors[index]
royjit marked this conversation as resolved.
Show resolved Hide resolved
interceptor.interceptMessage(message, for: endpoint) { interceptedMessage in
self.chainInterceptors(
index: index + 1,
message: interceptedMessage,
endpoint: endpoint,
completion: completion
)
}
}

// MARK: Deprecated method

public func interceptMessage(_ message: AppSyncMessage, for endpoint: URL) -> AppSyncMessage {
// This is added here for backward compatibility
let finalMessage = messageInterceptors.reduce(message) { $1.interceptMessage($0, for: endpoint) }
return finalMessage
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,17 @@ public class RealtimeConnectionProvider: ConnectionProvider {
self.updateCallback(event: .connection(self.status))

let request = AppSyncConnectionRequest(url: url)
let signedRequest = self.interceptConnection(request, for: url)
var urlRequest = self.urlRequest
urlRequest.url = signedRequest.url

DispatchQueue.global().async {
self.websocket.connect(
urlRequest: urlRequest,
protocols: ["graphql-ws"],
delegate: self
)
self.interceptConnection(request, for: url) { signedRequest in
var urlRequest = self.urlRequest
urlRequest.url = signedRequest.url

DispatchQueue.global().async {
self.websocket.connect(
urlRequest: urlRequest,
protocols: ["graphql-ws"],
delegate: self
)
}
}
}
}
Expand All @@ -142,25 +143,27 @@ public class RealtimeConnectionProvider: ConnectionProvider {
)))
return
}
let signedMessage = self.interceptMessage(message, for: url)
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(signedMessage)
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
let jsonError = ConnectionProviderError.jsonParse(message.id, nil)
self.updateCallback(event: .error(jsonError))
return
}
self.websocket.write(message: jsonString)
} catch {
AppSyncLogger.error(error)
switch message.messageType {
case .connectionInit:
self.receivedConnectionInit()
default:
self.updateCallback(event: .error(ConnectionProviderError.jsonParse(message.id, error)))
self.interceptMessage(message, for: url) { signedMessage in
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(signedMessage)
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
let jsonError = ConnectionProviderError.jsonParse(message.id, nil)
self.updateCallback(event: .error(jsonError))
return
}
self.websocket.write(message: jsonString)
} catch {
AppSyncLogger.error(error)
switch message.messageType {
case .connectionInit:
self.receivedConnectionInit()
default:
self.updateCallback(event: .error(ConnectionProviderError.jsonParse(message.id, error)))
}
}
}

}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public extension ConnectionInterceptable {

func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
) {
let result = interceptConnection(request, for: endpoint)
completion(result)
}
}

public extension MessageInterceptable {

func interceptMessage(
_ message: AppSyncMessage,
for endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
) {
let result = interceptMessage(message, for: endpoint)
completion(result)
}
}

public extension ConnectionInterceptor {

func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
) {
let result = interceptConnection(request, for: endpoint)
completion(result)
}
}

public extension MessageInterceptor {

func interceptMessage(
_ message: AppSyncMessage,
for endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
) {
let result = interceptMessage(message, for: endpoint)
completion(result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,86 @@ public protocol ConnectionInterceptable {
/// - Parameter interceptor: interceptor to be added
func addInterceptor(_ interceptor: ConnectionInterceptor)

func interceptConnection(_ request: AppSyncConnectionRequest, for endpoint: URL) -> AppSyncConnectionRequest
@available(
*,
deprecated,
message:
"""
Use the async version under ConnectionInterceptableAsync or completion handler flavor
"""
)
func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL
) -> AppSyncConnectionRequest

func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
)
}

public protocol MessageInterceptable {

func addInterceptor(_ interceptor: MessageInterceptor)

@available(
*,
deprecated,
message:
"""
Use the async version under MessageInterceptableAsync or completion handler flavor
"""
)
func interceptMessage(_ message: AppSyncMessage, for endpoint: URL) -> AppSyncMessage

func interceptMessage(
_ message: AppSyncMessage,
for endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
)
}

public protocol ConnectionInterceptor {

func interceptConnection(_ request: AppSyncConnectionRequest, for endpoint: URL) -> AppSyncConnectionRequest
@available(
*,
deprecated,
message:
"""
Use the async version under ConnectionInterceptorAsync or completion handler flavor
"""
)
func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL
) -> AppSyncConnectionRequest

func interceptConnection(
_ request: AppSyncConnectionRequest,
for endpoint: URL,
completion: @escaping (AppSyncConnectionRequest) -> Void
)
}

public protocol MessageInterceptor {

@available(
*,
deprecated,
message:
"""
Use the async version under MessageInterceptorAsync or completion handler flavor
"""
)
func interceptMessage(_ message: AppSyncMessage, for endpoint: URL) -> AppSyncMessage

func interceptMessage(
_ message: AppSyncMessage,
for endpoint: URL,
completion: @escaping (AppSyncMessage) -> Void
)
}

public protocol AuthInterceptor: MessageInterceptor, ConnectionInterceptor {}
Loading