UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

139 lines (138 loc) 5.51 kB
import { s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js"; import { n as serializeEventPayload, t as NodeRegistry } from "./node-registry-DzMBNLUj.js"; import { i as createSessionMessageSubscriberRegistry, r as createSessionEventSubscriberRegistry } from "./server-chat-state-CcwJF39T.js"; //#region src/gateway/server-node-subscriptions.ts /** Manages node subscriptions to gateway session events. */ function createNodeSubscriptionManager() { const nodeSubscriptions = /* @__PURE__ */ new Map(); const sessionSubscribers = /* @__PURE__ */ new Map(); const toPayloadJSON = (payload) => serializeEventPayload(payload); const subscribe = (nodeId, sessionKey) => { const normalizedNodeId = nodeId.trim(); const normalizedSessionKey = sessionKey.trim(); if (!normalizedNodeId || !normalizedSessionKey) return; let nodeSet = nodeSubscriptions.get(normalizedNodeId); if (!nodeSet) { nodeSet = /* @__PURE__ */ new Set(); nodeSubscriptions.set(normalizedNodeId, nodeSet); } if (nodeSet.has(normalizedSessionKey)) return; nodeSet.add(normalizedSessionKey); let sessionSet = sessionSubscribers.get(normalizedSessionKey); if (!sessionSet) { sessionSet = /* @__PURE__ */ new Set(); sessionSubscribers.set(normalizedSessionKey, sessionSet); } sessionSet.add(normalizedNodeId); }; const unsubscribe = (nodeId, sessionKey) => { const normalizedNodeId = nodeId.trim(); const normalizedSessionKey = sessionKey.trim(); if (!normalizedNodeId || !normalizedSessionKey) return; const nodeSet = nodeSubscriptions.get(normalizedNodeId); nodeSet?.delete(normalizedSessionKey); if (nodeSet?.size === 0) nodeSubscriptions.delete(normalizedNodeId); const sessionSet = sessionSubscribers.get(normalizedSessionKey); sessionSet?.delete(normalizedNodeId); if (sessionSet?.size === 0) sessionSubscribers.delete(normalizedSessionKey); }; const unsubscribeAll = (nodeId) => { const normalizedNodeId = nodeId.trim(); const nodeSet = nodeSubscriptions.get(normalizedNodeId); if (!nodeSet) return; for (const sessionKey of nodeSet) { const sessionSet = sessionSubscribers.get(sessionKey); sessionSet?.delete(normalizedNodeId); if (sessionSet?.size === 0) sessionSubscribers.delete(sessionKey); } nodeSubscriptions.delete(normalizedNodeId); }; const sendToSession = (sessionKey, event, payload, sendEvent) => { const normalizedSessionKey = sessionKey.trim(); if (!normalizedSessionKey || !sendEvent) return; const subs = sessionSubscribers.get(normalizedSessionKey); if (!subs || subs.size === 0) return; const payloadJSON = toPayloadJSON(payload); for (const nodeId of subs) sendEvent({ nodeId, event, payloadJSON }); }; const sendToAllSubscribed = (event, payload, sendEvent) => { if (!sendEvent) return; const payloadJSON = toPayloadJSON(payload); for (const nodeId of nodeSubscriptions.keys()) sendEvent({ nodeId, event, payloadJSON }); }; const sendToAllConnected = (event, payload, listConnected, sendEvent) => { if (!sendEvent || !listConnected) return; const payloadJSON = toPayloadJSON(payload); for (const node of listConnected()) sendEvent({ nodeId: node.nodeId, event, payloadJSON }); }; const clear = () => { nodeSubscriptions.clear(); sessionSubscribers.clear(); }; return { subscribe, unsubscribe, unsubscribeAll, sendToSession, sendToAllSubscribed, sendToAllConnected, clear }; } //#endregion //#region src/gateway/server-talk-nodes.ts const TALK_CAPABILITY = "talk"; const TALK_COMMAND_PREFIX = "talk."; /** Returns true when any connected node can handle talk routing. */ function hasConnectedTalkNode(registry) { return registry.listConnected().some(isTalkCapableNode); } function isTalkCapableNode(node) { return node.caps.some((capability) => normalizeOptionalLowercaseString(capability) === TALK_CAPABILITY) || node.commands.some((command) => normalizeOptionalLowercaseString(command)?.startsWith(TALK_COMMAND_PREFIX)); } //#endregion //#region src/gateway/server-node-session-runtime.ts /** Creates node registry/subscription runtime state for a gateway server. */ function createGatewayNodeSessionRuntime(params) { const nodeRegistry = new NodeRegistry(); const nodePresenceTimers = /* @__PURE__ */ new Map(); const nodeSubscriptions = createNodeSubscriptionManager(); const sessionEventSubscribers = createSessionEventSubscriberRegistry(); const sessionMessageSubscribers = createSessionMessageSubscriberRegistry(); const nodeSendEvent = (opts) => { nodeRegistry.sendEventRaw(opts.nodeId, opts.event, opts.payloadJSON ?? null); }; const nodeSendToSession = (sessionKey, event, payload) => nodeSubscriptions.sendToSession(sessionKey, event, payload, nodeSendEvent); const nodeSendToAllSubscribed = (event, payload) => nodeSubscriptions.sendToAllSubscribed(event, payload, nodeSendEvent); const broadcastVoiceWakeChanged = (triggers) => { params.broadcast("voicewake.changed", { triggers }, { dropIfSlow: true }); }; const hasTalkNodeConnected = () => hasConnectedTalkNode(nodeRegistry); return { nodeRegistry, nodePresenceTimers, sessionEventSubscribers, sessionMessageSubscribers, nodeSendToSession, nodeSendToAllSubscribed, nodeSubscribe: nodeSubscriptions.subscribe, nodeUnsubscribe: nodeSubscriptions.unsubscribe, nodeUnsubscribeAll: nodeSubscriptions.unsubscribeAll, broadcastVoiceWakeChanged, hasTalkNodeConnected }; } //#endregion export { createGatewayNodeSessionRuntime };