Files
OpenParty/core/classes/PluginManager.js

122 lines
4.6 KiB
JavaScript

/**
* Plugin Manager for OpenParty
* Handles loading and managing plugins
*/
const fs = require('fs');
const path = require('path');
const Plugin = require('./Plugin'); // This is the Plugin class PluginManager uses for comparison
const { resolvePath } = require('../helper');
const Logger = require('../utils/logger');
class PluginManager {
/**
* Create a new plugin manager
*/
constructor() {
this.plugins = new Map();
this.logger = new Logger('PluginManager');
}
/**
* Load plugins from settings
* @param {Object} modules - The modules configuration from settings.json
* @returns {Map} The loaded plugins
*/
loadPlugins(modules) {
this.logger.info('Loading plugins...');
// Log the Plugin class that PluginManager is using for comparison
this.logger.info('Plugin class used for comparison:', Plugin.name);
modules.forEach((item) => {
try {
const plugin = require(resolvePath(item.path));
// Log the Plugin class that the loaded plugin is extending
this.logger.info(`Loaded plugin '${item.path}' extends:`, Object.getPrototypeOf(plugin.constructor).name);
// Verify that the plugin extends the Plugin class
if (plugin instanceof Plugin) {
this.plugins.set(plugin.name, plugin);
this.logger.info(`Loaded plugin: ${plugin.name}`);
} else {
this.logger.error(`Error: ${item.path} is not a valid plugin. It does not extend the expected 'Plugin' class.`);
// Provide more detail if the instanceof check fails
this.logger.error(`Expected Plugin constructor:`, Plugin);
this.logger.error(`Actual plugin's prototype chain constructor:`, Object.getPrototypeOf(plugin.constructor));
}
} catch (error) {
this.logger.error(`Error loading plugin ${item.path}: ${error.message}`);
}
});
return this.plugins;
}
/**
* Initialize plugins based on execution type
* @param {Express} app - The Express application instance
* @param {string} executionType - The execution type (pre-load, init, etc.)
*/
initializePlugins(app, executionType) {
this.logger.info(`Initializing ${executionType} plugins...`);
this.plugins.forEach((plugin) => {
// Assuming isEnabled() exists on the Plugin base class or is handled otherwise
if (plugin.isEnabled && plugin.isEnabled()) {
try {
// Get the plugin's configuration from settings.json
const pluginConfig = this.getPluginConfig(plugin.name);
if (pluginConfig && pluginConfig.execution === executionType) {
this.logger.info(`Calling initroute for plugin: ${plugin.name} (Execution Type: ${executionType})`);
plugin.initroute(app);
} else {
this.logger.info(`Skipping plugin ${plugin.name}: Execution type mismatch or no config.`);
}
} catch (error) {
this.logger.error(`Error initializing plugin ${plugin.name}: ${error.message}`);
}
} else {
this.logger.info(`Skipping disabled plugin: ${plugin.name}`);
}
});
}
/**
* Get a plugin by name
* @param {string} name - The name of the plugin
* @returns {Plugin|null} The plugin or null if not found
*/
getPlugin(name) {
return this.plugins.get(name) || null;
}
/**
* Get all loaded plugins
* @returns {Map} The loaded plugins
*/
getPlugins() {
return this.plugins;
}
/**
* Get the configuration for a plugin from settings.json
* @param {string} name - The name of the plugin
* @returns {Object|null} The plugin configuration or null if not found
*/
getPluginConfig(name) {
// IMPORTANT: Adjust this path if your settings.json is not located relative to PluginManager.js
// For example, if PluginManager is in 'core/classes' and settings.json is in the root,
// '../../settings.json' is likely correct.
try {
const settings = require('../../settings.json');
return settings.modules.find(module => module.name === name) || null;
} catch (error) {
this.logger.error(`Error loading settings.json: ${error.message}`);
return null;
}
}
}
module.exports = PluginManager;