@@ -14,7 +14,34 @@ public struct RealtimeChannelConfig: Sendable {
1414 public var presence : PresenceJoinConfig
1515}
1616
17- public actor RealtimeChannelV2 {
17+ struct Socket : Sendable {
18+ var status : @Sendable ( ) -> RealtimeClientV2 . Status
19+ var options : @Sendable ( ) -> RealtimeClientOptions
20+ var accessToken : @Sendable ( ) -> String ?
21+ var makeRef : @Sendable ( ) -> Int
22+
23+ var connect : @Sendable ( ) async -> Void
24+ var addChannel : @Sendable ( _ channel: RealtimeChannelV2 ) -> Void
25+ var removeChannel : @Sendable ( _ channel: RealtimeChannelV2 ) async -> Void
26+ var push : @Sendable ( _ message: RealtimeMessageV2 ) async -> Void
27+ }
28+
29+ extension Socket {
30+ init ( client: RealtimeClientV2 ) {
31+ self . init (
32+ status: { [ weak client] in client? . status ?? . disconnected } ,
33+ options: { [ weak client] in client? . options ?? . init( ) } ,
34+ accessToken: { [ weak client] in client? . mutableState. accessToken } ,
35+ makeRef: { [ weak client] in client? . makeRef ( ) ?? 0 } ,
36+ connect: { [ weak client] in await client? . connect ( ) } ,
37+ addChannel: { [ weak client] in client? . addChannel ( $0) } ,
38+ removeChannel: { [ weak client] in await client? . removeChannel ( $0) } ,
39+ push: { [ weak client] in await client? . push ( $0) }
40+ )
41+ }
42+ }
43+
44+ public final class RealtimeChannelV2 : Sendable {
1845 public typealias Subscription = ObservationToken
1946
2047 public enum Status : Sendable {
@@ -24,24 +51,22 @@ public actor RealtimeChannelV2 {
2451 case unsubscribing
2552 }
2653
27- weak var socket : RealtimeClientV2 ? {
28- didSet {
29- assert ( oldValue == nil , " socket should not be modified once set " )
30- }
54+ struct MutableState {
55+ var clientChanges : [ PostgresJoinConfig ] = [ ]
56+ var joinRef : String ?
57+ var pushes : [ String : PushV2 ] = [ : ]
3158 }
3259
60+ private let mutableState = LockIsolated ( MutableState ( ) )
61+
3362 let topic : String
3463 let config : RealtimeChannelConfig
3564 let logger : ( any SupabaseLogger ) ?
65+ let socket : Socket
3666
3767 private let callbackManager = CallbackManager ( )
38-
3968 private let statusEventEmitter = EventEmitter < Status > ( initialEvent: . unsubscribed)
4069
41- private var clientChanges : [ PostgresJoinConfig ] = [ ]
42- private var joinRef : String ?
43- private var pushes : [ String : PushV2 ] = [ : ]
44-
4570 public private( set) var status : Status {
4671 get { statusEventEmitter. lastEvent }
4772 set { statusEventEmitter. emit ( newValue) }
@@ -54,13 +79,13 @@ public actor RealtimeChannelV2 {
5479 init (
5580 topic: String ,
5681 config: RealtimeChannelConfig ,
57- socket: RealtimeClientV2 ,
82+ socket: Socket ,
5883 logger: ( any SupabaseLogger ) ?
5984 ) {
60- self . socket = socket
6185 self . topic = topic
6286 self . config = config
6387 self . logger = logger
88+ self . socket = socket
6489 }
6590
6691 deinit {
@@ -69,32 +94,33 @@ public actor RealtimeChannelV2 {
6994
7095 /// Subscribes to the channel
7196 public func subscribe( ) async {
72- if await socket? . status != . connected {
73- if socket? . options. connectOnSubscribe != true {
97+ if socket. status ( ) != . connected {
98+ if socket. options ( ) . connectOnSubscribe != true {
7499 fatalError (
75100 " You can't subscribe to a channel while the realtime client is not connected. Did you forget to call `realtime.connect()`? "
76101 )
77102 }
78- await socket? . connect ( )
103+ await socket. connect ( )
79104 }
80105
81- await socket? . addChannel ( self )
106+ socket. addChannel ( self )
82107
83108 status = . subscribing
84109 logger? . debug ( " subscribing to channel \( topic) " )
85110
86111 let joinConfig = RealtimeJoinConfig (
87112 broadcast: config. broadcast,
88113 presence: config. presence,
89- postgresChanges: clientChanges
114+ postgresChanges: mutableState . clientChanges
90115 )
91116
92- let payload = await RealtimeJoinPayload (
117+ let payload = RealtimeJoinPayload (
93118 config: joinConfig,
94- accessToken: socket? . accessToken
119+ accessToken: socket. accessToken ( )
95120 )
96121
97- joinRef = await socket? . makeRef ( ) . description
122+ let joinRef = socket. makeRef ( ) . description
123+ mutableState. withValue { $0. joinRef = joinRef }
98124
99125 logger? . debug ( " subscribing to channel with body: \( joinConfig) " )
100126
@@ -109,7 +135,7 @@ public actor RealtimeChannelV2 {
109135 )
110136
111137 do {
112- try await withTimeout ( interval: socket? . options. timeoutInterval ?? 10 ) { [ self ] in
138+ try await withTimeout ( interval: socket. options ( ) . timeoutInterval) { [ self ] in
113139 _ = await statusChange. first { @Sendable in $0 == . subscribed }
114140 }
115141 } catch {
@@ -128,8 +154,8 @@ public actor RealtimeChannelV2 {
128154
129155 await push (
130156 RealtimeMessageV2 (
131- joinRef: joinRef,
132- ref: socket? . makeRef ( ) . description,
157+ joinRef: mutableState . joinRef,
158+ ref: socket. makeRef ( ) . description,
133159 topic: topic,
134160 event: ChannelEvent . leave,
135161 payload: [ : ]
@@ -141,8 +167,8 @@ public actor RealtimeChannelV2 {
141167 logger? . debug ( " Updating auth token for channel \( topic) " )
142168 await push (
143169 RealtimeMessageV2 (
144- joinRef: joinRef,
145- ref: socket? . makeRef ( ) . description,
170+ joinRef: mutableState . joinRef,
171+ ref: socket. makeRef ( ) . description,
146172 topic: topic,
147173 event: ChannelEvent . accessToken,
148174 payload: [ " access_token " : . string( jwt) ]
@@ -162,8 +188,8 @@ public actor RealtimeChannelV2 {
162188
163189 await push (
164190 RealtimeMessageV2 (
165- joinRef: joinRef,
166- ref: socket? . makeRef ( ) . description,
191+ joinRef: mutableState . joinRef,
192+ ref: socket. makeRef ( ) . description,
167193 topic: topic,
168194 event: ChannelEvent . broadcast,
169195 payload: [
@@ -187,8 +213,8 @@ public actor RealtimeChannelV2 {
187213
188214 await push (
189215 RealtimeMessageV2 (
190- joinRef: joinRef,
191- ref: socket? . makeRef ( ) . description,
216+ joinRef: mutableState . joinRef,
217+ ref: socket. makeRef ( ) . description,
192218 topic: topic,
193219 event: ChannelEvent . presence,
194220 payload: [
@@ -203,8 +229,8 @@ public actor RealtimeChannelV2 {
203229 public func untrack( ) async {
204230 await push (
205231 RealtimeMessageV2 (
206- joinRef: joinRef,
207- ref: socket? . makeRef ( ) . description,
232+ joinRef: mutableState . joinRef,
233+ ref: socket. makeRef ( ) . description,
208234 topic: topic,
209235 event: ChannelEvent . presence,
210236 payload: [
@@ -329,7 +355,7 @@ public actor RealtimeChannelV2 {
329355 Task { [ weak self] in
330356 guard let self else { return }
331357
332- await socket? . removeChannel ( self )
358+ await socket. removeChannel ( self )
333359 logger? . debug ( " Unsubscribed from channel \( message. topic) " )
334360 }
335361
@@ -439,7 +465,9 @@ public actor RealtimeChannelV2 {
439465 filter: filter
440466 )
441467
442- clientChanges. append ( config)
468+ mutableState. withValue {
469+ $0. clientChanges. append ( config)
470+ }
443471
444472 let id = callbackManager. addPostgresCallback ( filter: config, callback: callback)
445473 return Subscription { [ weak callbackManager, logger] in
@@ -464,14 +492,18 @@ public actor RealtimeChannelV2 {
464492 private func push( _ message: RealtimeMessageV2 ) async -> PushStatus {
465493 let push = PushV2 ( channel: self , message: message)
466494 if let ref = message. ref {
467- pushes [ ref] = push
495+ mutableState. withValue {
496+ $0. pushes [ ref] = push
497+ }
468498 }
469499 return await push. send ( )
470500 }
471501
472502 private func didReceiveReply( ref: String , status: String ) {
473503 Task {
474- let push = pushes. removeValue ( forKey: ref)
504+ let push = mutableState. withValue {
505+ $0. pushes. removeValue ( forKey: ref)
506+ }
475507 await push? . didReceive ( status: PushStatus ( rawValue: status) ?? . ok)
476508 }
477509 }
0 commit comments