Files
node_server/utils/plugin_event_handler.ts
2026-10-22 17:07:08 +08:00

47 lines
2.6 KiB
TypeScript

import type {Socket} from 'socket.io-client';
import {get_bot_context} from '../bot/instance/index.ts';
import {PluginError, type PluginErrorReason} from '../bot/plugins/error.ts';
import {plain_plugin_object, valid_plugin_config, valid_plugin_name, valid_plugin_path} from './plugin_validation.ts';
import {validate_code_map} from './validate_code_map.ts';
const codes = validate_code_map.plugin;
const errors: Record<PluginErrorReason, number> = {
INVALID_CONFIG: codes.invalid_config, ALREADY_INSTALLED: codes.already_installed,
NOT_INSTALLED: codes.not_installed, MANAGER_DISPOSED: codes.manager_disposed,
LOAD_FAILED: codes.load_failed, INIT_FAILED: codes.init_failed, DISPOSE_FAILED: codes.dispose_failed,
};
export async function plugin_event_handler(operation: 'inject' | 'uninject' | 'update_config', socket: Socket, data: unknown, callback: unknown) {
if (typeof callback !== 'function') {
socket.emit('error', {error: validate_code_map.web.method_not_allowed});
return;
}
let code: number = validate_code_map.web.invalid_parameter;
try {
const fields = operation === 'inject' ? ['bot_id', 'path', 'name', 'config']
: operation === 'update_config' ? ['bot_id', 'name', 'config'] : ['bot_id', 'name'];
if (plain_plugin_object(data) && Object.keys(data).length === fields.length
&& fields.every(field => Object.hasOwn(data, field))
&& typeof data.bot_id === 'number' && Number.isSafeInteger(data.bot_id) && data.bot_id > 0
&& valid_plugin_name(data.name)
&& (operation !== 'inject' || valid_plugin_path(data.path))
&& (operation === 'uninject' || valid_plugin_config(data.config))) {
const context = get_bot_context(data.bot_id);
const manager = context?.plugin_manager;
if (!context) code = codes.context_missing;
else if (!manager) code = codes.manager_missing;
else {
if (operation === 'inject') await manager.inject({name: data.name, path: data.path as string, config: data.config});
else if (operation === 'uninject') await manager.uninject(data.name);
else await manager.update_config(data.name, data.config as Record<string, unknown>);
code = codes.ok;
}
}
} catch (error) {
code = error instanceof PluginError ? errors[error.reason] ?? codes.error : codes.error;
}
// A transport callback can throw; never retry it or expose its exception to the dispatcher.
try { callback({status: code === codes.ok ? 'success' : 'error', data: code}); }
catch {}
}