socket.io-client-swift icon indicating copy to clipboard operation
socket.io-client-swift copied to clipboard

.forceWebsockets(true) has issues with reconnect

Open Rostyk opened this issue 1 year ago • 3 comments

I'm using the socket in a swift iOS app like this:

private var manager: SocketManager!
private var socketIO: SocketIOClient!
.....

 manager = SocketManager(socketURL: URL(string: url)!,
                                config: [
                                    .log(true),
                                    .reconnects(true),
                                    .forceWebsockets(true)
                                    .connectParams(["roomId": nameSpace])])
        
socketIO.on(clientEvent: .reconnect, callback: { [weak self] data, ack in
            NSLog("Socket is in reconnect state")
            self?.state = .reconnecting
})
socketIO = manager.defaultSocket
socketIO.connect()

After the internet connection is lost, no .reconnect event is sent for 25 seconds and there's no way to change that behavior. I see in SocketEngine.swift this piece of code:

public func didReceive(event: Starscream.WebSocketEvent, client: Starscream.WebSocketClient) {
        switch event {
        case let .connected(headers):
            wsConnected = true
            self.client?.engineDidWebsocketUpgrade(headers: headers)
            websocketDidConnect()
        case .cancelled:
            wsConnected = false
            websocketDidDisconnect(error: EngineError.canceled)
        case .disconnected(_, _):
            wsConnected = false
            websocketDidDisconnect(error: nil)
        case let .text(msg):
            parseEngineMessage(msg)
        case let .binary(data):
            parseEngineData(data)
        case _:
            break
        }
 }

So the viabilityChanged(Bool) state is not handled in the didReceive

public enum WebSocketEvent {
    case connected([String: String])
    case disconnected(String, UInt16)
    case text(String)
    case binary(Data)
    case pong(Data?)
    case ping(Data?)
    case error(Error?)
    case viabilityChanged(Bool) // falls into default case and there's no way to subscribe for this event
    case reconnectSuggested(Bool)
    case cancelled
    case peerClosed
}

The viabilityChanged(false) is sent by StarScream in .forceWebsocket(true) mode which indicates that the socket has no physical connection. Instead I don't get the clientEvent: .reconnect until the ping times out, which is 25 seconds usually. The pingTimeout is taken from here:

if let pingInterval = json["pingInterval"] as? Int, let pingTimeout = json["pingTimeout"] as? Int {
       self.pingInterval = pingInterval
       self.pingTimeout = pingTimeout
}

Is there something I'm missing here or it's designed this way and it's okay. I'm happy to submit pull-request with few tweaks to improve it

Rostyk avatar Sep 30 '24 15:09 Rostyk

I think there is already a PR (#1464) but unfortunately the maintainer of this repo has gone MIA.

cbiggin avatar Sep 30 '24 19:09 cbiggin

It seems it was resolved and released guys

Ariandr avatar Oct 02 '24 15:10 Ariandr

Yes, I was wondering if it had been. @Rostyk v16.1.1 was released 2 days ago so you can probably close this issue.

cbiggin avatar Oct 03 '24 16:10 cbiggin