Skip to content

Commit a7ff626

Browse files
author
ClashFX Team
committed
fix: reconnect traffic/log websocket on clean disconnect
The disconnect handler previously early-returned when error was nil, silently swallowing every clean close (sleep/wake, NAT timeout, server-initiated close, network change). Once a clean disconnect happened the menu bar speed indicator froze on the last received values indefinitely. Schedule the existing exponential-backoff retry on every disconnect, log a 'clean' label when no error was supplied, and cap the backoff at 64s so a long outage cannot push the next attempt hours away. Also switch the socket identity check from == to === and ignore disconnects from stale sockets (one whose reference was already replaced inside requestTrafficInfo/requestLog during a reconnect cycle) — previously the old traffic socket's delayed disconnect callback fell into the else branch and scheduled a spurious loggingWebSocket retry.
1 parent e8586c7 commit a7ff626

1 file changed

Lines changed: 33 additions & 22 deletions

File tree

ClashFX/General/ApiRequest.swift

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class ApiRequest {
7070
private var loggingWebSocketRetryDelay: TimeInterval = 1
7171
private var trafficWebSocketRetryTimer: Timer?
7272
private var loggingWebSocketRetryTimer: Timer?
73+
private static let maxRetryDelaySeconds: TimeInterval = 64
7374

7475
private var alamoFireManager: Session
7576

@@ -566,34 +567,44 @@ extension ApiRequest: WebSocketDelegate {
566567
}
567568

568569
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
569-
guard let err = error else {
570-
return
570+
if let err = error {
571+
Logger.log(err.localizedDescription, level: .error)
571572
}
572573

573-
Logger.log(err.localizedDescription, level: .error)
574-
575574
guard let webSocket = socket as? WebSocket else { return }
576575

577-
if webSocket == trafficWebSocket {
578-
Logger.log("trafficWebSocket did disconnect", level: .debug)
579-
trafficWebSocketRetryTimer?.invalidate()
580-
trafficWebSocketRetryTimer =
581-
Timer.scheduledTimer(withTimeInterval: trafficWebSocketRetryDelay, repeats: false, block: {
582-
[weak self] _ in
583-
if self?.trafficWebSocket?.isConnected == true { return }
584-
self?.requestTrafficInfo()
585-
})
586-
trafficWebSocketRetryDelay *= 2
576+
let errDesc = error?.localizedDescription ?? "clean"
577+
if webSocket === trafficWebSocket {
578+
Logger.log("trafficWebSocket did disconnect (\(errDesc))", level: .debug)
579+
scheduleTrafficRetry()
580+
} else if webSocket === loggingWebSocket {
581+
Logger.log("loggingWebSocket did disconnect (\(errDesc))", level: .debug)
582+
scheduleLogRetry()
587583
} else {
588-
Logger.log("loggingWebSocket did disconnect", level: .debug)
589-
loggingWebSocketRetryTimer =
590-
Timer.scheduledTimer(withTimeInterval: loggingWebSocketRetryDelay, repeats: false, block: {
591-
[weak self] _ in
592-
if self?.loggingWebSocket?.isConnected == true { return }
593-
self?.requestLog()
594-
})
595-
loggingWebSocketRetryDelay *= 2
584+
Logger.log("stale websocket disconnect ignored (\(errDesc))", level: .debug)
585+
}
586+
}
587+
588+
private func scheduleTrafficRetry() {
589+
trafficWebSocketRetryTimer?.invalidate()
590+
trafficWebSocketRetryTimer = Timer.scheduledTimer(
591+
withTimeInterval: trafficWebSocketRetryDelay, repeats: false
592+
) { [weak self] _ in
593+
if self?.trafficWebSocket?.isConnected == true { return }
594+
self?.requestTrafficInfo()
595+
}
596+
trafficWebSocketRetryDelay = min(trafficWebSocketRetryDelay * 2, Self.maxRetryDelaySeconds)
597+
}
598+
599+
private func scheduleLogRetry() {
600+
loggingWebSocketRetryTimer?.invalidate()
601+
loggingWebSocketRetryTimer = Timer.scheduledTimer(
602+
withTimeInterval: loggingWebSocketRetryDelay, repeats: false
603+
) { [weak self] _ in
604+
if self?.loggingWebSocket?.isConnected == true { return }
605+
self?.requestLog()
596606
}
607+
loggingWebSocketRetryDelay = min(loggingWebSocketRetryDelay * 2, Self.maxRetryDelaySeconds)
597608
}
598609

599610
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {

0 commit comments

Comments
 (0)