Files
2026-10-22 17:07:08 +08:00

69 lines
3.9 KiB
TypeScript

import type {bot_event_name, bot_instance_context} from '../../instance/bot_instance_init.ts';
import type {BranchState} from '../../../types/bot/workflow/runtime.ts';
import type {Json, workflow_config} from '../../../types/bot/workflow/workflow.ts';
import type {WorkflowStartTemplate} from '../../../types/bot/workflow/metadata.ts';
import {assert_json, evaluate_condition} from '../runtime/value.ts';
import {normalize_event} from '../node_action/event_node/registry.ts';
import {describe, output} from '../metadata.ts';
export const config_template: WorkflowStartTemplate = {
name: 'event', version: '1.0.0',
i18n: describe('事件启动', '机器人出生并就绪后,监听指定事件并按可选条件启动工作流。'),
config: [
{name: 'auto_start', type: 'boolean', required: false, default: true,
i18n: describe('自动监听', '机器人连接并出生后自动监听事件。')},
{name: 'mode', type: 'select', required: false, default: 'continuous',
i18n: describe('监听模式', '持续监听,或在一次启动被接受后停止监听。'), options: [
{value: 'continuous', i18n: describe('持续', '持续接受匹配的事件。')},
{value: 'once', i18n: describe('一次', '接受一次启动或排队后停止;忙碌跳过时继续监听。')},
]},
{name: 'event', type: 'string', required: true, provider: 'event',
i18n: describe('事件名称', '选择已描述的事件或填写自定义事件名称;不允许 workflow_update。')},
{name: 'condition', type: 'condition', required: false,
i18n: describe('触发条件', '使用标准化后的 trigger 数据判断;支持多个条件全部满足(and/且)、任一满足(or/或)和嵌套分组。条件为真时启动,引用缺失时跳过。')},
],
output: {
...output('object', '事件数据', '具体字段由所选事件模板定义;未知事件输出 {event, args}。'),
properties: {event: output('string', '事件名称', '当前订阅的事件名称。')},
additional_properties: output('json', '事件字段', '事件适配器提供的有界 JSON 数据。'),
},
};
export function create_event_handler(definition: workflow_config,
start: (trigger: Record<string, Json>) => void): (...args: unknown[]) => void {
if (definition.start.type !== 'event' || definition.start.event === 'workflow_update') {
throw new Error('Invalid workflow event trigger');
}
const config = definition.start;
return (...args: unknown[]) => {
if (config.event === 'any' && args[0] === 'workflow_update') return;
try {
if (args.length > 32) return;
const trigger = normalize_event(config.event, args);
if (!trigger) return;
assert_json(trigger);
if (Buffer.byteLength(JSON.stringify(trigger)) > 65_536) return;
if (config.condition) {
const state: BranchState = {trigger, vars: structuredClone(definition.initial_vars ?? {}),
outputs: {}, last_result: null, inputs: {}, retry_counts: {}};
if (!evaluate_condition(config.condition, state)) return;
}
start(trigger);
} catch { /* Unsupported payloads and missing condition references skip this occurrence. */ }
};
}
export function register_event_start(context: Pick<bot_instance_context<any>, 'on' | 'off'>,
definition: workflow_config, start: (trigger: Record<string, Json>) => void): () => void {
const callback = create_event_handler(definition, start);
const event = (definition.start as {event: string}).event as bot_event_name;
try { context.on(event, callback); }
catch (error) { context.off(event, callback); throw error; }
let disposed = false;
return () => {
if (disposed) return;
disposed = true;
context.off(event, callback);
};
}