@@ -10,21 +10,26 @@ This document describes the automatic reconnection logic implemented in the WebS
1010
1111The WebSocket middleware uses a simple approach: ** auto-reconnect for everything except custom application codes** .
1212
13- | Close Code | Scenario | Behavior |
14- | ------------------------ | ------------------------ | ------------------------------------------ |
15- | ** 4100** | Client-initiated cleanup | No reconnection, clean shutdown |
16- | ** 4000** | User code changed | No reconnection, show error, clear state |
17- | ** 4002** | Room combination changed | No reconnection, manual reconnect required |
18- | ** 4001** (not processor) | Processor shutdown | No reconnection, manual reconnect required |
19- | ** All other codes** | Any disconnect/error | ** Auto-reconnect after 5s** |
13+ | Close Code | Scenario | Behavior |
14+ | --------------------------------- | ------------------------ | ------------------------------------------ |
15+ | ** 4100** | Client-initiated cleanup | No reconnection, clean shutdown |
16+ | ** 4000** | User code changed | No reconnection, show error, clear state |
17+ | ** 4002** | Room combination changed | No reconnection, manual reconnect required |
18+ | ** 4001** (with touchpanel key) | Connection loss | ** Auto-reconnect after 5s** |
19+ | ** 4001** (no touchpanel, no proc) | Processor shutdown | No reconnection, manual reconnect required |
20+ | ** 4001** (no touchpanel, proc HW) | Connection loss | ** Auto-reconnect after 5s** |
21+ | ** All other codes** | Any disconnect/error | ** Auto-reconnect after 5s** |
2022
2123** This includes:**
2224
2325- ** 1000** (Normal Closure) - Typical processor hardware disconnect
24- - ** 4001** on processor hardware - Connection loss
2526- Any network errors, unexpected disconnects, etc.
2627
27- ** Simple rule** : If it's not one of the three custom codes (4000, 4002, 4100) or 4001 on non-processor hardware, it will auto-reconnect.
28+ ** Code 4001 Logic** :
29+
30+ 1 . ** If touchpanel key exists** → Always auto-reconnect (regardless of processor hardware flag)
31+ 2 . ** If no touchpanel key AND not on processor hardware** → Manual reconnect required
32+ 3 . ** If no touchpanel key BUT on processor hardware** → Auto-reconnect
2833
2934### Processor Hardware Mode
3035
@@ -92,38 +97,49 @@ newWs.onopen = (ev: Event) => {
9297};
9398```
9499
95- #### Special Case: Code 4001 on Non-Processor Hardware
96-
97- ** Scenario** : Server is on a computer/VM that might be shut down
100+ #### Special Case: Code 4001 Based on Touchpanel Key
98101
99- - Disconnect code 4001 likely means server is intentionally stopping
100- - Auto-reconnection would be futile
101- - User should manually reconnect when server restarts
102+ ** Scenario** : Code 4001 behavior depends on touchpanel key presence and processor hardware flag
102103
103- ** Behavior on disconnect (code 4001 only) ** :
104+ ** Priority Logic ** :
104105
105- 1 . Show error message: "Processor has disconnected. Click Reconnect"
106- 2 . Clear all state (full cleanup)
107- 3 . Wait for manual user action
108- 4 . ** No automatic reconnection**
106+ 1 . ** Touchpanel key exists** → Always auto-reconnect (best indicator of active touchpanel)
107+ 2 . ** No touchpanel key + not on processor hardware** → Manual reconnect required
108+ 3 . ** No touchpanel key + on processor hardware** → Auto-reconnect
109109
110110** Code** :
111111
112112``` typescript
113- // Code 4001 on non-processor hardware should not auto-reconnect
114- if (closeEvent .code === 4001 && ! serverIsRunningOnProcessorHardware ) {
115- console .log (
116- ' WebSocket middleware: Processor disconnected (not on processor hardware)'
117- );
118- dispatch (
119- uiActions .setErrorMessage (' Processor has disconnected. Click Reconnect' )
120- );
121- clearStateDataOnDisconnect (dispatch );
122- return ; // Early exit - no auto-reconnect
113+ // Handle code 4001 based on touchpanel key presence
114+ if (closeEvent .code === 4001 ) {
115+ const currentState = getState () as LocalRootState ;
116+ const hasTouchpanelKey = !! currentState .runtimeConfig ?.touchpanelKey ;
117+
118+ if (hasTouchpanelKey ) {
119+ console .log (
120+ ' WebSocket middleware: Code 4001 received with touchpanel key present, will auto-reconnect'
121+ );
122+ // Will fall through to auto-reconnect logic below
123+ } else if (! serverIsRunningOnProcessorHardware ) {
124+ console .log (
125+ ' WebSocket middleware: Processor disconnected (no touchpanel key, not on processor hardware)'
126+ );
127+ stopReconnectionLoop ();
128+ dispatch (
129+ uiActions .setErrorMessage (' Processor has disconnected. Click Reconnect' )
130+ );
131+ clearStateDataOnDisconnect (dispatch );
132+ return ;
133+ } else {
134+ console .log (
135+ ' WebSocket middleware: Code 4001 on processor hardware (no touchpanel key), will auto-reconnect'
136+ );
137+ // Will fall through to auto-reconnect logic below
138+ }
123139}
124140```
125141
126- ** Note ** : Code 4001 on processor hardware WILL auto-reconnect (treated like any other disconnect) .
142+ ** Touchpanel Key Priority ** : The presence of a touchpanel key indicates an active touchpanel connection that should be maintained, so it takes priority over the processor hardware flag for reconnection decisions .
127143
128144#### When Server is NOT on Processor Hardware (` serverIsRunningOnProcessorHardware: false ` )
129145
@@ -263,11 +279,38 @@ newWs.onclose = (closeEvent: CloseEvent): void => {
263279};
264280```
265281
282+ ## Anti-Flashing Mechanism
283+
284+ To prevent the UI from flashing between connected/disconnected states during reconnection attempts, the middleware uses a delayed connection state update:
285+
286+ ``` typescript
287+ newWs .onopen = (ev : Event ) => {
288+ console .log (' WebSocket middleware: Connected' );
289+ state .waitingToReconnect = false ;
290+ stopReconnectionLoop ();
291+
292+ // Delay setting connected state to avoid flashing during failed reconnection attempts
293+ setTimeout (() => {
294+ // Only set connected if this WebSocket is still the current client
295+ if (state .client === newWs && newWs .readyState === WebSocket .OPEN ) {
296+ dispatch (runtimeConfigActions .setWebsocketIsConnected (true ));
297+ }
298+ }, 100 );
299+ };
300+ ```
301+
302+ ** Why this prevents flashing** :
303+
304+ - WebSocket ` onopen ` can fire briefly even for connections that will immediately fail
305+ - Without delay: ` onopen ` → ` isConnected = true ` → UI shows children → ` onclose ` → ` isConnected = false ` → UI shows DisconnectedMessage (flashing)
306+ - With delay: ` onopen ` → wait 100ms → check if still connected → only then set ` isConnected = true `
307+
266308This ensures:
267309
268310- Only one connection attempt at a time
269311- ** Client reference is cleared immediately on disconnect**
270312- Prevents "already connected" errors on reconnection
313+ - ** No UI flashing during reconnection attempts**
271314- No race conditions
272315- Clean state management
273316
@@ -329,22 +372,33 @@ This is stored in Redux state at `runtimeConfig.serverIsRunningOnProcessorHardwa
3293724 . ** Expected** : Shows "Connection lost..."
3303735 . ** Expected** : Multiple retry attempts until network is back
331374
332- ### Test 3: Code 4001 on Processor Hardware
375+ ### Test 3: Code 4001 with Touchpanel Key Present
333376
334- 1 . Set ` serverIsRunningOnProcessorHardware: true `
377+ 1 . Set touchpanel key in runtime config: ` runtimeConfig.touchpanelKey = "some-key" `
3353782 . Connect to WebSocket
3363793 . Trigger disconnect with close code 4001
337- 4 . ** Expected** : Auto-reconnects after 5s
380+ 4 . ** Expected** : Auto-reconnects after 5s (regardless of processor hardware flag)
3383815 . ** Expected** : Shows "Connection lost. Attempting to reconnect..."
382+ 6 . ** Expected** : Continuous retry attempts until successful
383+
384+ ### Test 4: Code 4001 without Touchpanel Key (Processor Hardware)
339385
340- ### Test 4: Code 4001 on Non-Processor Hardware
386+ 1 . Set ` serverIsRunningOnProcessorHardware: true `
387+ 2 . Ensure no touchpanel key: ` runtimeConfig.touchpanelKey = null `
388+ 3 . Connect to WebSocket
389+ 4 . Trigger disconnect with close code 4001
390+ 5 . ** Expected** : Auto-reconnects after 5s
391+ 6 . ** Expected** : Shows "Connection lost. Attempting to reconnect..."
392+
393+ ### Test 5: Code 4001 without Touchpanel Key (Non-Processor Hardware)
341394
3423951 . Set ` serverIsRunningOnProcessorHardware: false `
343- 2 . Connect to WebSocket
344- 3 . Stop server with close code 4001
345- 4 . ** Expected** : Shows "Processor has disconnected. Click Reconnect"
346- 5 . ** Expected** : No auto-reconnect attempts
347- 6 . ** Expected** : Manual reconnect button works when server is back
396+ 2 . Ensure no touchpanel key: ` runtimeConfig.touchpanelKey = null `
397+ 3 . Connect to WebSocket
398+ 4 . Stop server with close code 4001
399+ 5 . ** Expected** : Shows "Processor has disconnected. Click Reconnect"
400+ 6 . ** Expected** : No auto-reconnect attempts
401+ 7 . ** Expected** : Manual reconnect button works when server is back
348402
349403### Test 5: User Code Changed (Code 4000)
350404
0 commit comments