fix: drop stale STK dialogs, finish pending on TP re-send, mute client-gone (v3.6.35)
The live log showed the "stuck" state: after the menu watchdog (60 s)
answered a pending command, the PWA kept the panel; the next click got
{'error': 'no pending command'}, 400 and that reply was fed to the dialog
handler as if it were a card answer. A page reload then cancelled in-flight
polls, flooding the log with BrokenPipeError tracebacks.
- stkMenuRespond detects the already-answered reply (stkNoPendingError) and
closes the panel (stkMenuPanelReset) instead of treating it as an answer;
the 5 s status poll drops the panel whenever the server reports
pending: false, even when the Phone tab is hidden.
- /api/terminal-profile (POST) and /api/rescue finish a pending command
with a cancel TR first, so re-sending the TP can never shadow an
unanswered FETCH.
- _send_json and _serve_static swallow BrokenPipe/ConnectionReset/
ConnectionAborted with one "CLIENT GONE" line (a reload cancels polls);
the handlers' state changes still stand.
Tests: stkNoPendingError + the already-answered respond path; version
3.6.35; sw simple-v308; stylesheet rebuilt.
This commit is contained in:
@@ -22,6 +22,8 @@ function extractFunc(src, name, asyncFn) {
|
||||
}
|
||||
|
||||
let code = extractFunc(html, 'stkMenuRespond', true) + '\n';
|
||||
code += extractFunc(html, 'stkNoPendingError') + '\n';
|
||||
code += extractFunc(html, 'stkMenuPanelReset') + '\n';
|
||||
code += extractFunc(html, 'stkMenuNaiSuffix') + '\n';
|
||||
code += extractFunc(html, 'stkMenuItemsHtml') + '\n';
|
||||
code += 'globalThis.esc = s => s;\n';
|
||||
@@ -32,10 +34,12 @@ function setup(response) {
|
||||
globalThis.pysimFetch = async () => response;
|
||||
globalThis.stkMenuHandleResponse = d => { calls.handled = d; };
|
||||
globalThis.stkMenuRenderItems = () => { calls.rendered++; };
|
||||
globalThis.stkCheckMenu = () => {};
|
||||
const btns = { classList: { add: () => {} } };
|
||||
const back = { style: {} };
|
||||
globalThis.document = {
|
||||
getElementById: id => (id === 'stk-menu-buttons' ? btns : id === 'stk-back-btn' ? back : { innerHTML: '' }),
|
||||
getElementById: id => (id === 'stk-menu-buttons' ? btns : id === 'stk-back-btn' ? back
|
||||
: { innerHTML: '', classList: { add: () => {} } }),
|
||||
};
|
||||
return calls;
|
||||
}
|
||||
@@ -114,3 +118,17 @@ test('ok navigates with the server response', async () => {
|
||||
assert.strictEqual(calls.handled, data);
|
||||
assert.strictEqual(calls.rendered, 0);
|
||||
});
|
||||
|
||||
test('stkNoPendingError detects the already-answered reply', () => {
|
||||
assert.strictEqual(stkNoPendingError({ error: 'no pending command' }), true);
|
||||
assert.strictEqual(stkNoPendingError({ sw: '9000', type: 'done' }), false);
|
||||
assert.strictEqual(stkNoPendingError({ error: 'other' }), false);
|
||||
assert.strictEqual(stkNoPendingError(null), false);
|
||||
});
|
||||
|
||||
test('an already-answered respond does not reach the dialog handler', async () => {
|
||||
const calls = setup({ error: 'no pending command' });
|
||||
await stkMenuRespond('ok');
|
||||
assert.strictEqual(calls.handled, null);
|
||||
assert.strictEqual(calls.rendered, 0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user