@riddix/hamh 2.1.0-alpha.517 → 2.1.0-alpha.519
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/backend/cli.js
CHANGED
|
@@ -166866,6 +166866,7 @@ function ensureCommissioningConfig(server) {
|
|
|
166866
166866
|
|
|
166867
166867
|
// src/services/bridges/bridge.ts
|
|
166868
166868
|
var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
166869
|
+
var DEAD_SESSION_TIMEOUT_MS = 6e4;
|
|
166869
166870
|
var Bridge = class {
|
|
166870
166871
|
constructor(env, logger203, dataProvider, endpointManager) {
|
|
166871
166872
|
this.dataProvider = dataProvider;
|
|
@@ -166888,6 +166889,8 @@ var Bridge = class {
|
|
|
166888
166889
|
// (e.g. Stopped → Starting → Running).
|
|
166889
166890
|
onStatusChange;
|
|
166890
166891
|
autoForceSyncTimer = null;
|
|
166892
|
+
deadSessionTimer = null;
|
|
166893
|
+
staleSessionTimers = /* @__PURE__ */ new Map();
|
|
166891
166894
|
// Tracks the last synced state JSON per entity to avoid pushing unchanged states.
|
|
166892
166895
|
// Key: entity_id, Value: JSON.stringify of entity.state
|
|
166893
166896
|
lastSyncedStates = /* @__PURE__ */ new Map();
|
|
@@ -167064,6 +167067,33 @@ ${e?.toString()}`);
|
|
|
167064
167067
|
this.log.warn(
|
|
167065
167068
|
`All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
|
|
167066
167069
|
);
|
|
167070
|
+
if (!this.deadSessionTimer) {
|
|
167071
|
+
this.deadSessionTimer = setTimeout(() => {
|
|
167072
|
+
this.deadSessionTimer = null;
|
|
167073
|
+
this.closeDeadSessions();
|
|
167074
|
+
}, DEAD_SESSION_TIMEOUT_MS);
|
|
167075
|
+
this.log.info(
|
|
167076
|
+
`Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS / 1e3}s`
|
|
167077
|
+
);
|
|
167078
|
+
}
|
|
167079
|
+
} else if (totalSubs > 0 && this.deadSessionTimer) {
|
|
167080
|
+
clearTimeout(this.deadSessionTimer);
|
|
167081
|
+
this.deadSessionTimer = null;
|
|
167082
|
+
this.log.info(
|
|
167083
|
+
"Subscriptions recovered, canceled dead session cleanup"
|
|
167084
|
+
);
|
|
167085
|
+
}
|
|
167086
|
+
if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
|
|
167087
|
+
this.staleSessionTimers.set(
|
|
167088
|
+
session.id,
|
|
167089
|
+
setTimeout(() => {
|
|
167090
|
+
this.staleSessionTimers.delete(session.id);
|
|
167091
|
+
this.closeStaleSession(session.id);
|
|
167092
|
+
}, DEAD_SESSION_TIMEOUT_MS)
|
|
167093
|
+
);
|
|
167094
|
+
} else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
|
|
167095
|
+
clearTimeout(this.staleSessionTimers.get(session.id));
|
|
167096
|
+
this.staleSessionTimers.delete(session.id);
|
|
167067
167097
|
}
|
|
167068
167098
|
};
|
|
167069
167099
|
sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
|
|
@@ -167092,6 +167122,38 @@ ${e?.toString()}`);
|
|
|
167092
167122
|
} catch {
|
|
167093
167123
|
}
|
|
167094
167124
|
}
|
|
167125
|
+
closeStaleSession(sessionId) {
|
|
167126
|
+
try {
|
|
167127
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
167128
|
+
for (const s of [...sessionManager.sessions]) {
|
|
167129
|
+
if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
|
|
167130
|
+
this.log.warn(
|
|
167131
|
+
`Force-closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
|
|
167132
|
+
);
|
|
167133
|
+
s.initiateForceClose().catch(() => {
|
|
167134
|
+
});
|
|
167135
|
+
break;
|
|
167136
|
+
}
|
|
167137
|
+
}
|
|
167138
|
+
} catch {
|
|
167139
|
+
}
|
|
167140
|
+
}
|
|
167141
|
+
closeDeadSessions() {
|
|
167142
|
+
try {
|
|
167143
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
167144
|
+
const sessions = [...sessionManager.sessions];
|
|
167145
|
+
for (const s of sessions) {
|
|
167146
|
+
if (!s.isClosing && s.subscriptions.size === 0) {
|
|
167147
|
+
this.log.warn(
|
|
167148
|
+
`Force-closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
|
|
167149
|
+
);
|
|
167150
|
+
s.initiateForceClose().catch(() => {
|
|
167151
|
+
});
|
|
167152
|
+
}
|
|
167153
|
+
}
|
|
167154
|
+
} catch {
|
|
167155
|
+
}
|
|
167156
|
+
}
|
|
167095
167157
|
unwireSessionDiagnostics() {
|
|
167096
167158
|
try {
|
|
167097
167159
|
const sessionManager = this.server.env.get(SessionManager);
|
|
@@ -167109,6 +167171,14 @@ ${e?.toString()}`);
|
|
|
167109
167171
|
this.sessionDiagHandler = void 0;
|
|
167110
167172
|
this.sessionAddedHandler = void 0;
|
|
167111
167173
|
this.sessionDeletedHandler = void 0;
|
|
167174
|
+
if (this.deadSessionTimer) {
|
|
167175
|
+
clearTimeout(this.deadSessionTimer);
|
|
167176
|
+
this.deadSessionTimer = null;
|
|
167177
|
+
}
|
|
167178
|
+
for (const timer of this.staleSessionTimers.values()) {
|
|
167179
|
+
clearTimeout(timer);
|
|
167180
|
+
}
|
|
167181
|
+
this.staleSessionTimers.clear();
|
|
167112
167182
|
}
|
|
167113
167183
|
stopAutoForceSync() {
|
|
167114
167184
|
if (this.autoForceSyncTimer) {
|
|
@@ -179508,6 +179578,7 @@ function hashAreaId(areaId) {
|
|
|
179508
179578
|
// src/services/bridges/server-mode-bridge.ts
|
|
179509
179579
|
init_dist();
|
|
179510
179580
|
var AUTO_FORCE_SYNC_INTERVAL_MS2 = 9e4;
|
|
179581
|
+
var DEAD_SESSION_TIMEOUT_MS2 = 6e4;
|
|
179511
179582
|
var ServerModeBridge = class {
|
|
179512
179583
|
constructor(logger203, dataProvider, endpointManager, server) {
|
|
179513
179584
|
this.dataProvider = dataProvider;
|
|
@@ -179524,6 +179595,8 @@ var ServerModeBridge = class {
|
|
|
179524
179595
|
// broadcast updates via WebSocket so the frontend sees every transition.
|
|
179525
179596
|
onStatusChange;
|
|
179526
179597
|
autoForceSyncTimer = null;
|
|
179598
|
+
deadSessionTimer = null;
|
|
179599
|
+
staleSessionTimers = /* @__PURE__ */ new Map();
|
|
179527
179600
|
warmStartTimer = null;
|
|
179528
179601
|
// Tracks the last synced state JSON per entity to avoid pushing unchanged states.
|
|
179529
179602
|
lastSyncedState;
|
|
@@ -179705,6 +179778,33 @@ ${e?.toString()}`);
|
|
|
179705
179778
|
this.log.warn(
|
|
179706
179779
|
`All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
|
|
179707
179780
|
);
|
|
179781
|
+
if (!this.deadSessionTimer) {
|
|
179782
|
+
this.deadSessionTimer = setTimeout(() => {
|
|
179783
|
+
this.deadSessionTimer = null;
|
|
179784
|
+
this.closeDeadSessions();
|
|
179785
|
+
}, DEAD_SESSION_TIMEOUT_MS2);
|
|
179786
|
+
this.log.info(
|
|
179787
|
+
`Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s`
|
|
179788
|
+
);
|
|
179789
|
+
}
|
|
179790
|
+
} else if (totalSubs > 0 && this.deadSessionTimer) {
|
|
179791
|
+
clearTimeout(this.deadSessionTimer);
|
|
179792
|
+
this.deadSessionTimer = null;
|
|
179793
|
+
this.log.info(
|
|
179794
|
+
"Subscriptions recovered, canceled dead session cleanup"
|
|
179795
|
+
);
|
|
179796
|
+
}
|
|
179797
|
+
if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
|
|
179798
|
+
this.staleSessionTimers.set(
|
|
179799
|
+
session.id,
|
|
179800
|
+
setTimeout(() => {
|
|
179801
|
+
this.staleSessionTimers.delete(session.id);
|
|
179802
|
+
this.closeStaleSession(session.id);
|
|
179803
|
+
}, DEAD_SESSION_TIMEOUT_MS2)
|
|
179804
|
+
);
|
|
179805
|
+
} else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
|
|
179806
|
+
clearTimeout(this.staleSessionTimers.get(session.id));
|
|
179807
|
+
this.staleSessionTimers.delete(session.id);
|
|
179708
179808
|
}
|
|
179709
179809
|
};
|
|
179710
179810
|
sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
|
|
@@ -179733,6 +179833,38 @@ ${e?.toString()}`);
|
|
|
179733
179833
|
} catch {
|
|
179734
179834
|
}
|
|
179735
179835
|
}
|
|
179836
|
+
closeStaleSession(sessionId) {
|
|
179837
|
+
try {
|
|
179838
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
179839
|
+
for (const s of [...sessionManager.sessions]) {
|
|
179840
|
+
if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
|
|
179841
|
+
this.log.warn(
|
|
179842
|
+
`Force-closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
|
|
179843
|
+
);
|
|
179844
|
+
s.initiateForceClose().catch(() => {
|
|
179845
|
+
});
|
|
179846
|
+
break;
|
|
179847
|
+
}
|
|
179848
|
+
}
|
|
179849
|
+
} catch {
|
|
179850
|
+
}
|
|
179851
|
+
}
|
|
179852
|
+
closeDeadSessions() {
|
|
179853
|
+
try {
|
|
179854
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
179855
|
+
const sessions = [...sessionManager.sessions];
|
|
179856
|
+
for (const s of sessions) {
|
|
179857
|
+
if (!s.isClosing && s.subscriptions.size === 0) {
|
|
179858
|
+
this.log.warn(
|
|
179859
|
+
`Force-closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
|
|
179860
|
+
);
|
|
179861
|
+
s.initiateForceClose().catch(() => {
|
|
179862
|
+
});
|
|
179863
|
+
}
|
|
179864
|
+
}
|
|
179865
|
+
} catch {
|
|
179866
|
+
}
|
|
179867
|
+
}
|
|
179736
179868
|
unwireSessionDiagnostics() {
|
|
179737
179869
|
try {
|
|
179738
179870
|
const sessionManager = this.server.env.get(SessionManager);
|
|
@@ -179750,6 +179882,14 @@ ${e?.toString()}`);
|
|
|
179750
179882
|
this.sessionDiagHandler = void 0;
|
|
179751
179883
|
this.sessionAddedHandler = void 0;
|
|
179752
179884
|
this.sessionDeletedHandler = void 0;
|
|
179885
|
+
if (this.deadSessionTimer) {
|
|
179886
|
+
clearTimeout(this.deadSessionTimer);
|
|
179887
|
+
this.deadSessionTimer = null;
|
|
179888
|
+
}
|
|
179889
|
+
for (const timer of this.staleSessionTimers.values()) {
|
|
179890
|
+
clearTimeout(timer);
|
|
179891
|
+
}
|
|
179892
|
+
this.staleSessionTimers.clear();
|
|
179753
179893
|
}
|
|
179754
179894
|
stopAutoForceSync() {
|
|
179755
179895
|
if (this.autoForceSyncTimer) {
|