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: skip network monitoring for watchOS, add watchOS client timeout #139

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Expand Up @@ -13,7 +13,7 @@ extension AppSyncSubscriptionConnection {
// we should retry the connection
if connectionState == .notConnected
&& subscriptionState == .inProgress {
let connectionError = ConnectionProviderError.connection
let connectionError = ConnectionProviderError.connection(nil, nil)
handleError(error: connectionError)
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extension RealtimeConnectionProvider {
self.status = .notConnected
self.isStaleConnection = false
self.websocket.disconnect()
self.updateCallback(event: .error(ConnectionProviderError.connection))
self.updateCallback(event: .error(ConnectionProviderError.connection(nil, nil)))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,16 @@ extension RealtimeConnectionProvider: AppSyncWebsocketDelegate {
self.updateCallback(event: .connection(self.status))
return
}
self.updateCallback(event: .error(ConnectionProviderError.connection))
#if os(watchOS)
AppSyncLogger.debug(
"[RealtimeConnectionProvider] on watchOS, received disconnect."
)
self.updateCallback(event: .error(ConnectionProviderError.connection(
"This API uses low-level networking (websockets). Running on watchOS only works for specific circumstances.",
error)))
#else
self.updateCallback(event: .error(ConnectionProviderError.connection(nil, error)))
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,13 @@ public class RealtimeConnectionProvider: ConnectionProvider {
self.serialCallbackQueue = serialCallbackQueue
self.connectivityMonitor = connectivityMonitor

// On a physical watchOS device, it is showing "unsatisfied" despite connected to the internet
// according to https://developer.apple.com/forums/thread/729568
// To avoid an incorrect network status state for the system, do not use connectivity monitor
// for watchOS apps.
#if !os(watchOS)
connectivityMonitor.start(onUpdates: handleConnectivityUpdates(connectivity:))
#endif

if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) {
subscribeToLimitExceededThrottle()
Expand Down Expand Up @@ -249,6 +255,6 @@ public class RealtimeConnectionProvider: ConnectionProvider {
/// - Warning: This must be invoked from the `connectionQueue`
private func receivedConnectionInit() {
status = .notConnected
updateCallback(event: .error(ConnectionProviderError.connection))
updateCallback(event: .error(ConnectionProviderError.connection(nil, nil)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extension RealtimeConnectionProviderResponse {

// If it is in-progress, return `.connection`.
guard connectionState != .inProgress else {
return .connection
return .connection(nil, nil)
}

if isLimitExceededError() || isMaxSubscriptionReachedError() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ extension RealtimeConnectionProviderAsync {
self.status = .notConnected
self.isStaleConnection = false
self.websocket.disconnect()
self.updateCallback(event: .error(ConnectionProviderError.connection))
self.updateCallback(event: .error(ConnectionProviderError.connection(nil, nil)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,16 @@ extension RealtimeConnectionProviderAsync: AppSyncWebsocketDelegate {
self.updateCallback(event: .connection(self.status))
return
}
self.updateCallback(event: .error(ConnectionProviderError.connection))
#if os(watchOS)
AppSyncLogger.debug(
"[RealtimeConnectionProvider] on watchOS, received disconnect."
)
self.updateCallback(event: .error(ConnectionProviderError.connection(
"This API uses low-level networking (websockets). Running on watchOS only works for specific circumstances.",
error)))
#else
self.updateCallback(event: .error(ConnectionProviderError.connection(nil, error)))
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,14 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
self.serialCallbackQueue = serialCallbackQueue
self.connectivityMonitor = connectivityMonitor

// On a physical watchOS device, it is showing "unsatisfied" despite connected to the internet
// according to https://developer.apple.com/forums/thread/729568
// To avoid an incorrect network status state for the system, do not use connectivity monitor
// for watchOS apps.
#if !os(watchOS)
connectivityMonitor.start(onUpdates: handleConnectivityUpdates(connectivity:))
#endif

subscribeToLimitExceededThrottle()
}

Expand Down Expand Up @@ -236,7 +243,7 @@ public class RealtimeConnectionProviderAsync: ConnectionProvider {
/// - Warning: This must be invoked from the `taskQueue`
private func receivedConnectionInit() {
status = .notConnected
updateCallback(event: .error(ConnectionProviderError.connection))
updateCallback(event: .error(ConnectionProviderError.connection(nil, nil)))
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
public enum ConnectionProviderError: Error {

/// Caused by connection error
case connection
case connection(String?, Error?)

/// Caused by JSON parse error. The first optional String will be the connection identifier if available.
case jsonParse(String?, Error?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class StarscreamAdapter: AppSyncWebsocketProvider {
}
}

let watchOSConnectivityTimer: CountdownTimer

public init() {
let serialQueue = DispatchQueue(label: "com.amazonaws.StarscreamAdapter.serialQueue")
let callbackQueue = DispatchQueue(
Expand All @@ -32,6 +34,7 @@ public class StarscreamAdapter: AppSyncWebsocketProvider {
self._isConnected = false
self.serialQueue = serialQueue
self.callbackQueue = callbackQueue
self.watchOSConnectivityTimer = CountdownTimer()
}

public func connect(urlRequest: URLRequest, protocols: [String], delegate: AppSyncWebsocketDelegate?) {
Expand All @@ -49,6 +52,33 @@ public class StarscreamAdapter: AppSyncWebsocketProvider {
self.socket?.delegate = self
self.socket?.callbackQueue = self.callbackQueue
self.socket?.connect()
#if os(watchOS)
AppSyncLogger.debug(
"[StarscreamAdapter] Starting connectivity timer for watchOS for 3s."
)
self.watchOSConnectivityTimer.start(interval: 3) {
AppSyncLogger.debug(
"[StarscreamAdapter] watchOS connectivity timer is up."
)
self.serialQueue.async {
if !self._isConnected {
AppSyncLogger.debug(
"[StarscreamAdapter] watchOS subscriptions not connected after 3s."
)
AppSyncLogger.debug(
"[StarscreamAdapter] Manually send disconnect."
)
let error = ConnectionProviderError.connection("WatchOS Error", nil)
delegate?.websocketDidDisconnect(provider: self, error: error)
} else {
AppSyncLogger.debug(
"[StarscreamAdapter] watchOS subscriptions are connected within 3s."
)
}
}

}
#endif
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class AppSyncSubscriptionConnectionErrorHandlerTests: XCTestCase {
XCTAssertEqual(connection.subscriptionState, .subscribed)
XCTAssertNotNil(connectionProvider.listener)

let connectionError = ConnectionProviderError.connection
let connectionError = ConnectionProviderError.connection(nil, nil)
connection.handleError(error: connectionError)
wait(for: [failedEvent], timeout: 5)
XCTAssertEqual(connection.subscriptionState, .notSubscribed)
Expand Down Expand Up @@ -304,7 +304,7 @@ class AppSyncSubscriptionConnectionErrorHandlerTests: XCTestCase {
XCTAssertEqual(connection.subscriptionState, .subscribed)
XCTAssertNotNil(connectionProvider.listener)

let connectionError = ConnectionProviderError.connection
let connectionError = ConnectionProviderError.connection(nil, nil)
connection.handleError(error: connectionError)
wait(for: [connectedOnRetryExpectation], timeout: 5)
XCTAssertEqual(connection.subscriptionState, .subscribed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class MockConnectionProvider: ConnectionProvider {

func connect() {
guard validConnection else {
listener?(.error(ConnectionProviderError.connection))
listener?(.error(ConnectionProviderError.connection(nil, nil)))
return
}

Expand All @@ -39,7 +39,7 @@ class MockConnectionProvider: ConnectionProvider {
func write(_ message: AppSyncMessage) {

guard validConnection else {
listener?(.error(ConnectionProviderError.connection))
listener?(.error(ConnectionProviderError.connection(nil, nil)))
return
}

Expand Down Expand Up @@ -70,7 +70,7 @@ class MockConnectionProvider: ConnectionProvider {

func disconnect() {
guard validConnection else {
listener?(.error(ConnectionProviderError.connection))
listener?(.error(ConnectionProviderError.connection(nil, nil)))
return
}

Expand Down