openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
171 lines (170 loc) • 7.41 kB
JavaScript
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { Cn as validateNodePendingDrainParams, wn as validateNodePendingEnqueueParams } from "./src-BiL5aQto.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import { r as respondUnavailableOnThrow } from "./nodes.helpers-7uACMTmw.js";
import { t as assertValidParams } from "./validation-pzrlzFvo.js";
import { i as removeNodePendingWorkItem, n as drainNodePendingWork, r as enqueueNodePendingWork } from "./node-pending-work-B-emncmK.js";
import { n as NODE_WAKE_RECONNECT_WAIT_MS, r as captureNodeWakeLifecycle, s as releaseNodeWakeLifecycle, t as NODE_WAKE_RECONNECT_RETRY_WAIT_MS } from "./node-wake-state-CWVR-GCk.js";
import { i as isNodePairingGenerationCurrent, n as captureNodePairingGeneration } from "./device-pairing-node-state-DxNt2jjv.js";
import { i as isNodePairingWorkCurrent, n as maybeWakeNodeWithApns, r as waitForNodeReconnect, t as maybeSendNodeWakeNudge } from "./nodes.wake-DsmpSHp_.js";
//#region src/gateway/server-methods/nodes.pending-work.ts
function respondPairingChanged(respond) {
respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "node pairing changed while pending work was active", {
retryable: true,
details: { code: "PAIRING_CHANGED" }
}));
}
function resolveClientNodeId(client) {
const trimmed = (client?.connect?.device?.id ?? client?.connect?.client?.id ?? "").trim();
return trimmed.length > 0 ? trimmed : null;
}
/** Gateway handlers for queueing work until a paired node reconnects. */
const nodePendingWorkHandlers = {
"node.pending.drain": async ({ params, respond, client, context }) => {
if (!assertValidParams(params, validateNodePendingDrainParams, "node.pending.drain", respond)) return;
const nodeId = resolveClientNodeId(client);
if (!nodeId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "node.pending.drain requires a connected device identity"));
return;
}
await respondUnavailableOnThrow(respond, async () => {
const generation = await captureNodePairingGeneration(nodeId);
if (!generation || !await isNodePairingGenerationCurrent(generation)) {
respondPairingChanged(respond);
return;
}
const session = context.nodeRegistry.getForPairingGeneration(nodeId, generation.key);
if (!client?.connId || session?.connId !== client.connId) {
respondPairingChanged(respond);
return;
}
const drained = drainNodePendingWork(nodeId, {
maxItems: params.maxItems,
includeDefaultStatus: true,
pairingGeneration: generation.key
});
respond(true, {
nodeId,
...drained
}, void 0);
});
},
"node.pending.enqueue": async ({ params, respond, context }) => {
if (!assertValidParams(params, validateNodePendingEnqueueParams, "node.pending.enqueue", respond)) return;
const p = params;
await respondUnavailableOnThrow(respond, async () => {
const nodeId = p.nodeId.trim();
const generation = await captureNodePairingGeneration(nodeId);
if (!generation) {
respondPairingChanged(respond);
return;
}
const wakeLifecycle = captureNodeWakeLifecycle(nodeId, generation.key);
try {
if (!await isNodePairingWorkCurrent({
nodeId,
generation,
lifecycle: wakeLifecycle
})) {
respondPairingChanged(respond);
return;
}
const queued = enqueueNodePendingWork({
nodeId,
type: p.type,
priority: p.priority,
expiresInMs: p.expiresInMs,
pairingGeneration: generation.key
});
let wakeTriggered = false;
if (p.wake !== false && !queued.deduped && !context.nodeRegistry.getForPairingGeneration(nodeId, generation.key)) {
const wakeReqId = queued.item.id;
context.logGateway.info(`node pending wake start node=${nodeId} req=${wakeReqId} type=${queued.item.type}`);
const cfg = context.getRuntimeConfig();
const wake = await maybeWakeNodeWithApns(nodeId, {
wakeReason: "node.pending",
cfg,
lifecycle: wakeLifecycle,
generation
});
context.logGateway.info(`node pending wake stage=wake1 node=${nodeId} req=${wakeReqId} available=${wake.available} throttled=${wake.throttled} path=${wake.path} durationMs=${wake.durationMs} apnsStatus=${wake.apnsStatus ?? -1} apnsReason=${wake.apnsReason ?? "-"}`);
wakeTriggered = wake.available;
if (wake.available) {
const reconnected = await waitForNodeReconnect({
nodeId,
context,
timeoutMs: NODE_WAKE_RECONNECT_WAIT_MS,
lifecycle: wakeLifecycle,
pairingGeneration: generation.key
});
context.logGateway.info(`node pending wake stage=wait1 node=${nodeId} req=${wakeReqId} reconnected=${reconnected} timeoutMs=${NODE_WAKE_RECONNECT_WAIT_MS}`);
}
if (await isNodePairingWorkCurrent({
nodeId,
generation,
lifecycle: wakeLifecycle
}) && !context.nodeRegistry.getForPairingGeneration(nodeId, generation.key) && wake.available) {
const retryWake = await maybeWakeNodeWithApns(nodeId, {
force: true,
wakeReason: "node.pending",
cfg,
lifecycle: wakeLifecycle,
generation
});
context.logGateway.info(`node pending wake stage=wake2 node=${nodeId} req=${wakeReqId} force=true available=${retryWake.available} throttled=${retryWake.throttled} path=${retryWake.path} durationMs=${retryWake.durationMs} apnsStatus=${retryWake.apnsStatus ?? -1} apnsReason=${retryWake.apnsReason ?? "-"}`);
if (retryWake.available) {
const reconnected = await waitForNodeReconnect({
nodeId,
context,
timeoutMs: NODE_WAKE_RECONNECT_RETRY_WAIT_MS,
lifecycle: wakeLifecycle,
pairingGeneration: generation.key
});
context.logGateway.info(`node pending wake stage=wait2 node=${nodeId} req=${wakeReqId} reconnected=${reconnected} timeoutMs=${NODE_WAKE_RECONNECT_RETRY_WAIT_MS}`);
}
}
if (await isNodePairingWorkCurrent({
nodeId,
generation,
lifecycle: wakeLifecycle
}) && !context.nodeRegistry.getForPairingGeneration(nodeId, generation.key)) {
const nudge = await maybeSendNodeWakeNudge(nodeId, {
cfg,
lifecycle: wakeLifecycle,
generation
});
context.logGateway.info(`node pending wake nudge node=${nodeId} req=${wakeReqId} sent=${nudge.sent} throttled=${nudge.throttled} reason=${nudge.reason} durationMs=${nudge.durationMs} apnsStatus=${nudge.apnsStatus ?? -1} apnsReason=${nudge.apnsReason ?? "-"}`);
context.logGateway.warn(`node pending wake done node=${nodeId} req=${wakeReqId} connected=false reason=not_connected`);
} else if (await isNodePairingWorkCurrent({
nodeId,
generation,
lifecycle: wakeLifecycle
})) context.logGateway.info(`node pending wake done node=${nodeId} req=${wakeReqId} connected=true`);
}
if (!await isNodePairingWorkCurrent({
nodeId,
generation,
lifecycle: wakeLifecycle
})) {
if (!queued.deduped) removeNodePendingWorkItem({
nodeId,
itemId: queued.item.id,
pairingGeneration: generation.key
});
respondPairingChanged(respond);
return;
}
respond(true, {
nodeId,
revision: queued.revision,
queued: queued.item,
wakeTriggered
}, void 0);
} finally {
releaseNodeWakeLifecycle(nodeId, wakeLifecycle);
}
});
}
};
//#endregion
export { nodePendingWorkHandlers };