@@ -20,8 +20,13 @@ public final class RealtimeClientV2: Sendable {
20
20
var accessToken : String ?
21
21
var ref = 0
22
22
var pendingHeartbeatRef : Int ?
23
+
24
+ /// Long-running task that keeps sending heartbeat messages.
23
25
var heartbeatTask : Task < Void , Never > ?
26
+
27
+ /// Long-running task for listening for incoming messages from WebSocket.
24
28
var messageTask : Task < Void , Never > ?
29
+
25
30
var connectionTask : Task < Void , Never > ?
26
31
var channels : [ String : RealtimeChannelV2 ] = [ : ]
27
32
var sendBuffer : [ @Sendable ( ) async -> Void ] = [ ]
@@ -34,13 +39,14 @@ public final class RealtimeClientV2: Sendable {
34
39
let http : any HTTPClientType
35
40
let apikey : String ?
36
41
42
+ /// All managed channels indexed by their topics.
37
43
public var channels : [ String : RealtimeChannelV2 ] {
38
44
mutableState. channels
39
45
}
40
46
41
47
private let statusEventEmitter = EventEmitter < RealtimeClientStatus > ( initialEvent: . disconnected)
42
48
43
- /// AsyncStream that emits when connection status change .
49
+ /// Listen for connection status changes .
44
50
///
45
51
/// You can also use ``onStatusChange(_:)`` for a closure based method.
46
52
public var statusChange : AsyncStream < RealtimeClientStatus > {
@@ -198,6 +204,13 @@ public final class RealtimeClientV2: Sendable {
198
204
await connect ( reconnect: true )
199
205
}
200
206
207
+ /// Creates a new channel and bind it to this client.
208
+ /// - Parameters:
209
+ /// - topic: Channel's topic.
210
+ /// - options: Configuration options for the channel.
211
+ /// - Returns: Channel instance.
212
+ ///
213
+ /// - Note: This method doesn't subscribe to the channel, call ``RealtimeChannelV2/subscribe()`` on the returned channel instance.
201
214
public func channel(
202
215
_ topic: String ,
203
216
options: @Sendable ( inout RealtimeChannelConfig ) -> Void = { _ in }
@@ -223,6 +236,9 @@ public final class RealtimeClientV2: Sendable {
223
236
}
224
237
}
225
238
239
+ /// Unsubscribe and removes channel.
240
+ ///
241
+ /// If there is no channel left, client is disconnected.
226
242
public func removeChannel( _ channel: RealtimeChannelV2 ) async {
227
243
if channel. status == . subscribed {
228
244
await channel. unsubscribe ( )
@@ -238,6 +254,7 @@ public final class RealtimeClientV2: Sendable {
238
254
}
239
255
}
240
256
257
+ /// Unsubscribes and removes all channels.
241
258
public func removeAllChannels( ) async {
242
259
await withTaskGroup ( of: Void . self) { group in
243
260
for channel in channels. values {
@@ -327,6 +344,7 @@ public final class RealtimeClientV2: Sendable {
327
344
}
328
345
}
329
346
347
+ /// Disconnects client.
330
348
public func disconnect( ) {
331
349
options. logger? . debug ( " Closing WebSocket connection " )
332
350
mutableState. withValue {
@@ -388,13 +406,14 @@ public final class RealtimeClientV2: Sendable {
388
406
try Task . checkCancellation ( )
389
407
try await self ? . ws. send ( message)
390
408
} catch {
391
- self ? . options. logger? . error ( """
392
- Failed to send message:
393
- \( message)
394
-
395
- Error:
396
- \( error)
397
- """ )
409
+ self ? . options. logger? . error (
410
+ """
411
+ Failed to send message:
412
+ \( message)
413
+
414
+ Error:
415
+ \( error)
416
+ """ )
398
417
}
399
418
}
400
419
@@ -470,3 +489,31 @@ public final class RealtimeClientV2: Sendable {
470
489
url. appendingPathComponent ( " api/broadcast " )
471
490
}
472
491
}
492
+
493
+ import Network
494
+
495
+ final class NetworkMonitor : @unchecked Sendable {
496
+ static let shared = NetworkMonitor ( )
497
+
498
+ private let monitor : NWPathMonitor
499
+ private let queue = DispatchQueue ( label: " NetworkMonitor " )
500
+
501
+ private( set) var isConnected : Bool = false
502
+
503
+ private init ( ) {
504
+ monitor = NWPathMonitor ( )
505
+ }
506
+
507
+ func start( _ onChange: ( @Sendable ( ) -> Void ) ? = nil ) {
508
+ monitor. pathUpdateHandler = { [ weak self] path in
509
+ self ? . isConnected = path. status != . unsatisfied
510
+ onChange ? ( )
511
+ }
512
+
513
+ monitor. start ( queue: queue)
514
+ }
515
+
516
+ func stop( ) {
517
+ monitor. cancel ( )
518
+ }
519
+ }
0 commit comments