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: pass URLRequest instead of URL to interfaces #110

Merged
merged 4 commits into from
Jan 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ public class RealtimeConnectionProvider: ConnectionProvider {
/// message before we consider it stale and force a disconnect
static let staleConnectionTimeout: TimeInterval = 5 * 60

private let url: URL
private let urlRequest: URLRequest
var listeners: [String: ConnectionProviderCallback]

let websocket: AppSyncWebsocketProvider
@@ -58,12 +58,12 @@ public class RealtimeConnectionProvider: ConnectionProvider {
return iLimitExceededSubject as! PassthroughSubject<ConnectionProviderError, Never> // swiftlint:disable:this force_cast line_length
}

public convenience init(for url: URL, websocket: AppSyncWebsocketProvider) {
self.init(url: url, websocket: websocket)
public convenience init(for urlRequest: URLRequest, websocket: AppSyncWebsocketProvider) {
self.init(urlRequest: urlRequest, websocket: websocket)
}

init(
url: URL,
urlRequest: URLRequest,
websocket: AppSyncWebsocketProvider,
connectionQueue: DispatchQueue = DispatchQueue(
label: "com.amazonaws.AppSyncRealTimeConnectionProvider.serialQueue"
@@ -73,7 +73,7 @@ public class RealtimeConnectionProvider: ConnectionProvider {
),
connectivityMonitor: ConnectivityMonitor = ConnectivityMonitor()
) {
self.url = url
self.urlRequest = urlRequest
self.websocket = websocket
self.listeners = [:]
self.status = .notConnected
@@ -103,13 +103,25 @@ public class RealtimeConnectionProvider: ConnectionProvider {
self.updateCallback(event: .connection(self.status))
return
}

guard let url = self.urlRequest.url else {
self.updateCallback(event: .error(ConnectionProviderError.unknown(
message: "Missing URL",
payload: nil
)))
return
5d marked this conversation as resolved.
Show resolved Hide resolved
}
self.status = .inProgress
self.updateCallback(event: .connection(self.status))
let request = AppSyncConnectionRequest(url: self.url)
let signedRequest = self.interceptConnection(request, for: self.url)

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(
url: signedRequest.url,
urlRequest: urlRequest,
protocols: ["graphql-ws"],
delegate: self
)
@@ -123,8 +135,14 @@ public class RealtimeConnectionProvider: ConnectionProvider {
guard let self = self else {
return
}

let signedMessage = self.interceptMessage(message, for: self.url)
guard let url = self.urlRequest.url else {
self.updateCallback(event: .error(ConnectionProviderError.unknown(
message: "Missing URL",
payload: nil
)))
return
5d marked this conversation as resolved.
Show resolved Hide resolved
}
let signedMessage = self.interceptMessage(message, for: url)
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(signedMessage)
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
/// message before we consider it stale and force a disconnect
static let staleConnectionTimeout: TimeInterval = 5 * 60

let url: URL
let urlRequest: URLRequest
var listeners: [String: ConnectionProviderCallback]

let websocket: AppSyncWebsocketProvider
@@ -63,15 +63,15 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
}

init(
url: URL,
urlRequest: URLRequest,
websocket: AppSyncWebsocketProvider,

serialCallbackQueue: DispatchQueue = DispatchQueue(
label: "com.amazonaws.AppSyncRealTimeConnectionProvider.callbackQueue"
),
connectivityMonitor: ConnectivityMonitor = ConnectivityMonitor()
) {
self.url = url
self.urlRequest = urlRequest
self.websocket = websocket
self.listeners = [:]
self.status = .notConnected
@@ -84,8 +84,8 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
subscribeToLimitExceededThrottle()
}

public convenience init(for url: URL, websocket: AppSyncWebsocketProvider) {
self.init(url: url, websocket: websocket)
public convenience init(for urlRequest: URLRequest, websocket: AppSyncWebsocketProvider) {
self.init(urlRequest: urlRequest, websocket: websocket)
}

// MARK: - ConnectionProvider methods
@@ -99,13 +99,21 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
self.updateCallback(event: .connection(self.status))
return
}
guard let url = self.urlRequest.url else {
self.updateCallback(event: .error(ConnectionProviderError.unknown(
message: "Missing URL",
payload: nil
)))
return
}
self.status = .inProgress
self.updateCallback(event: .connection(self.status))
let request = AppSyncConnectionRequest(url: self.url)

let signedRequest = await self.interceptConnection(request, for: self.url)
let request = AppSyncConnectionRequest(url: url)
let signedRequest = await self.interceptConnection(request, for: url)
var urlRequest = self.urlRequest
urlRequest.url = signedRequest.url
self.websocket.connect(
url: signedRequest.url,
urlRequest: urlRequest,
protocols: ["graphql-ws"],
delegate: self
)
@@ -117,8 +125,14 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
guard let self = self else {
return
}

let signedMessage = await self.interceptMessage(message, for: self.url)
guard let url = self.urlRequest.url else {
self.updateCallback(event: .error(ConnectionProviderError.unknown(
message: "Missing URL",
payload: nil
)))
return
}
let signedMessage = await self.interceptMessage(message, for: url)

let jsonEncoder = JSONEncoder()
do {
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import Foundation
public enum ConnectionProviderFactory {

public static func createConnectionProvider(
for url: URL,
for urlRequest: URLRequest,
authInterceptor: AuthInterceptor,
connectionType: SubscriptionConnectionType
) -> ConnectionProvider {
@@ -20,7 +20,7 @@ public enum ConnectionProviderFactory {
switch connectionType {
case .appSyncRealtime:
let websocketProvider = StarscreamAdapter()
provider = RealtimeConnectionProvider(for: url, websocket: websocketProvider)
provider = RealtimeConnectionProvider(for: urlRequest, websocket: websocketProvider)
}

if let messageInterceptable = provider as? MessageInterceptable {
@@ -37,7 +37,7 @@ public enum ConnectionProviderFactory {
#if swift(>=5.5.2)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public static func createConnectionProviderAsync(
for url: URL,
for urlRequest: URLRequest,
authInterceptor: AuthInterceptorAsync,
connectionType: SubscriptionConnectionType
) -> ConnectionProvider {
@@ -46,7 +46,7 @@ public enum ConnectionProviderFactory {
switch connectionType {
case .appSyncRealtime:
let websocketProvider = StarscreamAdapter()
provider = RealtimeConnectionProviderAsync(for: url, websocket: websocketProvider)
provider = RealtimeConnectionProviderAsync(for: urlRequest, websocket: websocketProvider)
}

if let messageInterceptable = provider as? MessageInterceptableAsync {
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ public protocol AppSyncWebsocketProvider {
///
/// This is an async call. After the connection is succesfully established, the delegate
/// will receive the callback on `websocketDidConnect(:)`
func connect(url: URL, protocols: [String], delegate: AppSyncWebsocketDelegate?)
func connect(urlRequest: URLRequest, protocols: [String], delegate: AppSyncWebsocketDelegate?)

/// Disconnects the websocket.
func disconnect()
Original file line number Diff line number Diff line change
@@ -34,10 +34,11 @@ public class StarscreamAdapter: AppSyncWebsocketProvider {
self.callbackQueue = callbackQueue
}

public func connect(url: URL, protocols: [String], delegate: AppSyncWebsocketDelegate?) {
public func connect(urlRequest: URLRequest, protocols: [String], delegate: AppSyncWebsocketDelegate?) {
serialQueue.async {
AppSyncLogger.verbose("[StarscreamAdapter] connect. Connecting to url")
var urlRequest = URLRequest(url: url)
var urlRequest = urlRequest

urlRequest.setValue("no-store", forHTTPHeaderField: "Cache-Control")

let protocolHeaderValue = protocols.joined(separator: ", ")
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ class AppSyncRealTimeClientAsyncFailureTests: AppSyncRealTimeClientTestBase {
subscribeSuccess.expectedFulfillmentCount = 100
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -91,7 +91,7 @@ class AppSyncRealTimeClientAsyncFailureTests: AppSyncRealTimeClientTestBase {
subscribeSuccess.expectedFulfillmentCount = 100
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ class AppSyncRealTimeClientAsyncIntegrationTests: AppSyncRealTimeClientTestBase
let subscribeSuccess = expectation(description: "subscribe successfully")
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -75,7 +75,7 @@ class AppSyncRealTimeClientAsyncIntegrationTests: AppSyncRealTimeClientTestBase

let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -170,7 +170,7 @@ class AppSyncRealTimeClientAsyncIntegrationTests: AppSyncRealTimeClientTestBase
func testSubscribeUnsubscribeRepeat() {
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -197,7 +197,7 @@ class AppSyncRealTimeClientAsyncIntegrationTests: AppSyncRealTimeClientTestBase
func testMultipleThreadsSubscribeUnsubscribe() {
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProviderAsync(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ class AppSyncRealTimeClientFailureTests: AppSyncRealTimeClientTestBase {
subscribeSuccess.expectedFulfillmentCount = 100
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -91,7 +91,7 @@ class AppSyncRealTimeClientFailureTests: AppSyncRealTimeClientTestBase {
subscribeSuccess.expectedFulfillmentCount = 100
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -171,7 +171,7 @@ class AppSyncRealTimeClientFailureTests: AppSyncRealTimeClientTestBase {
let subscribeFailed = expectation(description: "subscribe failed")
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ class AppSyncRealTimeClientIntegrationTests: AppSyncRealTimeClientTestBase {
let subscribeSuccess = expectation(description: "subscribe successfully")
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -75,7 +75,7 @@ class AppSyncRealTimeClientIntegrationTests: AppSyncRealTimeClientTestBase {

let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -170,7 +170,7 @@ class AppSyncRealTimeClientIntegrationTests: AppSyncRealTimeClientTestBase {
func testSubscribeUnsubscribeRepeat() {
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
@@ -197,7 +197,7 @@ class AppSyncRealTimeClientIntegrationTests: AppSyncRealTimeClientTestBase {
func testMultipleThreadsSubscribeUnsubscribe() {
let authInterceptor = APIKeyAuthInterceptor(apiKey)
let connectionProvider = ConnectionProviderFactory.createConnectionProvider(
for: url,
for: urlRequest,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime
)
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import XCTest

class AppSyncRealTimeClientTestBase: XCTestCase {

var url: URL!
var urlRequest: URLRequest!
var apiKey: String!
let requestString = """
subscription onCreate {
@@ -35,7 +35,8 @@ class AppSyncRealTimeClientTestBase: XCTestCase {
let endpoint = apiName["endpoint"] as? String,
let apiKey = apiName["apiKey"] as? String {

url = URL(string: endpoint)
urlRequest = URLRequest(url: URL(string: endpoint)!)

self.apiKey = apiKey
} else {
throw "Could not retrieve endpoint"
Original file line number Diff line number Diff line change
@@ -14,13 +14,14 @@ class StarscreamAdapterTests: AppSyncRealTimeClientTestBase {
func testConnectDisconnect() throws {
let starscreamAdapter = StarscreamAdapter()
let apiKeyAuthInterceptor = APIKeyAuthInterceptor(apiKey)
let request = AppSyncConnectionRequest(url: url)
let signedRequest = apiKeyAuthInterceptor.interceptConnection(request, for: url)
let request = AppSyncConnectionRequest(url: urlRequest.url!)
let signedRequest = apiKeyAuthInterceptor.interceptConnection(request, for: urlRequest.url!)
urlRequest.url = signedRequest.url
let expectedPerforms = expectation(description: "total performs")
expectedPerforms.expectedFulfillmentCount = 1_000
DispatchQueue.concurrentPerform(iterations: 1_000) { _ in
starscreamAdapter.connect(
url: signedRequest.url,
urlRequest: urlRequest,
protocols: ["graphql-ws"],
delegate: nil
)
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import XCTest

class RealtimeConnectionProviderAsyncTestBase: XCTestCase {

let url = URL(string: "https://www.appsyncrealtimeclient.test/")!
let urlRequest = URLRequest(url: URL(string: "https://www.appsyncrealtimeclient.test/")!)

var websocket: MockWebsocketProvider!

@@ -47,7 +47,7 @@ class RealtimeConnectionProviderAsyncTestBase: XCTestCase {
connectivityMonitor: ConnectivityMonitor = ConnectivityMonitor()
) -> RealtimeConnectionProvider {
let provider = RealtimeConnectionProvider(
url: url,
urlRequest: urlRequest,
websocket: websocket,
serialCallbackQueue: serialCallbackQueue,
connectivityMonitor: connectivityMonitor
Original file line number Diff line number Diff line change
@@ -9,13 +9,13 @@ import XCTest
@testable import AppSyncRealTimeClient

class ConnectionProviderHandleErrorTests: XCTestCase {
let url = URL(string: "https://www.appsyncrealtimeclient.test/")!
let urlRequest = URLRequest(url: URL(string: "https://www.appsyncrealtimeclient.test/")!)
var websocket = MockWebsocketProvider()

/// Error response is limit exceeded with id
/// Should receive ConnectionProviderError.limitExceeded with id
func testLimitExceededWithId() {
let provider = RealtimeConnectionProvider(url: url, websocket: websocket)
let provider = RealtimeConnectionProvider(urlRequest: urlRequest, websocket: websocket)

let subscriptionEvent = expectation(description: "Receieved subscription event")
provider.addListener(identifier: "id") { event in
@@ -42,7 +42,7 @@ class ConnectionProviderHandleErrorTests: XCTestCase {
/// Should throttle and receive a fraction of ConnectionProviderError.limitExceeded event without id
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
func testLimitExceededMissingIdThrottled() {
let provider = RealtimeConnectionProvider(url: url, websocket: websocket)
let provider = RealtimeConnectionProvider(urlRequest: urlRequest, websocket: websocket)
let limitExceededThrottle = expectation(description: "received limit exceeded")
limitExceededThrottle.expectedFulfillmentCount = 100
let sink = provider.limitExceededSubject.sink { error in
@@ -86,7 +86,7 @@ class ConnectionProviderHandleErrorTests: XCTestCase {
/// Error response is max subscription with subscription id
/// Should receive ConnectionProviderError.limitExceeded with id
func testMaxSubscriptionReached() {
let provider = RealtimeConnectionProvider(url: url, websocket: websocket)
let provider = RealtimeConnectionProvider(urlRequest: urlRequest, websocket: websocket)

let subscriptionEvent = expectation(description: "Receieved subscription event")
provider.addListener(identifier: "id") { event in
@@ -112,7 +112,7 @@ class ConnectionProviderHandleErrorTests: XCTestCase {
/// Error response with no indication for which subscription and missing payload
/// Should receive ConnectionProviderError.other
func testMissingId() throws {
let provider = RealtimeConnectionProvider(url: url, websocket: websocket)
let provider = RealtimeConnectionProvider(urlRequest: urlRequest, websocket: websocket)

let subscriptionEvent = expectation(description: "Receieved subscription event")
provider.addListener(identifier: "id") { event in
@@ -137,7 +137,7 @@ class ConnectionProviderHandleErrorTests: XCTestCase {
/// Error response subscription id and payload
/// Should receive ConnectionProviderError.subscription(id, payload)
func testWithSubscriptionId() throws {
let provider = RealtimeConnectionProvider(url: url, websocket: websocket)
let provider = RealtimeConnectionProvider(urlRequest: urlRequest, websocket: websocket)

let subscriptionEvent = expectation(description: "Receieved subscription event")
provider.addListener(identifier: "id") { event in
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import XCTest

class RealtimeConnectionProviderTestBase: XCTestCase {

let url = URL(string: "https://www.appsyncrealtimeclient.test/")!
let urlRequest = URLRequest(url: URL(string: "https://www.appsyncrealtimeclient.test/")!)

var websocket: MockWebsocketProvider!

@@ -50,7 +50,7 @@ class RealtimeConnectionProviderTestBase: XCTestCase {
connectivityMonitor: ConnectivityMonitor = ConnectivityMonitor()
) -> RealtimeConnectionProvider {
let provider = RealtimeConnectionProvider(
url: url,
urlRequest: urlRequest,
websocket: websocket,
connectionQueue: connectionQueue,
serialCallbackQueue: serialCallbackQueue,
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import Foundation
import AppSyncRealTimeClient

class MockWebsocketProvider: AppSyncWebsocketProvider {
typealias OnConnect = (URL, [String], AppSyncWebsocketDelegate?) -> Void
typealias OnConnect = (URLRequest, [String], AppSyncWebsocketDelegate?) -> Void
typealias OnDisconnect = () -> Void
typealias OnWrite = (String) -> Void

@@ -30,8 +30,8 @@ class MockWebsocketProvider: AppSyncWebsocketProvider {
self.onWrite = onWrite
}

func connect(url: URL, protocols: [String], delegate: AppSyncWebsocketDelegate?) {
onConnect?(url, protocols, delegate)
func connect(urlRequest: URLRequest, protocols: [String], delegate: AppSyncWebsocketDelegate?) {
onConnect?(urlRequest, protocols, delegate)
}

func disconnect() {
11 changes: 6 additions & 5 deletions Pods/Pods.xcodeproj/project.pbxproj