bridge: fix exponential reconnect (OOM) + add dataref resolve probe
The X-Plane socket fired both 'error' and 'close' on a failed connect, each scheduling a reconnect — so attempts doubled every cycle, leaking sockets/timers until the process OOMed (~3 min with the sim down). Guard onDown so each socket schedules exactly one reconnect (and tear the dead socket down). Also log a one-shot resolve-probe (GET /datarefs?filter[name]=airspeed…) on connect so a Web-API version/format mismatch is visible in the log. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,15 @@ async function fetchAllByName(resource, names) {
|
|||||||
|
|
||||||
// ---- X-Plane connection ---------------------------------------------------
|
// ---- X-Plane connection ---------------------------------------------------
|
||||||
async function resolveIds() {
|
async function resolveIds() {
|
||||||
|
// one-shot diagnostic: probe a universal dataref so the log shows the API's
|
||||||
|
// real response shape (helps when a version/format mismatch yields 0 matches).
|
||||||
|
try {
|
||||||
|
const probe = 'sim/cockpit2/gauges/indicators/airspeed_kts_pilot';
|
||||||
|
const u = `${REST}/datarefs?filter[name]=${encodeURIComponent(probe)}`;
|
||||||
|
const r = await fetch(u, { headers: { Accept: 'application/json' } });
|
||||||
|
const txt = await r.text();
|
||||||
|
log(`resolve-probe: GET ${u} -> HTTP ${r.status}; body ${txt.slice(0, 160)}`);
|
||||||
|
} catch (e) { log(`resolve-probe failed: ${e.message}`); }
|
||||||
const drefNames = Object.values(DATAREFS);
|
const drefNames = Object.values(DATAREFS);
|
||||||
const cmdNames = Object.values(COMMANDS);
|
const cmdNames = Object.values(COMMANDS);
|
||||||
state.drefNameToId = await fetchAllByName('datarefs', [
|
state.drefNameToId = await fetchAllByName('datarefs', [
|
||||||
@@ -146,11 +155,18 @@ function connectXPlane() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 'error' and 'close' both fire on a failed socket — guard so each socket
|
||||||
|
// schedules exactly ONE reconnect (otherwise attempts double every cycle and
|
||||||
|
// the process leaks sockets/timers until it OOMs).
|
||||||
|
let downHandled = false;
|
||||||
const onDown = (why) => {
|
const onDown = (why) => {
|
||||||
|
if (downHandled) return;
|
||||||
|
downHandled = true;
|
||||||
if (state.xpConnected) log(`X-Plane disconnected (${why})`);
|
if (state.xpConnected) log(`X-Plane disconnected (${why})`);
|
||||||
state.xpConnected = false;
|
state.xpConnected = false;
|
||||||
broadcast({ type: 'status', xpConnected: false });
|
broadcast({ type: 'status', xpConnected: false });
|
||||||
if (state.xpSocket === sock) state.xpSocket = null;
|
if (state.xpSocket === sock) state.xpSocket = null;
|
||||||
|
try { sock.removeAllListeners(); sock.terminate?.(); } catch {}
|
||||||
setTimeout(connectXPlane, 3000);
|
setTimeout(connectXPlane, 3000);
|
||||||
};
|
};
|
||||||
sock.on('close', () => onDown('close'));
|
sock.on('close', () => onDown('close'));
|
||||||
|
|||||||
Reference in New Issue
Block a user