@@ -25,9 +25,9 @@ public class WebSocketTransport {
2525 public static var provider : ApolloWebSocketClient . Type = ApolloWebSocket . self
2626 public weak var delegate : WebSocketTransportDelegate ?
2727
28- var reconnect = false
28+ let reconnect : Atomic < Bool > = Atomic ( false )
2929 var websocket : ApolloWebSocketClient
30- var error : Error ? = nil
30+ let error : Atomic < Error ? > = Atomic ( nil )
3131 let serializationFormat = JSONSerializationFormat . self
3232 private let requestCreator : RequestCreator
3333
@@ -40,10 +40,11 @@ public class WebSocketTransport {
4040
4141 private var subscribers = [ String : ( Result < JSONObject , Error > ) -> Void ] ( )
4242 private var subscriptions : [ String : String ] = [ : ]
43+ private let processingQueue = DispatchQueue ( label: " com.apollographql.WebSocketTransport " )
4344
4445 private let sendOperationIdentifiers : Bool
4546 private let reconnectionInterval : TimeInterval
46- fileprivate var sequenceNumber = 0
47+ fileprivate let sequenceNumberCounter = Atomic < Int > ( 0 )
4748 fileprivate var reconnected = false
4849
4950 /// NOTE: Setting this won't override immediately if the socket is still connected, only on reconnection.
@@ -87,6 +88,7 @@ public class WebSocketTransport {
8788 self . websocket. request. setValue ( self . clientVersion, forHTTPHeaderField: WebSocketTransport . headerFieldNameClientVersion)
8889 self . websocket. delegate = self
8990 self . websocket. connect ( )
91+ self . websocket. callbackQueue = processingQueue
9092 }
9193
9294 public func isConnected( ) -> Bool {
@@ -174,7 +176,7 @@ public class WebSocketTransport {
174176 }
175177
176178 public func initServer( reconnect: Bool = true ) {
177- self . reconnect = reconnect
179+ self . reconnect. value = reconnect
178180 self . acked = false
179181
180182 if let str = OperationMessage ( payload: self . connectingPayload, type: . connectionInit) . rawMessage {
@@ -184,12 +186,17 @@ public class WebSocketTransport {
184186 }
185187
186188 public func closeConnection( ) {
187- self . reconnect = false
188- if let str = OperationMessage ( type: . connectionTerminate) . rawMessage {
189- write ( str)
189+ self . reconnect. value = false
190+
191+ let str = OperationMessage ( type: . connectionTerminate) . rawMessage
192+ processingQueue. async {
193+ if let str = str {
194+ self . write ( str)
195+ }
196+
197+ self . queue. removeAll ( )
198+ self . subscriptions. removeAll ( )
190199 }
191- self . queue. removeAll ( )
192- self . subscriptions. removeAll ( )
193200 }
194201
195202 private func write( _ str: String , force forced: Bool = false , id: Int ? = nil ) {
@@ -213,43 +220,44 @@ public class WebSocketTransport {
213220 websocket. delegate = nil
214221 }
215222
216- private func nextSequenceNumber( ) -> Int {
217- sequenceNumber += 1
218- return sequenceNumber
219- }
220-
221223 func sendHelper< Operation: GraphQLOperation > ( operation: Operation , resultHandler: @escaping ( _ result: Result < JSONObject , Error > ) -> Void ) -> String ? {
222224 let body = requestCreator. requestBody ( for: operation, sendOperationIdentifiers: self . sendOperationIdentifiers)
223- let sequenceNumber = " \( nextSequenceNumber ( ) ) "
225+ let sequenceNumber = " \( sequenceNumberCounter . increment ( ) ) "
224226
225227 guard let message = OperationMessage ( payload: body, id: sequenceNumber) . rawMessage else {
226228 return nil
227229 }
228-
229- write ( message)
230+
231+ processingQueue. async {
232+ self . write ( message)
230233
231- subscribers [ sequenceNumber] = resultHandler
232- if operation. operationType == . subscription {
233- subscriptions [ sequenceNumber] = message
234+ self . subscribers [ sequenceNumber] = resultHandler
235+ if operation. operationType == . subscription {
236+ self . subscriptions [ sequenceNumber] = message
237+ }
234238 }
235239
236240 return sequenceNumber
237241 }
238242
239243 public func unsubscribe( _ subscriptionId: String ) {
240- if let str = OperationMessage ( id: subscriptionId, type: . stop) . rawMessage {
241- write ( str)
244+ let str = OperationMessage ( id: subscriptionId, type: . stop) . rawMessage
245+
246+ processingQueue. async {
247+ if let str = str {
248+ self . write ( str)
249+ }
250+ self . subscribers. removeValue ( forKey: subscriptionId)
251+ self . subscriptions. removeValue ( forKey: subscriptionId)
242252 }
243- subscribers. removeValue ( forKey: subscriptionId)
244- subscriptions. removeValue ( forKey: subscriptionId)
245253 }
246254}
247255
248256// MARK: - HTTPNetworkTransport conformance
249257
250258extension WebSocketTransport : NetworkTransport {
251259 public func send< Operation> ( operation: Operation , completionHandler: @escaping ( _ result: Result < GraphQLResponse < Operation > , Error > ) -> Void ) -> Cancellable {
252- if let error = self . error {
260+ if let error = self . error. value {
253261 completionHandler ( . failure( error) )
254262 return EmptyCancellable ( )
255263 }
@@ -271,7 +279,7 @@ extension WebSocketTransport: NetworkTransport {
271279extension WebSocketTransport : WebSocketDelegate {
272280
273281 public func websocketDidConnect( socket: WebSocketClient ) {
274- self . error = nil
282+ self . error. value = nil
275283 initServer ( )
276284 if reconnected {
277285 self . delegate? . webSocketTransportDidReconnect ( self )
@@ -290,16 +298,16 @@ extension WebSocketTransport: WebSocketDelegate {
290298 public func websocketDidDisconnect( socket: WebSocketClient , error: Error ? ) {
291299 // report any error to all subscribers
292300 if let error = error {
293- self . error = WebSocketError ( payload: nil , error: error, kind: . networkError)
301+ self . error. value = WebSocketError ( payload: nil , error: error, kind: . networkError)
294302 self . notifyErrorAllHandlers ( error)
295303 } else {
296- self . error = nil
304+ self . error. value = nil
297305 }
298306
299- self . delegate? . webSocketTransport ( self , didDisconnectWithError: self . error)
307+ self . delegate? . webSocketTransport ( self , didDisconnectWithError: self . error. value )
300308 acked = false // need new connect and ack before sending
301309
302- if reconnect {
310+ if reconnect. value {
303311 DispatchQueue . main. asyncAfter ( deadline: . now( ) + reconnectionInterval) {
304312 self . websocket. connect ( )
305313 }
0 commit comments