UNPKG

mira-app-core

Version:

Core library for Mira TypeScript project - provides base functionality without auto-execution

205 lines 8.38 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ServerPluginManager = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); class ServerPluginManager { constructor({ server, dbService, pluginsDir }) { this.loadedPlugins = new Map(); this.fields = []; this.pluginsDir = path.join(pluginsDir ?? __dirname, 'plugins'); console.log({ pluginsDir: this.pluginsDir }); this.server = server; this.dbService = dbService; this.pluginsConfigPath = path.join(this.pluginsDir, 'plugins.json'); // Ensure plugins directory exists if (!fs.existsSync(this.pluginsDir)) { fs.mkdirSync(this.pluginsDir, { recursive: true }); } // Initialize plugins.json if it doesn't exist if (!fs.existsSync(this.pluginsConfigPath)) { fs.writeFileSync(this.pluginsConfigPath, JSON.stringify([], null, 2)); } } // getPluginDir getPluginDir(pluginName) { return path.join(this.pluginsDir, pluginName); } async loadPlugins(reload = false) { const config = JSON.parse(fs.readFileSync(this.pluginsConfigPath, 'utf-8')); for (const pluginConfig of config) { if (pluginConfig.enabled) { await this.loadPlugin(pluginConfig, reload); } } } async loadPlugin(pluginConfig, reload = false) { try { // 检查插件是否已经加载过 if (!reload && this.loadedPlugins.has(pluginConfig.name)) { console.log(`Plugin ${pluginConfig.name} already loaded, skipping...`); return; } const pluginPath = path.join(this.pluginsDir, pluginConfig.path); // 如果是重新加载,清除require缓存 if (reload || this.loadedPlugins.has(pluginConfig.name)) { delete require.cache[require.resolve(pluginPath)]; } const pluginModule = require(pluginPath); if (typeof pluginModule.init === 'function') { await pluginModule.init({ pluginManager: this, server: this.server, dbService: this.dbService }); } this.loadedPlugins.set(pluginConfig.name, pluginModule); console.log(`${reload ? 'Reloaded' : 'Loaded'} plugin: ${pluginConfig.name}`); } catch (err) { console.error(`Failed to load plugin ${pluginConfig.name}:`, err); // 如果加载失败,从已加载插件中移除 this.loadedPlugins.delete(pluginConfig.name); } } registerFields(fields) { for (const field of fields) { this.registerField(field); } } registerField(field) { let { action, type, field: fieldName } = field; if (!fieldName || !action || !type) { throw new Error('Field registration error: action, type, and field are required'); } this.fields.push(field); } getPlugin(name) { return this.loadedPlugins.get(name); } isPluginLoaded(name) { return this.loadedPlugins.has(name); } unloadPlugin(name) { if (this.loadedPlugins.has(name)) { // 尝试调用插件的清理函数(如果存在) const plugin = this.loadedPlugins.get(name); if (plugin && typeof plugin.cleanup === 'function') { try { plugin.cleanup(); } catch (error) { console.error(`Error cleaning up plugin ${name}:`, error); } } this.loadedPlugins.delete(name); console.log(`Unloaded plugin: ${name}`); return true; } return false; } async reloadPlugin(name) { const config = JSON.parse(fs.readFileSync(this.pluginsConfigPath, 'utf-8')); const pluginConfig = config.find(p => p.name === name); if (!pluginConfig) { console.error(`Plugin config not found for: ${name}`); return false; } if (!pluginConfig.enabled) { console.log(`Plugin ${name} is disabled, skipping reload`); return false; } // 先卸载插件 this.unloadPlugin(name); // 重新加载插件 await this.loadPlugin(pluginConfig, true); return this.isPluginLoaded(name); } getPluginsList() { const config = JSON.parse(fs.readFileSync(this.pluginsConfigPath, 'utf-8')); return config.map(pluginConfig => { const pluginDir = this.getPluginDir(pluginConfig.name); let packageInfo = {}; try { const packageJsonPath = path.join(pluginDir, 'package.json'); if (fs.existsSync(packageJsonPath)) { packageInfo = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); } } catch (error) { console.error(`Error reading package.json for plugin ${pluginConfig.name}:`, error); } // 检查是否有图标文件 let icon = null; const iconExtensions = ['.png', '.jpg', '.jpeg', '.svg', '.ico']; for (const ext of iconExtensions) { const iconPath = path.join(pluginDir, `icon${ext}`); if (fs.existsSync(iconPath)) { // 返回相对于插件目录的路径,前端可以通过API获取 icon = `/api/plugins/${pluginConfig.name}/icon${ext}`; break; } } return { name: pluginConfig.name, enabled: pluginConfig.enabled, path: pluginConfig.path, ...packageInfo, status: pluginConfig.enabled ? 'active' : 'inactive', configurable: true, icon: icon || packageInfo.icon || null, // 支持package.json中的icon字段 category: packageInfo.category || 'general', // 添加分类 tags: packageInfo.tags || [] // 添加标签 }; }); } async addPlugin(config) { const currentConfig = JSON.parse(fs.readFileSync(this.pluginsConfigPath, 'utf-8')); const existingIndex = currentConfig.findIndex(p => p.name === config.name); if (existingIndex >= 0) { currentConfig[existingIndex] = config; } else { currentConfig.push(config); } fs.writeFileSync(this.pluginsConfigPath, JSON.stringify(currentConfig, null, 2)); if (config.enabled) { await this.loadPlugin(config, true); // 使用 reload=true 确保新插件被加载 } } } exports.ServerPluginManager = ServerPluginManager; //# sourceMappingURL=ServerPluginManager.js.map