UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

103 lines (102 loc) 4.6 kB
//#region src/gateway/node-wake-state-store.ts const nodeWakeStateByOwner = /* @__PURE__ */ new Map(); const nodeWakeOwnerBySignal = /* @__PURE__ */ new WeakMap(); function nodeWakeStateKey(nodeId, pairingGeneration) { return JSON.stringify([nodeId.trim(), pairingGeneration?.trim() || null]); } //#endregion //#region src/gateway/node-wake-state.ts const NODE_WAKE_RECONNECT_WAIT_MS = 3e3; const NODE_WAKE_RECONNECT_RETRY_WAIT_MS = 12e3; function getOrCreateNodeWakeOwner(nodeId, pairingGeneration) { const normalizedNodeId = nodeId.trim(); const stateKey = nodeWakeStateKey(normalizedNodeId, pairingGeneration); const existing = nodeWakeStateByOwner.get(stateKey); if (existing) return existing; const created = { nodeId: normalizedNodeId, stateKey }; nodeWakeStateByOwner.set(stateKey, created); return created; } function deleteIdleNodeWakeOwner(owner) { if (owner.lifecycle?.users || owner.inFlightWake || owner.lastWakeAtMs !== void 0 || owner.lastNudgeAtMs !== void 0) return; owner.lifecycle?.controller.abort(); if (owner.lifecycle) nodeWakeOwnerBySignal.delete(owner.lifecycle.controller.signal); nodeWakeStateByOwner.delete(owner.stateKey); } function captureNodeWakeLifecycle(nodeId, pairingGeneration) { const owner = getOrCreateNodeWakeOwner(nodeId, pairingGeneration); if (!owner.lifecycle || owner.lifecycle.controller.signal.aborted) { owner.lifecycle = { controller: new AbortController(), users: 0 }; nodeWakeOwnerBySignal.set(owner.lifecycle.controller.signal, owner); } owner.lifecycle.users += 1; return owner.lifecycle.controller.signal; } function isNodeWakeLifecycleCurrent(nodeId, lifecycle, pairingGeneration) { const owner = nodeWakeOwnerBySignal.get(lifecycle); const expectedStateKey = nodeWakeStateKey(nodeId, pairingGeneration); return !lifecycle.aborted && owner?.nodeId === nodeId.trim() && owner.stateKey === expectedStateKey && nodeWakeStateByOwner.get(expectedStateKey) === owner && owner.lifecycle?.controller.signal === lifecycle; } function releaseNodeWakeLifecycle(nodeId, lifecycle) { const owner = nodeWakeOwnerBySignal.get(lifecycle); if (owner?.nodeId !== nodeId.trim() || nodeWakeStateByOwner.get(owner.stateKey) !== owner || owner.lifecycle?.controller.signal !== lifecycle) return; owner.lifecycle.users = Math.max(0, owner.lifecycle.users - 1); deleteIdleNodeWakeOwner(owner); } /** Owns wake dedupe and throttle state while the caller owns APNs policy and I/O. */ async function runNodeWakeAttempt(params) { const owner = getOrCreateNodeWakeOwner(params.nodeId, params.pairingGeneration); if (owner.inFlightWake) return await owner.inFlightWake; if (!params.force && owner.lastWakeAtMs !== void 0 && performance.now() - owner.lastWakeAtMs < params.throttleMs) return { available: true, throttled: true, path: "throttled", durationMs: 0 }; const attempt = params.attempt(() => { owner.lastWakeAtMs = performance.now(); }); owner.inFlightWake = attempt; try { return await attempt; } finally { if (owner.inFlightWake === attempt) owner.inFlightWake = void 0; deleteIdleNodeWakeOwner(owner); } } /** Owns reconnect-nudge throttling while the caller owns APNs policy and I/O. */ async function runNodeWakeNudgeAttempt(params) { const owner = getOrCreateNodeWakeOwner(params.nodeId, params.pairingGeneration); if (owner.lastNudgeAtMs !== void 0 && performance.now() - owner.lastNudgeAtMs < params.throttleMs) return params.throttled(); const result = await params.attempt(); if (result.reason === "sent") owner.lastNudgeAtMs = performance.now(); deleteIdleNodeWakeOwner(owner); return result; } function clearNodeWakeState(nodeId) { const normalizedNodeId = nodeId.trim(); for (const owner of nodeWakeStateByOwner.values()) { if (owner.nodeId !== normalizedNodeId) continue; owner.lastWakeAtMs = void 0; owner.inFlightWake = void 0; owner.lastNudgeAtMs = void 0; deleteIdleNodeWakeOwner(owner); } } function invalidateNodeWakeState(nodeId) { const normalizedNodeId = nodeId.trim(); for (const owner of nodeWakeStateByOwner.values()) { if (owner.nodeId !== normalizedNodeId) continue; owner.lifecycle?.controller.abort(); if (owner.lifecycle) nodeWakeOwnerBySignal.delete(owner.lifecycle.controller.signal); nodeWakeStateByOwner.delete(owner.stateKey); } } //#endregion export { invalidateNodeWakeState as a, runNodeWakeAttempt as c, clearNodeWakeState as i, runNodeWakeNudgeAttempt as l, NODE_WAKE_RECONNECT_WAIT_MS as n, isNodeWakeLifecycleCurrent as o, captureNodeWakeLifecycle as r, releaseNodeWakeLifecycle as s, NODE_WAKE_RECONNECT_RETRY_WAIT_MS as t };