69 lines
3.9 KiB
TypeScript
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);
|
|
};
|
|
}
|