UNPKG

@diagramers/api

Version:

Diagramers API - A comprehensive Node.js API template with TypeScript, Firebase Functions, and Socket.io

233 lines (200 loc) 5.87 kB
import { BasePlugin, PluginMetadata, PluginConfig, PluginContext, PluginRegistration, PluginFactory } from './plugin'; export interface PluginManagerConfig { pluginsPath: string; autoLoad: boolean; hotReload: boolean; } export class PluginManager { private static instance: PluginManager; private plugins: Map<string, PluginRegistration> = new Map(); private factories: Map<string, PluginFactory> = new Map(); private config: PluginManagerConfig; private context: PluginContext; constructor(config: PluginManagerConfig, context: PluginContext) { this.config = config; this.context = context; } static getInstance(config?: PluginManagerConfig, context?: PluginContext): PluginManager { if (!PluginManager.instance && config && context) { PluginManager.instance = new PluginManager(config, context); } return PluginManager.instance; } /** * Register a plugin factory */ registerFactory(name: string, factory: PluginFactory): void { this.factories.set(name, factory); } /** * Load a plugin */ async loadPlugin(name: string, config: PluginConfig): Promise<void> { try { const factory = this.factories.get(name); if (!factory) { throw new Error(`Plugin factory not found: ${name}`); } const plugin = factory(config, this.context); await plugin.initialize(); const metadata = plugin.getMetadata(); this.plugins.set(name, { plugin, metadata, config }); console.log(`Plugin loaded: ${name} v${metadata.version}`); } catch (error: any) { throw new Error(`Failed to load plugin ${name}: ${error.message}`); } } /** * Start all enabled plugins */ async startPlugins(): Promise<void> { const enabledPlugins = Array.from(this.plugins.values()) .filter(registration => registration.config.enabled); for (const registration of enabledPlugins) { try { await registration.plugin.start(); console.log(`Plugin started: ${registration.metadata.name}`); } catch (error: any) { console.error(`Failed to start plugin ${registration.metadata.name}:`, error.message); } } } /** * Stop all plugins */ async stopPlugins(): Promise<void> { for (const registration of this.plugins.values()) { try { await registration.plugin.stop(); console.log(`Plugin stopped: ${registration.metadata.name}`); } catch (error: any) { console.error(`Failed to stop plugin ${registration.metadata.name}:`, error.message); } } } /** * Get a plugin by name */ getPlugin(name: string): BasePlugin | undefined { return this.plugins.get(name)?.plugin; } /** * Get all loaded plugins */ getPlugins(): BasePlugin[] { return Array.from(this.plugins.values()).map(registration => registration.plugin); } /** * Get plugin registrations */ getRegistrations(): PluginRegistration[] { return Array.from(this.plugins.values()); } /** * Check if a plugin is loaded */ isPluginLoaded(name: string): boolean { return this.plugins.has(name); } /** * Unload a plugin */ async unloadPlugin(name: string): Promise<void> { const registration = this.plugins.get(name); if (!registration) { throw new Error(`Plugin not found: ${name}`); } try { await registration.plugin.stop(); this.plugins.delete(name); console.log(`Plugin unloaded: ${name}`); } catch (error: any) { throw new Error(`Failed to unload plugin ${name}: ${error.message}`); } } /** * Get plugin health status */ async getPluginHealth(name: string): Promise<any> { const plugin = this.getPlugin(name); if (!plugin) { throw new Error(`Plugin not found: ${name}`); } return await plugin.getHealth(); } /** * Get all plugins health status */ async getAllPluginsHealth(): Promise<Record<string, any>> { const health: Record<string, any> = {}; for (const [name, registration] of this.plugins) { try { health[name] = await registration.plugin.getHealth(); } catch (error: any) { health[name] = { status: 'unhealthy', message: error.message, timestamp: new Date() }; } } return health; } /** * Get plugin metrics */ async getPluginMetrics(name: string): Promise<any> { const plugin = this.getPlugin(name); if (!plugin) { throw new Error(`Plugin not found: ${name}`); } return await plugin.getMetrics(); } /** * Get all plugins metrics */ async getAllPluginsMetrics(): Promise<Record<string, any>> { const metrics: Record<string, any> = {}; for (const [name, registration] of this.plugins) { try { metrics[name] = await registration.plugin.getMetrics(); } catch (error: any) { metrics[name] = { name, metrics: {}, timestamp: new Date(), error: error.message }; } } return metrics; } /** * Update plugin configuration */ async updatePluginConfig(name: string, config: Partial<PluginConfig>): Promise<void> { const registration = this.plugins.get(name); if (!registration) { throw new Error(`Plugin not found: ${name}`); } registration.plugin.updateConfig(config); registration.config = { ...registration.config, ...config }; console.log(`Plugin configuration updated: ${name}`); } /** * Enable a plugin */ async enablePlugin(name: string): Promise<void> { await this.updatePluginConfig(name, { enabled: true }); } /** * Disable a plugin */ async disablePlugin(name: string): Promise<void> { await this.updatePluginConfig(name, { enabled: false }); } }