UNPKG

cyberbot-next

Version:

cyberbot, 基于napcat-ts, nodejs,轻量qq机器人框架。

337 lines 11.6 kB
import * as cron from 'node-cron'; import { logger } from './logger.js'; import path from 'path'; import fs from 'fs'; import { globalJitiLoader, clearModuleCache } from './jitiLoader.js'; export class CybePlugin { client; messageHandlers = new Map(); cronJobs = []; currentContext = null; enabled = true; isSystemPlugin = false; description; cron; initialize(client) { this.client = client; if (this.enabled) { this.setup(); this.setupCronJobs(); } logger.info(`[${this.name} v${this.version}] 插件已初始化${this.description ? `: ${this.description}` : ''} (${this.enabled ? '启用' : '禁用'})`); } cleanup() { if (this.client) { for (const handler of this.messageHandlers.values()) { this.client.removeMessageListener(handler); } } this.cleanupCronJobs(); this.messageHandlers.clear(); this.currentContext = null; this.client = null; logger.info(`[${this.name}] 插件资源已清理`); } enable() { if (this.enabled) { return false; } this.enabled = true; if (this.client) { this.setup(); this.setupCronJobs(); } logger.info(`[${this.name}] 插件已启用`); return true; } disable() { if (this.isSystemPlugin) { logger.warn(`[${this.name}] 系统插件不能被禁用`); return false; } if (!this.enabled) { return false; } this.enabled = false; if (this.client) { for (const handler of this.messageHandlers.values()) { this.client.removeMessageListener(handler); } this.messageHandlers.clear(); } this.cleanupCronJobs(); logger.info(`[${this.name}] 插件已禁用`); return true; } registerMessageHandler(type, handler) { if (!this.client) { logger.error('插件未初始化'); return; } if (!this.enabled) { return; } if (this.messageHandlers.has(type)) { const oldHandler = this.messageHandlers.get(type); if (oldHandler) { this.client.removeMessageListener(oldHandler); } } const wrappedHandler = (e) => { if (!this.enabled) return; if (type === 'message' || (type === 'message.private' && 'user_id' in e && !('group_id' in e) && 'message_type' in e && e.message_type === 'private') || (type === 'message.group' && 'group_id' in e && 'message_type' in e && e.message_type === 'group') || (type === 'notice' && 'notice_type' in e) || (type === 'request' && 'request_type' in e)) { try { this.currentContext = e; this.client.currentContext = e; handler(e); } finally { this.client.currentContext = null; } } }; this.messageHandlers.set(type, wrappedHandler); this.client.onMessage(wrappedHandler); } setupCronJobs() { if (!this.cron || !this.client) return; for (const [expression, task] of this.cron) { try { const job = cron.schedule(expression, () => { try { task(this.client); } catch (error) { logger.error(`[${this.name}] 定时任务执行错误:${error}`); } }); this.cronJobs.push(job); logger.info(`[${this.name}] 定时任务已设置: ${expression}`); } catch (error) { logger.error(`[${this.name}] 定时任务设置失败:${error}`); } } } cleanupCronJobs() { for (const job of this.cronJobs) { job.stop(); } this.cronJobs = []; } getClient() { if (!this.client) { logger.error('插件未初始化'); return null; } return this.client; } reply(content, quote = false) { if (!this.currentContext) { logger.error(`[${this.name}] 回复消息失败:无法获取消息上下文`); return Promise.resolve({ message_id: 0 }); } return this.client.events.reply(this.currentContext, content, quote); } } export class PluginManager { plugins = new Map(); client; configPath; constructor(client, configPath = 'config.json') { this.client = client; this.configPath = configPath; } loadPlugin(plugin, isSystemPlugin = false) { if (this.plugins.has(plugin.name)) { logger.debug(`插件 ${plugin.name} 已经加载`); return; } try { const cybePlugin = plugin; if (isSystemPlugin) { cybePlugin.isSystemPlugin = true; cybePlugin.enabled = true; } plugin.initialize(this.client); this.plugins.set(plugin.name, cybePlugin); logger.debug(`插件 ${plugin.name} 加载成功 (${cybePlugin.enabled ? '启用' : '禁用'})`); } catch (error) { logger.error(`插件 ${plugin.name} 加载失败:${error}`); } } unloadPlugin(pluginName) { const plugin = this.plugins.get(pluginName); if (plugin) { try { plugin.cleanup(); this.plugins.delete(pluginName); logger.info(`插件 ${pluginName} 卸载成功`); return true; } catch (error) { logger.error(`插件 ${plugin.name} 卸载失败:${error}`); } } return false; } enablePlugin(pluginName) { const plugin = this.plugins.get(pluginName); if (!plugin) { logger.error(`插件 ${pluginName} 不存在`); return false; } if (plugin.enable()) { this.updatePluginConfig(pluginName, true); return true; } return false; } disablePlugin(pluginName) { const plugin = this.plugins.get(pluginName); if (!plugin) { logger.error(`插件 ${pluginName} 不存在`); return false; } if (plugin.isSystemPlugin) { logger.warn(`系统插件 ${pluginName} 不能被禁用`); return false; } if (plugin.disable()) { this.updatePluginConfig(pluginName, false); return true; } return false; } async reloadPlugin(pluginName) { const plugin = this.plugins.get(pluginName); if (!plugin) { logger.error(`插件 ${pluginName} 不存在`); return false; } try { const wasEnabled = plugin.enabled; const isSystem = plugin.isSystemPlugin; plugin.cleanup(); this.plugins.delete(pluginName); const success = await this.loadPluginFromFile(pluginName, isSystem, wasEnabled); if (success) { logger.info(`插件 ${pluginName} 重载成功`); return true; } else { logger.error(`插件 ${pluginName} 重载失败`); return false; } } catch (error) { logger.error(`插件 ${pluginName} 重载失败:${error}`); return false; } } async loadPluginFromFile(pluginName, isSystem = false, shouldEnable = true) { try { const pluginsDir = path.join(process.cwd(), 'plugins'); const pluginDir = path.join(pluginsDir, pluginName); if (!fs.existsSync(pluginDir)) { logger.error(`插件目录 ${pluginDir} 不存在`); return false; } const possibleExtensions = ['.ts', '.js']; let pluginPath = ''; let found = false; for (const ext of possibleExtensions) { const testPath = path.join(pluginDir, `index${ext}`); if (fs.existsSync(testPath)) { pluginPath = testPath; found = true; break; } } if (!found) { logger.error(`在插件 ${pluginName} 中未找到任何可用的入口文件`); return false; } clearModuleCache(pluginPath); logger.info(`正在使用 jiti 加载插件: ${pluginPath}`); const pluginModule = await globalJitiLoader.import(pluginPath); const pluginClass = Object.values(pluginModule).find((item) => typeof item === 'function' && item.name.endsWith('Plugin')); if (pluginClass) { const newPlugin = new pluginClass(); newPlugin.isSystemPlugin = isSystem; newPlugin.enabled = shouldEnable; this.loadPlugin(newPlugin, isSystem); logger.info(`插件 ${pluginName} 已从文件重新加载`); return true; } else { logger.error(`在 ${pluginName} 中未找到插件类`); return false; } } catch (error) { logger.error(`加载插件 ${pluginName} 失败:${error}`); return false; } } updatePluginConfig(pluginName, enabled) { try { const configPath = this.configPath; if (!fs.existsSync(configPath)) { logger.error('配置文件不存在'); return; } const configData = fs.readFileSync(configPath, 'utf-8'); const config = JSON.parse(configData); if (enabled) { if (!config.plugins.user.includes(pluginName)) { config.plugins.user.push(pluginName); } } else { config.plugins.user = config.plugins.user.filter((p) => p !== pluginName); } fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8'); logger.info(`插件 ${pluginName} 配置已更新`); } catch (error) { logger.error(`更新插件配置失败:${error}`); } } getLoadedPlugins() { return Array.from(this.plugins.keys()); } getPluginInfo() { const result = []; for (const [name, plugin] of this.plugins.entries()) { result.push({ name, version: plugin.version, description: plugin.description, enabled: plugin.enabled, isSystem: plugin.isSystemPlugin }); } return result; } unloadAllPlugins() { for (const [name, plugin] of this.plugins.entries()) { try { plugin.cleanup(); logger.info(`插件 ${name} 卸载成功`); } catch (error) { logger.error(`插件 ${name} 卸载失败:${error}`); } } this.plugins.clear(); } } //# sourceMappingURL=pluginManager.js.map