-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathConnection.swift
More file actions
167 lines (140 loc) · 5.59 KB
/
Connection.swift
File metadata and controls
167 lines (140 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import Ably
/**
* Represents a connection to Ably.
*/
@MainActor
public protocol Connection: AnyObject, Sendable {
// swiftlint:disable:next missing_docs
associatedtype StatusSubscription: AblyChat.StatusSubscription
/**
* The current status of the connection.
*/
var status: ConnectionStatus { get }
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
/**
* The current error, if any, that caused the connection to enter the current status.
*/
var error: ARTErrorInfo? { get }
/**
* Subscribes a given listener to a connection status changes.
*
* - Parameters:
* - callback: The listener closure for capturing ``ConnectionStatusChange`` events.
*
* - Returns: A subscription that can be used to unsubscribe from ``ConnectionStatusChange`` events.
*/
@discardableResult
func onStatusChange(_ callback: @escaping @MainActor (ConnectionStatusChange) -> Void) -> StatusSubscription
}
/// `AsyncSequence` variant of `Connection` status changes.
public extension Connection {
/**
* Subscribes a given listener to a connection status changes.
*
* - Parameters:
* - bufferingPolicy: The ``BufferingPolicy`` for the created subscription.
*
* - Returns: A subscription `AsyncSequence` that can be used to iterate through ``ConnectionStatusChange`` events.
*/
func onStatusChange(bufferingPolicy: BufferingPolicy) -> SubscriptionAsyncSequence<ConnectionStatusChange> {
let subscriptionAsyncSequence = SubscriptionAsyncSequence<ConnectionStatusChange>(bufferingPolicy: bufferingPolicy)
let subscription = onStatusChange { statusChange in
subscriptionAsyncSequence.emit(statusChange)
}
subscriptionAsyncSequence.addTerminationHandler {
Task { @MainActor in
subscription.off()
}
}
return subscriptionAsyncSequence
}
/// Same as calling ``onStatusChange(bufferingPolicy:)`` with ``BufferingPolicy/unbounded``.
func onStatusChange() -> SubscriptionAsyncSequence<ConnectionStatusChange> {
onStatusChange(bufferingPolicy: .unbounded)
}
}
/**
* The different states that the connection can be in through its lifecycle.
*/
public enum ConnectionStatus: Sendable {
// (CHA-CS1a) The INITIALIZED status is a default status when the realtime client is first initialized. This value will only (likely) be seen if the realtime client doesn’t have autoconnect turned on.
/**
* A temporary state for when the library is first initialized.
*/
case initialized
// (CHA-CS1b) The CONNECTING status is used when the client is in the process of connecting to Ably servers.
/**
* The library is currently connecting to Ably.
*/
case connecting
// (CHA-CS1c) The CONNECTED status is used when the client connected to Ably servers.
/**
* The library is currently connected to Ably.
*/
case connected
// (CHA-CS1d) The DISCONNECTED status is used when the client is not currently connected to Ably servers. This state may be temporary as the underlying Realtime SDK seeks to reconnect.
/**
* The library is currently disconnected from Ably, but will attempt to reconnect.
*/
case disconnected
// (CHA-CS1e) The SUSPENDED status is used when the client is in an extended state of disconnection, but will attempt to reconnect.
/**
* The library is in an extended state of disconnection, but will attempt to reconnect.
*/
case suspended
// (CHA-CS1f) The FAILED status is used when the client is disconnected from the Ably servers due to some non-retriable failure such as authentication failure. It will not attempt to reconnect.
/**
* The library is currently disconnected from Ably and will not attempt to reconnect.
*/
case failed
internal static func fromRealtimeConnectionState(_ state: ARTRealtimeConnectionState) -> Self {
switch state {
case .initialized:
.initialized
case .connecting:
.connecting
case .connected:
.connected
case .disconnected:
.disconnected
case .suspended:
.suspended
case .failed, .closing, .closed:
.failed
@unknown default:
.failed
}
}
}
/**
* Represents a change in the status of the connection.
*/
public struct ConnectionStatusChange: Sendable {
/**
* The new status of the connection.
*/
public var current: ConnectionStatus
/**
* The previous status of the connection.
*/
public var previous: ConnectionStatus
// TODO: (https://github.com/ably-labs/ably-chat-swift/issues/12): consider how to avoid the need for an unwrap
/**
* An error that provides a reason why the connection has
* entered the new status, if applicable.
*/
public var error: ARTErrorInfo?
/**
* The time in milliseconds that the client will wait before attempting to reconnect.
*/
public var retryIn: TimeInterval?
/// Memberwise initializer to create a `ConnectionStatusChange`.
///
/// - Note: You should not need to use this initializer when using the Chat SDK. It is exposed only to allow users to create mock versions of the SDK's protocols.
public init(current: ConnectionStatus, previous: ConnectionStatus, error: ARTErrorInfo? = nil, retryIn: TimeInterval?) {
self.current = current
self.previous = previous
self.error = error
self.retryIn = retryIn
}
}