-
Notifications
You must be signed in to change notification settings - Fork 0
Compatibility changes for StreamChat migration #29
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
Changes from all commits
a2d531b
4d50396
c0e4527
986c20d
7e5f478
e2ad397
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,7 +35,7 @@ extension Data { | |
| /// | ||
| /// - Returns: Gzip-compressed `Data` instance. | ||
| /// - Throws: `GzipError` | ||
| public func gzipped() throws -> Data { | ||
| func gzipped() throws -> Data { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to be public anymore (previous PR did that) |
||
| guard !isEmpty else { | ||
| return Data() | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ extension Notification { | |
| /// | ||
| /// Basically, it's a wrapper over legacy monitor based on `Reachability` (iOS 11 only) | ||
| /// and default monitor based on `Network`.`NWPathMonitor` (iOS 12+). | ||
| public final class InternetConnection: @unchecked Sendable { | ||
| open class InternetConnection: @unchecked Sendable { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test tools need to subclass it on the chat side |
||
| /// The current Internet connection status. | ||
| @Published private(set) var status: InternetConnectionStatus { | ||
| didSet { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| import Combine | ||
| import Foundation | ||
|
|
||
| public protocol StreamTimer { | ||
| public protocol TimerScheduling { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naming conflict: did not know there was StreamTimer in the UIKit module and Timer was conflicting with Foundation. |
||
| /// Schedules a new timer. | ||
| /// | ||
| /// - Parameters: | ||
|
|
@@ -33,7 +33,7 @@ public protocol StreamTimer { | |
| static func currentTime() -> Date | ||
| } | ||
|
|
||
| extension StreamTimer { | ||
| extension TimerScheduling { | ||
| public static func currentTime() -> Date { | ||
| Date() | ||
| } | ||
|
|
@@ -58,7 +58,7 @@ extension DispatchWorkItem: TimerControl {} | |
| extension DispatchWorkItem: @retroactive @unchecked Sendable {} | ||
|
|
||
| /// Default real-world implementations of timers. | ||
| public struct DefaultTimer: StreamTimer { | ||
| public struct DefaultTimer: TimerScheduling { | ||
| @discardableResult | ||
| public static func schedule( | ||
| timeInterval: TimeInterval, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,7 @@ public class IOSBackgroundTaskScheduler: BackgroundTaskScheduler, @unchecked Sen | |
|
|
||
| @MainActor | ||
| public func beginTask(expirationHandler: (@Sendable () -> Void)?) -> Bool { | ||
| endTask() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From Chat |
||
| activeBackgroundTask = app?.beginBackgroundTask { [weak self] in | ||
| self?._endTask() | ||
| expirationHandler?() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,10 @@ import CoreData | |
| import Foundation | ||
|
|
||
| /// The type that keeps track of active chat components and asks them to reconnect when it's needed | ||
| public protocol ConnectionRecoveryHandler: ConnectionStateDelegate, Sendable {} | ||
| public protocol ConnectionRecoveryHandler: ConnectionStateDelegate, Sendable { | ||
| func start() | ||
| func stop() | ||
| } | ||
|
Comment on lines
+9
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chat needs this to support some flows |
||
|
|
||
| /// The type is designed to obtain missing events that happened in watched channels while user | ||
| /// was not connected to the web-socket. | ||
|
|
@@ -24,7 +27,7 @@ public final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler, | |
| private let eventNotificationCenter: EventNotificationCenter | ||
| private let backgroundTaskScheduler: BackgroundTaskScheduler? | ||
| private let internetConnection: InternetConnection | ||
| private let reconnectionTimerType: StreamTimer.Type | ||
| private let reconnectionTimerType: TimerScheduling.Type | ||
| private let keepConnectionAliveInBackground: Bool | ||
| private nonisolated(unsafe) var reconnectionStrategy: RetryStrategy | ||
| private nonisolated(unsafe) var reconnectionTimer: TimerControl? | ||
|
|
@@ -38,7 +41,7 @@ public final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler, | |
| backgroundTaskScheduler: BackgroundTaskScheduler?, | ||
| internetConnection: InternetConnection, | ||
| reconnectionStrategy: RetryStrategy, | ||
| reconnectionTimerType: StreamTimer.Type, | ||
| reconnectionTimerType: TimerScheduling.Type, | ||
| keepConnectionAliveInBackground: Bool | ||
| ) { | ||
| self.init( | ||
|
|
@@ -51,7 +54,6 @@ public final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler, | |
| keepConnectionAliveInBackground: keepConnectionAliveInBackground, | ||
| reconnectionPolicies: [ | ||
| WebSocketAutomaticReconnectionPolicy(webSocketClient), | ||
| InternetAvailabilityReconnectionPolicy(internetConnection), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is interesting, I struggled with reconnection when building and running demo app and as soon as I dropped this, things started to work. I spent a day on this, so not planning to spend more time on this. Chat's recovery handler also did not check for internet connection (makes sense since the monitor is not 100% accurate and URLRequest can trigger connection establishment even when the monitor says there is no connection. This is also what Apple suggest (can't remember which WWDC on top of my head)) |
||
| BackgroundStateReconnectionPolicy(backgroundTaskScheduler) | ||
| ] | ||
| ) | ||
|
|
@@ -63,7 +65,7 @@ public final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler, | |
| backgroundTaskScheduler: BackgroundTaskScheduler?, | ||
| internetConnection: InternetConnection, | ||
| reconnectionStrategy: RetryStrategy, | ||
| reconnectionTimerType: StreamTimer.Type, | ||
| reconnectionTimerType: TimerScheduling.Type, | ||
| keepConnectionAliveInBackground: Bool, | ||
| reconnectionPolicies: [AutomaticReconnectionPolicy] | ||
| ) { | ||
|
|
@@ -75,14 +77,22 @@ public final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler, | |
| self.reconnectionTimerType = reconnectionTimerType | ||
| self.keepConnectionAliveInBackground = keepConnectionAliveInBackground | ||
| self.reconnectionPolicies = reconnectionPolicies | ||
|
|
||
| subscribeOnNotifications() | ||
| start() | ||
| } | ||
|
|
||
| deinit { | ||
| public func start() { | ||
| subscribeOnNotifications() | ||
| } | ||
|
|
||
| public func stop() { | ||
| unsubscribeFromNotifications() | ||
| cancelReconnectionTimer() | ||
| } | ||
|
|
||
| deinit { | ||
| stop() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Subscriptions | ||
|
|
@@ -94,21 +104,19 @@ private extension DefaultConnectionRecoveryHandler { | |
| onEnteringBackground: { [weak self] in self?.appDidEnterBackground() }, | ||
| onEnteringForeground: { [weak self] in self?.appDidBecomeActive() } | ||
| ) | ||
|
|
||
| internetConnection.notificationCenter.addObserver( | ||
| self, | ||
| selector: #selector(internetConnectionAvailabilityDidChange(_:)), | ||
| name: .internetConnectionAvailabilityDidChange, | ||
| object: nil | ||
| ) | ||
| } | ||
| internetConnection.notificationCenter.addObserver( | ||
| self, | ||
| selector: #selector(internetConnectionAvailabilityDidChange(_:)), | ||
| name: .internetConnectionAvailabilityDidChange, | ||
| object: nil | ||
| ) | ||
| } | ||
|
|
||
| func unsubscribeFromNotifications() { | ||
| Task { @MainActor [backgroundTaskScheduler] in | ||
| backgroundTaskScheduler?.stopListeningForAppStateUpdates() | ||
| } | ||
|
|
||
| internetConnection.notificationCenter.removeObserver( | ||
| self, | ||
| name: .internetConnectionStatusDidChange, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,23 +42,24 @@ public extension ConnectionStatus { | |
| self = .disconnecting | ||
|
|
||
| case let .disconnected(source): | ||
| let isWaitingForReconnect = webSocketConnectionState.isAutomaticReconnectionEnabled || source.serverError? | ||
| .isInvalidTokenError == true | ||
|
|
||
| let isWaitingForReconnect = webSocketConnectionState.isAutomaticReconnectionEnabled | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From chat |
||
| self = isWaitingForReconnect ? .connecting : .disconnected(error: source.serverError) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| typealias ConnectionId = String | ||
| public typealias ConnectionId = String | ||
|
|
||
| /// A web socket connection state. | ||
| public enum WebSocketConnectionState: Equatable { | ||
| public enum WebSocketConnectionState: Equatable, Sendable { | ||
| /// Provides additional information about the source of disconnecting. | ||
| public enum DisconnectionSource: Equatable { | ||
| public indirect enum DisconnectionSource: Equatable, Sendable { | ||
| /// A user initiated web socket disconnecting. | ||
| case userInitiated | ||
|
|
||
| /// The connection timed out while trying to connect. | ||
| case timeout(from: WebSocketConnectionState) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chat needs this state for special reconnection flows |
||
|
|
||
| /// A server initiated web socket disconnecting, an optional error object is provided. | ||
| case serverInitiated(error: ClientError? = nil) | ||
|
|
||
|
|
@@ -95,7 +96,7 @@ public enum WebSocketConnectionState: Equatable { | |
| case disconnecting(source: DisconnectionSource) | ||
|
|
||
| /// Checks if the connection state is connected. | ||
| var isConnected: Bool { | ||
| public var isConnected: Bool { | ||
| if case .connected = self { | ||
| return true | ||
| } | ||
|
|
@@ -141,6 +142,8 @@ public enum WebSocketConnectionState: Equatable { | |
| return true | ||
| case .userInitiated: | ||
| return false | ||
| case .timeout: | ||
| return false | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From Chat's implementation