import type {bot_status} from "../../../types/bot/instance/bot_runtime"; import {BasePlugin, type PluginContext, type plugin} from "../../../types/bot/plugins/plugin"; const config_template = { name: 'auto_reconnect' as const, i18n: [{lang: 'zh-CN', name: '自动重连', description: 'Bot 连接断开后自动重连'}], version: '1.0.0', config: [ { name: 'reconnect_delay' as const, i18n: [{lang: 'zh-CN', name: '重连延时', description: '重连时的延时时间(单位:毫秒)'}], required: false, default: 1000, type: 'number', }, { name: 'reconnect_max_attempts' as const, i18n: [{lang: 'zh-CN', name: '最大重连次数', description: '最大重连次数,默认 10 次'}], required: false, default: 10, type: 'number', }, ], } satisfies plugin; type auto_reconnect_status = {attempts: number}; type auto_reconnect_config = { [K in typeof config_template['config'][number]['name']]: number; }; export class init extends BasePlugin { readonly name = 'auto_reconnect'; readonly config_template = config_template; private cleanup?: () => void; constructor() { super(); this.set_states({attempts: 0}); } async init(context: PluginContext, config: auto_reconnect_config): Promise { const delay = Number.isInteger(config.reconnect_delay) && config.reconnect_delay >= 0 && config.reconnect_delay <= 2_147_483_647 ? config.reconnect_delay : 1000; const max_attempts = Number.isInteger(config.reconnect_max_attempts) && config.reconnect_max_attempts >= 0 && config.reconnect_max_attempts < 100 ? config.reconnect_max_attempts : 10; let uninjected = false; const lost = () => { if (uninjected || this.get_status()!.attempts >= max_attempts) return; void context.schedule_reconnect(delay).catch(error => { if (context.logger) context.log([context.logger.error(`安排自动重连失败: ${String(error)}`)]); }); }; const attempt = () => { this.set_states({attempts: this.get_status()!.attempts + 1}); }; const reset = () => { if (this.get_status()!.attempts !== 0) this.set_states({attempts: 0}); }; const updated = (value: bot_status) => { if (value === 'online') reset(); }; this.cleanup = () => { if (uninjected) return; uninjected = true; context.cancel_reconnect(); context.off('connection_lost', lost); context.off('reconnect_attempt', attempt); context.off('connection_requested', reset); context.off('status_update', updated); }; context.on('connection_lost', lost); context.on('reconnect_attempt', attempt); context.on('connection_requested', reset); context.on('status_update', updated); } async dispose(): Promise { this.cleanup?.(); this.cleanup = undefined; } }