@@ -7,24 +7,23 @@ open class Realtime : Service {
7
7
8
8
private let TYPE_ERROR = "error"
9
9
private let TYPE_EVENT = "event"
10
- private let DEBOUNCE_MILLIS = 1
10
+ private let DEBOUNCE_NANOS = 1_000_000
11
11
12
12
private var socketClient: WebSocketClient? = nil
13
13
private var activeChannels = Set<String >()
14
14
private var activeSubscriptions = [Int: RealtimeCallback]()
15
15
16
16
let connectSync = DispatchQueue(label: "ConnectSync")
17
- let callbackSync = DispatchQueue(label: "CallbackSync")
18
17
19
18
private var subCallDepth = 0
20
19
private var reconnectAttempts = 0
21
20
private var subscriptionsCounter = 0
22
21
private var reconnect = true
23
22
24
- private func createSocket() {
23
+ private func createSocket() async throws {
25
24
guard activeChannels.count > 0 else {
26
25
reconnect = false
27
- closeSocket()
26
+ try await closeSocket()
28
27
return
29
28
}
30
29
@@ -38,17 +37,31 @@ open class Realtime : Service {
38
37
39
38
if (socketClient != nil) {
40
39
reconnect = false
41
- closeSocket()
42
- } else {
43
- socketClient = WebSocketClient(url, tlsEnabled: !client.selfSigned, delegate: self)!
40
+ try await closeSocket()
44
41
}
45
42
46
- try! socketClient?.connect()
43
+ socketClient = WebSocketClient(
44
+ url,
45
+ tlsEnabled: !client.selfSigned,
46
+ delegate: self
47
+ )
48
+
49
+ try await socketClient?.connect()
47
50
}
48
51
49
- private func closeSocket() {
50
- socketClient?.close()
51
- //socket?.close(RealtimeCode.POLICY_VIOLATION.value, null)
52
+ private func closeSocket() async throws {
53
+ guard let client = socketClient,
54
+ let group = client.threadGroup else {
55
+ return
56
+ }
57
+
58
+ if (client.isConnected) {
59
+ let promise = group.any().makePromise(of: Void.self)
60
+ client.close(promise: promise)
61
+ try await promise.futureResult.get()
62
+ }
63
+
64
+ try await group.shutdownGracefully()
52
65
}
53
66
54
67
private func getTimeout() -> Int {
@@ -63,8 +76,8 @@ open class Realtime : Service {
63
76
public func subscribe (
64
77
channel: String ,
65
78
callback: @escaping (RealtimeResponseEvent ) -> Void
66
- ) -> RealtimeSubscription {
67
- return subscribe(
79
+ ) async throws -> RealtimeSubscription {
80
+ return try await subscribe(
68
81
channels: [channel],
69
82
payloadType: String.self,
70
83
callback: callback
@@ -74,8 +87,8 @@ open class Realtime : Service {
74
87
public func subscribe(
75
88
channels: Set<String >,
76
89
callback: @escaping (RealtimeResponseEvent) -> Void
77
- ) -> RealtimeSubscription {
78
- return subscribe(
90
+ ) async throws -> RealtimeSubscription {
91
+ return try await subscribe(
79
92
channels: channels,
80
93
payloadType: String.self,
81
94
callback: callback
@@ -86,8 +99,8 @@ open class Realtime : Service {
86
99
channel: String,
87
100
payloadType: T.Type,
88
101
callback: @escaping (RealtimeResponseEvent) -> Void
89
- ) -> RealtimeSubscription {
90
- return subscribe(
102
+ ) async throws -> RealtimeSubscription {
103
+ return try await subscribe(
91
104
channels: [channel],
92
105
payloadType: T.self,
93
106
callback: callback
@@ -98,36 +111,38 @@ open class Realtime : Service {
98
111
channels: Set<String >,
99
112
payloadType: T.Type,
100
113
callback: @escaping (RealtimeResponseEvent) -> Void
101
- ) -> RealtimeSubscription {
114
+ ) async throws -> RealtimeSubscription {
102
115
subscriptionsCounter += 1
103
- let counter = subscriptionsCounter
116
+
117
+ let count = subscriptionsCounter
104
118
105
119
channels.forEach {
106
120
activeChannels.insert($0)
107
121
}
108
122
109
- activeSubscriptions[counter ] = RealtimeCallback(
123
+ activeSubscriptions[count ] = RealtimeCallback(
110
124
for: Set(channels),
111
- and : callback
125
+ with : callback
112
126
)
113
127
114
128
connectSync.sync {
115
129
subCallDepth+=1
116
130
}
117
131
118
- DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(DEBOUNCE_MILLIS)) {
119
- if (self.subCallDepth == 1) {
120
- self.createSocket()
121
- }
122
- self.connectSync.sync {
123
- self.subCallDepth-=1
124
- }
132
+ try await Task.sleep(nanoseconds: UInt64(DEBOUNCE_NANOS))
133
+
134
+ if self.subCallDepth == 1 {
135
+ try await self.createSocket()
136
+ }
137
+
138
+ connectSync.sync {
139
+ self.subCallDepth -= 1
125
140
}
126
141
127
142
return RealtimeSubscription {
128
- self.activeSubscriptions[counter ] = nil
143
+ self.activeSubscriptions[count ] = nil
129
144
self.cleanUp(channels: channels)
130
- self.createSocket()
145
+ try await self.createSocket()
131
146
}
132
147
}
133
148
@@ -163,7 +178,7 @@ extension Realtime: WebSocketClientDelegate {
163
178
}
164
179
}
165
180
166
- public func onClose(channel: Channel, data: Data) {
181
+ public func onClose(channel: Channel, data: Data) async throws {
167
182
if (!reconnect) {
168
183
reconnect = true
169
184
return
@@ -173,10 +188,11 @@ extension Realtime: WebSocketClientDelegate {
173
188
174
189
print("Realtime disconnected. Re-connecting in \(timeout / 1000) seconds.")
175
190
176
- DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(timeout)) {
177
- self.reconnectAttempts += 1
178
- self.createSocket()
179
- }
191
+ try await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000))
192
+
193
+ self.reconnectAttempts += 1
194
+
195
+ try await self.createSocket()
180
196
}
181
197
182
198
public func onError(error: Swift.Error?, status: HTTPResponseStatus?) {
@@ -188,16 +204,10 @@ extension Realtime: WebSocketClientDelegate {
188
204
}
189
205
190
206
func handleResponseEvent(from json: [String: Any]) {
191
- guard let data = json["data"] as? [String: Any] else {
192
- return
193
- }
194
- guard let channels = data["channels"] as? Array<String > else {
195
- return
196
- }
197
- guard let events = data["events"] as? Array<String > else {
198
- return
199
- }
200
- guard let payload = data["payload"] as? [String: Any] else {
207
+ guard let data = json["data"] as? [String: Any],
208
+ let channels = data["channels"] as? [String],
209
+ let events = data["events"] as? [String],
210
+ let payload = data["payload"] as? [String: Any] else {
201
211
return
202
212
}
203
213
guard channels.contains(where: { channel in
0 commit comments