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 = { 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); 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 {} }