44 lines
1.9 KiB
JavaScript
44 lines
1.9 KiB
JavaScript
/**
|
|||
|
|
* app-lease.js — "app 窗口还开着"的凭证。
|
||
|
|
*
|
||
|
|
* 与 esp32_server.py 的 /ws/app-lease 保持一条 WebSocket。服务端在
|
||
|
|
* **所有** 租约连接断开后的宽限期结束时, 自动把 EtherCAT PDO 循环停掉、
|
||
|
|
* 从站退回 INIT —— 这是"关掉 app 从站必须停"的兜底, 无论 ecat_native
|
||
|
|
* 是谁拉起的(本服务复用现成实例时, 它的 --parent-pid 看门狗够不着)。
|
||
|
|
*
|
||
|
|
* 为什么用 WebSocket 而不是心跳轮询: 已建立的连接不受浏览器后台标签页
|
||
|
|
* 定时器节流影响(那会把"挂在后台的 app"误判成已关闭), 断开靠 TCP FIN
|
||
|
|
* 即时感知, 不依赖任何计时器。服务端另有 3s 断连吸收窗口, 页面刷新不会误停。
|
||
|
|
*
|
||
|
|
* 接入位置: tabs.html(外壳, 覆盖整个 app 窗口生命周期) 和 pages/motor.html
|
||
|
|
* (单独打开电机页时它自己就是窗口)。同一窗口里两条连接并存没问题,
|
||
|
|
* 服务端判据是"连接数归零"。断线自动重连; file:// 直开页面时静默跳过。
|
||
|
|
*/
|
||
|
|
(function () {
|
||
|
|
"use strict";
|
||
|
|
if (location.protocol !== "http:" && location.protocol !== "https:") return;
|
||
|
|
var url = (location.protocol === "https:" ? "wss://" : "ws://") +
|
||
|
|
location.host + "/ws/app-lease";
|
||
|
|
var retryTimer = null;
|
||
|
|
var delay = 3000;
|
||
|
|
|
||
|
|
function scheduleReconnect() {
|
||
|
|
if (retryTimer) return;
|
||
|
|
// 3~30s 递增退避: 服务没起/刚重启时不去刷屏, 起来后最多等半分钟接上。
|
||
|
|
retryTimer = setTimeout(function () {
|
||
|
|
retryTimer = null;
|
||
|
|
delay = Math.min(delay * 2, 30000);
|
||
|
|
connect();
|
||
|
|
}, delay);
|
||
|
|
}
|
||
|
|
|
||
|
|
function connect() {
|
||
|
|
var ws;
|
||
|
|
try { ws = new WebSocket(url); } catch (e) { scheduleReconnect(); return; }
|
||
|
|
ws.onopen = function () { delay = 3000; };
|
||
|
|
ws.onclose = function () { scheduleReconnect(); };
|
||
|
|
ws.onerror = function () { try { ws.close(); } catch (e) {} };
|
||
|
|
}
|
||
|
|
connect();
|
||
|
|
})();
|