Add Explicit Session Exit Controls Mini-Features ä2+3

This commit is contained in:
2026-08-31 04:02:19 +02:00
parent c37fab67db
commit 06bf33b3cf
9 changed files with 77 additions and 16 deletions
+18 -2
View File
@@ -119,6 +119,7 @@ static const char s_index_html[] =
"<div class=\"button-row\">\n"
"<button id=\"request-control\" class=\"button primary\" type=\"button\" disabled>Request control</button>\n"
"<button id=\"release-control\" class=\"button danger\" type=\"button\" disabled>Release control</button>\n"
"<button id=\"disconnect\" class=\"button danger\" type=\"button\">Disconnect</button>\n"
"<button id=\"reconnect\" class=\"button\" type=\"button\">Reconnect</button>\n"
"</div>\n"
"<p id=\"input-state\" class=\"input-state\" data-enabled=\"false\" aria-live=\"polite\">"
@@ -151,6 +152,7 @@ static const char s_app_js[] =
"const connectionDetail = element('connection-detail');\n"
"const requestControl = element('request-control');\n"
"const releaseControl = element('release-control');\n"
"const disconnectButton = element('disconnect');\n"
"const reconnectButton = element('reconnect');\n"
"const terminalHost = element('terminal');\n"
"const terminal = new Terminal({\n"
@@ -171,6 +173,7 @@ static const char s_app_js[] =
"let ticketAbort = null;\n"
"let reconnectTimer = null;\n"
"let reconnectDelay = 1000;\n"
"let reconnectEnabled = true;\n"
"let connectionGeneration = 0;\n"
"let role = 'observer';\n"
"let clientId = null;\n"
@@ -193,6 +196,7 @@ static const char s_app_js[] =
" terminal.options.disableStdin = !writer;\n"
" requestControl.disabled = !socketOpen() || writer;\n"
" releaseControl.disabled = !socketOpen() || !writer;\n"
" disconnectButton.disabled = unloading || (!reconnectEnabled && socket === null && ticketAbort === null);\n"
" inputState.dataset.enabled = writer ? 'true' : 'false';\n"
" inputState.textContent = writer\n"
" ? 'Writer mode — terminal input is enabled.'\n"
@@ -215,7 +219,7 @@ static const char s_app_js[] =
" }\n"
"};\n"
"const scheduleReconnect = () => {\n"
" if (unloading || reconnectTimer !== null) return;\n"
" if (unloading || !reconnectEnabled || reconnectTimer !== null) return;\n"
" const delay = reconnectDelay;\n"
" reconnectDelay = Math.min(reconnectDelay * 2, 10000);\n"
" setConnection('Disconnected', 'bad', `Reconnecting in ${Math.ceil(delay / 1000)} second(s)…`);\n"
@@ -267,7 +271,7 @@ static const char s_app_js[] =
" return ticket;\n"
"}\n"
"async function connect() {\n"
" if (unloading) return;\n"
" if (unloading || !reconnectEnabled) return;\n"
" clearReconnectTimer();\n"
" const generation = ++connectionGeneration;\n"
" if (ticketAbort !== null) ticketAbort.abort();\n"
@@ -331,7 +335,19 @@ static const char s_app_js[] =
"releaseControl.addEventListener('click', () => {\n"
" if (role === 'writer' && socketOpen()) socket.send('release-writer');\n"
"});\n"
"disconnectButton.addEventListener('click', () => {\n"
" reconnectEnabled = false;\n"
" ++connectionGeneration;\n"
" clearReconnectTimer();\n"
" if (ticketAbort !== null) { ticketAbort.abort(); ticketAbort = null; }\n"
" if (socket !== null) { const previous = socket; socket = null; previous.close(); }\n"
" clientId = null;\n"
" clientIdField.textContent = '—';\n"
" setRole('observer');\n"
" setConnection('Disconnected', 'warn', 'Disconnected by user. Automatic reconnect is paused.');\n"
"});\n"
"reconnectButton.addEventListener('click', () => {\n"
" reconnectEnabled = true;\n"
" reconnectDelay = 1000;\n"
" connect();\n"
"});\n"