Skip to content

Commit 8cccc64

Browse files
authored
Merge pull request #231 from krasnyt/fix/reconnect-on-pong-timeout
fix(websocket): auto-restart after abnormal local close (pong timeout)
2 parents 9b0361a + 18f7195 commit 8cccc64

2 files changed

Lines changed: 28 additions & 10 deletions

File tree

src/main/java/cz/smarteon/loxone/LoxoneWebsocketClient.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,11 @@ public void onClose(int code, String reason, boolean remote) {
133133
keepAliveFuture.cancel(true);
134134
}
135135
ws.connectionClosed(code, remote);
136-
if (remote && code != CloseFrame.NEVER_CONNECTED) {
136+
// Reconnect not only on remote close, but also on an abnormal *local* close (code 1006),
137+
// which is how Java-WebSocket reports a lost connection (e.g. the miniserver stops
138+
// answering pings/pongs). A deliberate LoxoneWebSocket.close() produces a NORMAL (1000)
139+
// local close, so it is intentionally excluded and won't trigger a restart.
140+
if (code != CloseFrame.NEVER_CONNECTED && (remote || code == CloseFrame.ABNORMAL_CLOSE)) {
137141
ws.autoRestart();
138142
}
139143
}

src/test/kotlin/LoxoneWebsocketClientTest.kt

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package cz.smarteon.loxone
22

33
import io.mockk.mockk
4+
import io.mockk.verify
5+
import org.java_websocket.framing.CloseFrame
46
import org.junit.jupiter.api.BeforeEach
57
import org.junit.jupiter.api.Test
6-
import org.junit.jupiter.params.ParameterizedTest
7-
import org.junit.jupiter.params.provider.ValueSource
88
import strikt.api.expectCatching
99
import strikt.assertions.isSuccess
1010
import java.net.URI
@@ -27,13 +27,27 @@ class LoxoneWebsocketClientTest {
2727
}.isSuccess()
2828
}
2929

30-
@ParameterizedTest
31-
@ValueSource(booleans = [true, false])
32-
fun `should handle onClose`(remote: Boolean) {
33-
client.onClose(1000, "some reason", remote)
30+
@Test
31+
fun `should auto-restart on remote close`() {
32+
client.onClose(CloseFrame.NORMAL, "normally closed", true)
33+
34+
verify { webSocket.connectionClosed(CloseFrame.NORMAL, true) }
35+
verify { webSocket.autoRestart() }
36+
}
37+
38+
@Test
39+
fun `should auto-restart on abnormal local close (lost connection or pong timeout)`() {
40+
client.onClose(CloseFrame.ABNORMAL_CLOSE, "no pong in time", false)
41+
42+
verify { webSocket.connectionClosed(CloseFrame.ABNORMAL_CLOSE, false) }
43+
verify { webSocket.autoRestart() }
44+
}
45+
46+
@Test
47+
fun `should not auto-restart on deliberate local close`() {
48+
client.onClose(CloseFrame.NORMAL, "closed by client", false)
3449

35-
expectCatching { webSocket.wsClosed() }.isSuccess()
36-
expectCatching { webSocket.connectionClosed(1000, remote) }.isSuccess()
37-
if (remote) expectCatching { webSocket.autoRestart() }.isSuccess()
50+
verify { webSocket.connectionClosed(CloseFrame.NORMAL, false) }
51+
verify(exactly = 0) { webSocket.autoRestart() }
3852
}
3953
}

0 commit comments

Comments
 (0)