Skip to content

Commit 8ffd5a7

Browse files
committed
Fix ACConnectionMonitor didn't reconnect
There were three main issues. The first was that ACConnectionMonitor started polling onConnected, and stopped on client.disconnect(). This meant that it would never be restarted after its first disconnection, since it would never receive another onConnected event. The second was that ACStarscreamWebSocket wasn't calling onDisconnected in all scenarios where it was disconnected. Specifically, it wasn't calling onDisconnected during cancelled events (i.e. if client rather than server called disconnect) or error events. Finally, I don't think that Starscream sockets are meant to be reused after a disconnect, so it now creates a new socket per connect request.
1 parent 726004c commit 8ffd5a7

File tree

5 files changed

+30
-22
lines changed

5 files changed

+30
-22
lines changed

Examples/ACStarscreamWebSocket.swift

+19-9
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,54 @@ import ACActionCable
1010
import Starscream
1111

1212
class ACStarscreamWebSocket: ACWebSocketProtocol, WebSocketDelegate {
13-
13+
1414
var url: URL
1515

16-
private var socket: WebSocket
16+
private var socket: WebSocket?
1717

1818
init(stringURL: String) {
1919
url = URL(string: stringURL)!
20-
socket = WebSocket(request: URLRequest(url: url))
21-
socket.delegate = self
2220
}
2321

2422
var onConnected: ACConnectionHandler?
2523
var onDisconnected: ACDisconnectionHandler?
2624
var onText: ACTextHandler?
2725

2826
func connect(headers: ACRequestHeaders?) {
29-
socket.request.allHTTPHeaderFields = headers
30-
socket.connect()
27+
guard socket == nil else { return }
28+
socket = WebSocket(request: URLRequest(url: url))
29+
socket?.delegate = self
30+
socket?.request.allHTTPHeaderFields = headers
31+
socket?.connect()
3132
}
3233

3334
func disconnect() {
34-
socket.disconnect()
35+
socket?.disconnect()
3536
}
3637

3738
func send(text: String, completion: ACEventHandler?) {
38-
socket.write(string: text, completion: completion)
39+
socket?.write(string: text, completion: completion)
3940
}
4041

4142
func didReceive(event: WebSocketEvent, client: WebSocket) {
4243
switch event {
4344
case .connected(let headers):
4445
onConnected?(headers)
4546
case .disconnected(let reason, _):
46-
onDisconnected?(reason)
47+
onSocketDisconnected(reason)
4748
case .text(let text):
4849
onText?(text)
50+
case .cancelled:
51+
onSocketDisconnected()
52+
case .error(_):
53+
onSocketDisconnected()
4954
default:
5055
break
5156
}
5257
}
58+
59+
private func onSocketDisconnected(_ reason: String? = nil) {
60+
onDisconnected?(reason)
61+
socket = nil
62+
}
5363
}

Sources/ACActionCable/ACClient.swift

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public final class ACClient {
2020

2121
public var headers: ACRequestHeaders? = nil
2222

23+
static var reconnectDelay: UInt32 = 1
24+
2325
var connectionMonitor: ACConnectionMontior?
2426

2527
private var socket: ACWebSocketProtocol
@@ -78,6 +80,7 @@ public final class ACClient {
7880
// MARK: Connections
7981

8082
public func connect() {
83+
connectionMonitor?.start()
8184
socket.connect(headers: headers)
8285
}
8386

@@ -89,6 +92,12 @@ public final class ACClient {
8992
socket.disconnect()
9093
}
9194

95+
func reconnect() {
96+
socket.disconnect()
97+
sleep(Self.reconnectDelay)
98+
socket.connect(headers: headers)
99+
}
100+
92101
// MARK: Sending
93102

94103
func send(_ command: ACCommand, completion: ACEventHandler? = nil) {

Sources/ACActionCable/ACConnectionMonitor.swift

+1-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ class ACConnectionMontior {
1414
static var now: () -> Date = { Date() }
1515
static var pollIntervalRange: Range<UInt32> = 3..<30
1616
static var pollIntervalMultiplier = 5.0
17-
static var reconnectDelay: UInt32 = 1
1817

1918
var startedAt: Date?
2019
var stoppedAt: Date?
@@ -78,9 +77,7 @@ class ACConnectionMontior {
7877
func reconnectIfStale() {
7978
guard isConnectionStale && !disconnectedRecently else { return }
8079
reconnectAttempts += 1
81-
client?.disconnect(allowReconnect: true)
82-
sleep(Self.reconnectDelay)
83-
client?.connect()
80+
client?.reconnect()
8481
}
8582

8683
func stop() {
@@ -98,7 +95,6 @@ class ACConnectionMontior {
9895
reconnectAttempts = 0
9996
recordPing()
10097
disconnectedAt = nil
101-
start()
10298
}
10399

104100
private func onDisconnected(_ reason: String?) {

Tests/ACActionCableTests/ACClientTests.swift

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ final class ACClientTests: XCTestCase {
4747
client.connect()
4848
XCTAssertNotNil(client.connectionMonitor)
4949
XCTAssertEqual(expected, client.connectionMonitor!.staleThreshold)
50-
socket.onConnected?(nil)
5150
XCTAssert(client.connectionMonitor!.isRunning)
5251
}
5352

Tests/ACActionCableTests/ACConnectionMonitorTests.swift

+1-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ACConnectionMonitorTests: XCTestCase {
1818
monitor = ACConnectionMontior(client: client, staleThreshold: 6)
1919
ACConnectionMontior.now = { Date() }
2020
ACConnectionMontior.pollIntervalRange = 3..<30
21-
ACConnectionMontior.reconnectDelay = 0
21+
ACClient.reconnectDelay = 0
2222
}
2323

2424
func testStartStop() {
@@ -45,12 +45,6 @@ class ACConnectionMonitorTests: XCTestCase {
4545
XCTAssertEqual(stoppedAt, monitor.stoppedAt)
4646
}
4747

48-
func testShouldStartOnClientConnected() throws {
49-
XCTAssert(!monitor.isRunning)
50-
socket.onConnected?(nil)
51-
XCTAssert(monitor.isRunning)
52-
}
53-
5448
func testShouldRecordPingOnActionCablePing() throws {
5549
monitor.start()
5650
XCTAssertNil(monitor.pingedAt)

0 commit comments

Comments
 (0)