Skip to content

Commit 2d62272

Browse files
committed
Further improve connection state management and reconnection approach
1 parent 72cc2fb commit 2d62272

File tree

2 files changed

+68
-14
lines changed

2 files changed

+68
-14
lines changed

Sources/PusherConnection.swift

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,27 @@ public typealias PusherEventJSON = [String: AnyObject]
4848
}
4949

5050
self!.delegate?.debugLog?(message: "[PUSHER DEBUG] Network reachable")
51-
guard self!.connectionState == .disconnected else {
51+
52+
switch self!.connectionState {
53+
case .disconnecting, .connecting, .reconnecting:
54+
// If in one of these states then part of the connection, reconnection, or explicit
55+
// disconnection process is underway, so do nothing
56+
return
57+
case .disconnected:
58+
// If already disconnected then reset connection and try to reconnect, provided the
59+
// state isn't disconnected because of an intentional disconnection
60+
if !self!.intentionalDisconnect { self!.resetConnectionAndAttemptReconnect() }
61+
return
62+
case .connected:
63+
// If already connected then we assume that there was a missed network event that
64+
// led to a bad connection so we move to the disconnected state and then attempt
65+
// reconnection
5266
self!.delegate?.debugLog?(
53-
message: "[PUSHER DEBUG] Connection state is \(self!.connectionState.stringValue()) so not calling attemptReconnect"
67+
message: "[PUSHER DEBUG] Connection state is \(self!.connectionState.stringValue()) but received network reachability change so going to call attemptReconnect"
5468
)
69+
self!.resetConnectionAndAttemptReconnect()
5570
return
5671
}
57-
58-
self!.attemptReconnect()
5972
}
6073
reachability?.whenUnreachable = { [weak self] reachability in
6174
guard self != nil else {
@@ -64,7 +77,7 @@ public typealias PusherEventJSON = [String: AnyObject]
6477
}
6578

6679
self!.delegate?.debugLog?(message: "[PUSHER DEBUG] Network unreachable")
67-
self!.setConnectionStateToDisconnectedAndReset()
80+
self!.resetConnectionAndAttemptReconnect()
6881
}
6982
return reachability
7083
}()
@@ -278,6 +291,9 @@ public typealias PusherEventJSON = [String: AnyObject]
278291
Establish a websocket connection
279292
*/
280293
@objc open func connect() {
294+
// reset the intentional disconnect state
295+
intentionalDisconnect = false
296+
281297
if self.connectionState == .connected {
282298
return
283299
} else {
@@ -348,24 +364,51 @@ public typealias PusherEventJSON = [String: AnyObject]
348364
}
349365
}
350366

351-
fileprivate func setConnectionStateToDisconnectedAndReset() {
352-
updateConnectionState(to: .disconnected)
367+
/**
368+
Set the connection state to disconnected, mark channels as unsubscribed,
369+
reset connection-related state to initial state, and initiate reconnect
370+
process
371+
*/
372+
fileprivate func resetConnectionAndAttemptReconnect() {
373+
if connectionState != .disconnected {
374+
updateConnectionState(to: .disconnected)
375+
}
376+
353377
for (_, channel) in self.channels.channels {
354378
channel.subscribed = false
355379
}
380+
381+
cleanUpActivityAndPongResponseTimeoutTimers()
382+
356383
socketConnected = false
357384
connectionEstablishedMessageReceived = false
358385
socketId = nil
386+
359387
attemptReconnect()
360388
}
361389

390+
/**
391+
Reset the activity timeout timer
392+
*/
362393
func resetActivityTimeoutTimer() {
394+
cleanUpActivityAndPongResponseTimeoutTimers()
395+
establishActivityTimeoutTimer()
396+
}
397+
398+
/**
399+
Clean up the activity timeout and pong response timers
400+
*/
401+
func cleanUpActivityAndPongResponseTimeoutTimers() {
363402
activityTimeoutTimer?.invalidate()
403+
activityTimeoutTimer = nil
364404
pongResponseTimeoutTimer?.invalidate()
365405
pongResponseTimeoutTimer = nil
366-
establishActivityTimeoutTimer()
367406
}
368407

408+
/**
409+
Schedule a timer to be fired if no activity occurs over the socket within
410+
the activityTimeoutInterval
411+
*/
369412
fileprivate func establishActivityTimeoutTimer() {
370413
self.activityTimeoutTimer = Timer.scheduledTimer(
371414
timeInterval: self.activityTimeoutInterval,
@@ -376,13 +419,20 @@ public typealias PusherEventJSON = [String: AnyObject]
376419
)
377420
}
378421

422+
/**
423+
Send a ping to the server
424+
*/
379425
@objc fileprivate func sendPing() {
380426
socket.write(ping: Data()) {
381427
self.delegate?.debugLog?(message: "[PUSHER DEBUG] Ping sent")
382428
self.setupPongResponseTimeoutTimer()
383429
}
384430
}
385431

432+
/**
433+
Schedule a timer that will fire if no pong response is received within the
434+
pongResponseTImeoutInterval
435+
*/
386436
fileprivate func setupPongResponseTimeoutTimer() {
387437
pongResponseTimeoutTimer = Timer.scheduledTimer(
388438
timeInterval: pongResponseTimeoutInterval,
@@ -393,10 +443,14 @@ public typealias PusherEventJSON = [String: AnyObject]
393443
)
394444
}
395445

446+
/**
447+
Invalidate the pongResponseTimeoutTimer and set connection state to disconnected
448+
as well as marking channels as unsubscribed
449+
*/
396450
@objc fileprivate func cleanupAfterNoPongResponse() {
397451
pongResponseTimeoutTimer?.invalidate()
398452
pongResponseTimeoutTimer = nil
399-
setConnectionStateToDisconnectedAndReset()
453+
resetConnectionAndAttemptReconnect()
400454
}
401455

402456
/**

Sources/PusherWebsocketDelegate.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ extension PusherConnection: WebSocketDelegate {
3636
self.connectionEstablishedMessageReceived = false
3737
self.socketConnected = false
3838

39+
updateConnectionState(to: .disconnected)
40+
3941
guard !intentionalDisconnect else {
40-
// reset the intentional disconnect state
41-
intentionalDisconnect = false
4242
self.delegate?.debugLog?(message: "[PUSHER DEBUG] Deliberate disconnection - skipping reconnect attempts")
43-
return updateConnectionState(to: .disconnected)
43+
return
4444
}
4545

4646
// Handle error (if any)
@@ -54,12 +54,12 @@ extension PusherConnection: WebSocketDelegate {
5454
// Attempt reconnect if possible
5555

5656
guard self.options.autoReconnect else {
57-
return updateConnectionState(to: .disconnected)
57+
return
5858
}
5959

6060
guard reconnectAttemptsMax == nil || reconnectAttempts < reconnectAttemptsMax! else {
6161
self.delegate?.debugLog?(message: "[PUSHER DEBUG] Max reconnect attempts reached")
62-
return updateConnectionState(to: .disconnected)
62+
return
6363
}
6464

6565
if let reachability = self.reachability, reachability.connection == .none {

0 commit comments

Comments
 (0)