From 4d4df0e5896d32c47dc2f8fc2384ff3fa95c4eee Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Mon, 2 Mar 2026 16:01:47 +0100 Subject: [PATCH] Safari: ensure ws reconnect on reopen (#27867) --- assets/js/views/App.vue | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/assets/js/views/App.vue b/assets/js/views/App.vue index 8ebc5a2b3..86d1068e4 100644 --- a/assets/js/views/App.vue +++ b/assets/js/views/App.vue @@ -57,6 +57,7 @@ export default defineComponent({ data: () => { return { reconnectTimeout: null as number | null, + dataTimeout: null as number | null, ws: null as WebSocket | null, authNotConfigured: false, }; @@ -148,6 +149,10 @@ export default defineComponent({ }, 2500); }, disconnect() { + if (this.dataTimeout) { + window.clearTimeout(this.dataTimeout); + this.dataTimeout = null; + } if (this.ws) { this.ws.onerror = null; this.ws.onopen = null; @@ -189,13 +194,21 @@ export default defineComponent({ }; this.ws.onopen = () => { console.log("websocket connected"); - window.app.setOnline(); }; this.ws.onclose = () => { + if (this.dataTimeout) { + window.clearTimeout(this.dataTimeout); + this.dataTimeout = null; + } window.app.setOffline(); this.reconnect(); }; this.ws.onmessage = (evt) => { + if (this.dataTimeout) { + window.clearTimeout(this.dataTimeout); + this.dataTimeout = null; + } + window.app.setOnline(); try { const msg = JSON.parse(evt.data); if (msg.startupCompleted) { @@ -210,6 +223,15 @@ export default defineComponent({ }); } }; + + // Safari/iOS 26 may fail WS handshake or open without delivering data. + // Safari/iOS 26 may fail WS handshake or open without delivering data. + // If no message received within 10s, tear down and retry. + this.dataTimeout = window.setTimeout(() => { + console.log("websocket data timeout, reconnecting"); + this.dataTimeout = null; + this.ws?.close(); + }, 10000); }, reload() { window.location.reload();