mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-04 06:31:13 +00:00
Refactor plugin manager to support only directory plugins
Removed support for single-file plugins in OB11PluginMangerAdapter, simplifying plugin identification to use directory names as unique IDs. Updated related logic in the backend API to align with this change, ensuring consistent plugin management and status handling.
This commit is contained in:
parent
d680328762
commit
574c257591
@ -167,29 +167,23 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
const items = fs.readdirSync(this.pluginPath, { withFileTypes: true });
|
||||
const pluginConfig = this.loadPluginConfig();
|
||||
|
||||
// 扫描文件和目录
|
||||
// 扫描文件和目录 (Only support directories as plugins now)
|
||||
for (const item of items) {
|
||||
let pluginName = '';
|
||||
if (item.isFile()) {
|
||||
pluginName = path.parse(item.name).name;
|
||||
} else if (item.isDirectory()) {
|
||||
pluginName = item.name;
|
||||
}
|
||||
|
||||
// Check if plugin is disabled in config
|
||||
if (pluginConfig[pluginName] === false) {
|
||||
this.logger.log(`[Plugin Adapter] Plugin ${pluginName} is disabled in config, skipping`);
|
||||
if (!item.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pluginId = item.name;
|
||||
|
||||
// Check if plugin is disabled in config
|
||||
if (pluginConfig[pluginId] === false) {
|
||||
this.logger.log(`[Plugin Adapter] Plugin ${pluginId} is disabled in config, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.isFile()) {
|
||||
// 处理单文件插件
|
||||
await this.loadFilePlugin(item.name);
|
||||
} else if (item.isDirectory()) {
|
||||
// 处理目录插件
|
||||
await this.loadDirectoryPlugin(item.name);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`[Plugin Adapter] Loaded ${this.loadedPlugins.size} plugins`
|
||||
@ -199,49 +193,7 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载单文件插件 (.mjs, .js)
|
||||
*/
|
||||
public async loadFilePlugin (filename: string): Promise<void> {
|
||||
// 只处理支持的文件类型
|
||||
if (!this.isSupportedFile(filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = path.join(this.pluginPath, filename);
|
||||
const pluginName = path.parse(filename).name;
|
||||
const pluginConfig = this.loadPluginConfig();
|
||||
|
||||
// Check if plugin is disabled in config
|
||||
if (pluginConfig[pluginName] === false) {
|
||||
this.logger.log(`[Plugin Adapter] Plugin ${pluginName} is disabled by user`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const module = await this.importModule(filePath);
|
||||
if (!this.isValidPluginModule(module)) {
|
||||
this.logger.logWarn(
|
||||
`[Plugin Adapter] File ${filename} is not a valid plugin (missing plugin methods)`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const plugin: LoadedPlugin = {
|
||||
name: pluginName,
|
||||
pluginPath: this.pluginPath,
|
||||
entryPath: filePath,
|
||||
module,
|
||||
};
|
||||
|
||||
await this.registerPlugin(plugin);
|
||||
} catch (error) {
|
||||
this.logger.logError(
|
||||
`[Plugin Adapter] Error loading file plugin ${filename}:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
// loadFilePlugin removed
|
||||
|
||||
/**
|
||||
* 加载目录插件
|
||||
@ -249,16 +201,10 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
public async loadDirectoryPlugin (dirname: string): Promise<void> {
|
||||
const pluginDir = path.join(this.pluginPath, dirname);
|
||||
const pluginConfig = this.loadPluginConfig();
|
||||
const pluginId = dirname; // Use directory name as unique ID
|
||||
|
||||
// Ideally we'd get the name from package.json first, but we can use dirname as a fallback identifier initially.
|
||||
// However, the list scan uses item.name (dirname) as the key. Let's stick to using dirname/filename as the config key for simplicity and consistency.
|
||||
// Wait, package.json name might override. But for management, consistent ID is better.
|
||||
// Let's check config after parsing package.json?
|
||||
// User expects to disable 'plugin-name'. But if multiple folders have same name? Not handled.
|
||||
// Let's use dirname as the key for config to be consistent with file system.
|
||||
|
||||
if (pluginConfig[dirname] === false) {
|
||||
this.logger.log(`[Plugin Adapter] Plugin ${dirname} is disabled by user`);
|
||||
if (pluginConfig[pluginId] === false) {
|
||||
this.logger.log(`[Plugin Adapter] Plugin ${pluginId} is disabled by user`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -279,9 +225,6 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if disabled by package name IF package.json exists?
|
||||
// No, file system name is more reliable ID for resource management here.
|
||||
|
||||
// 确定入口文件
|
||||
const entryFile = this.findEntryFile(pluginDir, packageJson);
|
||||
if (!entryFile) {
|
||||
@ -302,7 +245,7 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
}
|
||||
|
||||
const plugin: LoadedPlugin = {
|
||||
name: packageJson?.name || dirname,
|
||||
name: pluginId, // Use Directory Name as Internal Plugin Name/ID
|
||||
version: packageJson?.version,
|
||||
pluginPath: pluginDir,
|
||||
entryPath,
|
||||
@ -345,13 +288,7 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为支持的文件类型
|
||||
*/
|
||||
private isSupportedFile (filename: string): boolean {
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
return ['.mjs', '.js'].includes(ext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 动态导入模块
|
||||
@ -632,18 +569,8 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
await this.unloadPlugin(pluginName);
|
||||
|
||||
// 重新加载插件
|
||||
// Use logic to re-determine if it is directory or file based on original paths
|
||||
// Note: we can't fully trust fs status if it's gone.
|
||||
const isDirectory =
|
||||
plugin.pluginPath !== this.pluginPath; // Simple check: if path is nested, it's a dir plugin
|
||||
|
||||
if (isDirectory) {
|
||||
const dirname = path.basename(plugin.pluginPath);
|
||||
await this.loadDirectoryPlugin(dirname);
|
||||
} else {
|
||||
const filename = path.basename(plugin.entryPath);
|
||||
await this.loadFilePlugin(filename);
|
||||
}
|
||||
// We assume pluginName IS the directory name (the ID)
|
||||
await this.loadDirectoryPlugin(pluginName);
|
||||
|
||||
this.logger.log(
|
||||
`[Plugin Adapter] Plugin ${pluginName} reloaded successfully`
|
||||
|
||||
@ -132,13 +132,8 @@ export const SetPluginStatusHandler: RequestHandler = async (req, res) => {
|
||||
return sendError(res, 'Plugin Manager not found');
|
||||
}
|
||||
|
||||
// Calculate ID from filename (remove ext if file)
|
||||
// Or just use the logic consistent with loadPlugins
|
||||
let id = filename;
|
||||
// If it has extension .js/.mjs, remove it to get the ID used in config
|
||||
if (filename.endsWith('.js') || filename.endsWith('.mjs')) {
|
||||
id = path.parse(filename).name;
|
||||
}
|
||||
// ID IS the filename (directory name) now
|
||||
const id = filename;
|
||||
|
||||
try {
|
||||
pluginManager.setPluginStatus(id, enable);
|
||||
@ -148,19 +143,17 @@ export const SetPluginStatusHandler: RequestHandler = async (req, res) => {
|
||||
const pluginPath = pluginManager.getPluginPath();
|
||||
const fullPath = path.join(pluginPath, filename);
|
||||
|
||||
if (fs.statSync(fullPath).isDirectory()) {
|
||||
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
|
||||
await pluginManager.loadDirectoryPlugin(filename);
|
||||
} else {
|
||||
await pluginManager.loadFilePlugin(filename);
|
||||
return sendError(res, 'Plugin directory not found: ' + filename);
|
||||
}
|
||||
} else {
|
||||
// Disabling is handled inside setPluginStatus usually if implemented,
|
||||
// OR we can explicitly unload here using the loaded name.
|
||||
// The Manager's setPluginStatus implementation (if added) might logic this out.
|
||||
// But our current Manager implementation just saves config.
|
||||
// Wait, I updated Manager to try to unload.
|
||||
// Let's rely on Manager's setPluginStatus or do it here?
|
||||
// I implemented a basic unload loop in Manager.setPluginStatus.
|
||||
// Disabling behavior is managed by setPluginStatus which updates config
|
||||
// If we want to unload immediately?
|
||||
// The config update will prevent load on next startup.
|
||||
// Does pluginManager.setPluginStatus unload it?
|
||||
// Inspecting pluginManager.setPluginStatus... it iterates and unloads if match found.
|
||||
}
|
||||
|
||||
return sendSuccess(res, { message: 'Status updated successfully' });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user