Files
node_server/bot/workflow/start_node/timer_node.ts
T
2026-10-22 17:07:08 +08:00

56 lines
2.7 KiB
TypeScript

import type {Json} from '../../../types/bot/workflow/workflow.ts';
import type {WorkflowStartTemplate} from '../../../types/bot/workflow/metadata.ts';
import {describe, output} from '../metadata.ts';
export const config_template: WorkflowStartTemplate = {
name: 'timer', 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: 'repeat',
i18n: describe('定时模式', '执行一次或按间隔重复执行。'), options: [
{value: 'once', i18n: describe('一次', '一次启动被接受后停止。')},
{value: 'repeat', i18n: describe('重复', '按间隔持续尝试启动。')},
]},
{name: 'max_runs', type: 'number', nullable: true, required: false, default: null,
integer: true, min: 1, max: 100000,
i18n: describe('最大启动次数', '仅计入已启动或排队的请求;null 表示无限次。')},
{
name: 'interval_ms', type: 'number', required: true, integer: true,
min: 10, max: 2_147_483_647, default: 1000,
i18n: describe('间隔毫秒', '定时触发的间隔,必须是至少 10 毫秒的安全整数。'),
}],
output: {
...output('object', '定时数据', '每次定时触发时生成的事件名称和时间戳。'),
properties: {
event: output('string', '事件名称', '固定为 timer。'),
timestamp: output('number', '触发时间', '触发时的 Unix 时间戳,单位为毫秒。'),
},
},
};
export function schedule_timer_start(interval_ms: number,
start: (trigger: Record<string, Json>) => void): () => void {
if (!Number.isSafeInteger(interval_ms) || interval_ms < 10 || interval_ms > 2_147_483_647) {
throw new Error('Invalid workflow timer interval');
}
const timer = setTimeout(() => start({event: 'timer', timestamp: Date.now()}), interval_ms);
timer.unref?.();
return () => clearTimeout(timer);
}
export function register_timer_start(interval_ms: number,
start: (trigger: Record<string, Json>) => void): () => void {
let disposed = false;
let cancel: () => void;
const schedule = () => {
cancel = schedule_timer_start(interval_ms, trigger => {
try { start(trigger); }
finally { if (!disposed) schedule(); }
});
};
schedule();
return () => { disposed = true; cancel(); };
}