Add manual plugin manager registration support

Introduces backend and frontend logic to manually register the plugin manager if not already loaded. Adds a new API endpoint and frontend UI prompt to guide users through registration after plugin installation when necessary.
This commit is contained in:
手瓜一十雪 2026-01-29 15:44:26 +08:00
parent 542036f46e
commit 7f05aee11d
4 changed files with 87 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import { WebUiDataRuntime } from '@/napcat-webui-backend/src/helper/Data';
import { sendError, sendSuccess } from '@/napcat-webui-backend/src/utils/response';
import { NapCatOneBot11Adapter } from '@/napcat-onebot/index';
import { OB11PluginMangerAdapter } from '@/napcat-onebot/network/plugin-manger';
import { webUiPathWrapper } from '@/napcat-webui-backend/index';
import path from 'path';
import fs from 'fs';
@ -13,6 +14,49 @@ const getPluginManager = (): OB11PluginMangerAdapter | null => {
return ob11.networkManager.findSomeAdapter('plugin_manager') as OB11PluginMangerAdapter;
};
// Helper to get OneBot context
const getOneBotContext = (): NapCatOneBot11Adapter | null => {
return WebUiDataRuntime.getOneBotContext() as NapCatOneBot11Adapter;
};
/**
* NetworkManager
*/
export const RegisterPluginManagerHandler: RequestHandler = async (_req, res) => {
const ob11 = getOneBotContext();
if (!ob11) {
return sendError(res, 'OneBot context not found');
}
// 检查是否已经注册
const existingManager = ob11.networkManager.findSomeAdapter('plugin_manager');
if (existingManager) {
return sendError(res, '插件管理器已经注册');
}
try {
// 确保插件目录存在
const pluginPath = webUiPathWrapper.pluginPath;
if (!fs.existsSync(pluginPath)) {
fs.mkdirSync(pluginPath, { recursive: true });
}
// 创建并注册插件管理器
const pluginManager = new OB11PluginMangerAdapter(
'plugin_manager',
ob11.core,
ob11,
ob11.actions
);
await ob11.networkManager.registerAdapterAndOpen(pluginManager);
return sendSuccess(res, { message: '插件管理器注册成功' });
} catch (e: any) {
return sendError(res, '注册插件管理器失败: ' + e.message);
}
};
export const GetPluginListHandler: RequestHandler = async (_req, res) => {
const pluginManager = getPluginManager();
if (!pluginManager) {

View File

@ -4,7 +4,8 @@ import {
SetPluginStatusHandler,
UninstallPluginHandler,
GetPluginConfigHandler,
SetPluginConfigHandler
SetPluginConfigHandler,
RegisterPluginManagerHandler
} from '@/napcat-webui-backend/src/api/Plugin';
import {
GetPluginStoreListHandler,
@ -20,6 +21,7 @@ router.post('/SetStatus', SetPluginStatusHandler);
router.post('/Uninstall', UninstallPluginHandler);
router.get('/Config', GetPluginConfigHandler);
router.post('/Config', SetPluginConfigHandler);
router.post('/RegisterManager', RegisterPluginManagerHandler);
// 插件商店相关路由
router.get('/Store/List', GetPluginStoreListHandler);

View File

@ -43,6 +43,14 @@ export default class PluginManager {
return data.data;
}
/**
* NetworkManager
*/
public static async registerPluginManager () {
const { data } = await serverRequest.post<ServerResponse<{ message: string; }>>('/Plugin/RegisterManager');
return data.data;
}
public static async setPluginStatus (name: string, enable: boolean, filename?: string) {

View File

@ -38,6 +38,7 @@ export default function PluginStorePage () {
const [loading, setLoading] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [activeTab, setActiveTab] = useState<string>('all');
const [pluginManagerNotFound, setPluginManagerNotFound] = useState(false);
const dialog = useDialog();
// 获取镜像列表
@ -52,6 +53,10 @@ export default function PluginStorePage () {
try {
const data = await PluginManager.getPluginStoreList();
setPlugins(data.plugins);
// 检查插件管理器是否已加载
const listResult = await PluginManager.getPluginList();
setPluginManagerNotFound(listResult.pluginManagerNotFound);
} catch (e: any) {
toast.error(e.message);
} finally {
@ -195,6 +200,33 @@ export default function PluginStorePage () {
} else if (data.success) {
toast.success('插件安装成功!', { id: loadingToast });
eventSource.close();
// 安装成功后检查插件管理器状态
if (pluginManagerNotFound) {
dialog.confirm({
title: '插件管理器未加载',
content: (
<div className="space-y-2">
<p className="text-sm text-default-600">
</p>
<p className="text-sm text-default-600">
</p>
</div>
),
confirmText: '注册插件管理器',
cancelText: '稍后再说',
onConfirm: async () => {
try {
await PluginManager.registerPluginManager();
toast.success('插件管理器注册成功');
setPluginManagerNotFound(false);
} catch (e: any) {
toast.error('注册失败: ' + e.message);
}
},
});
}
} else if (data.message) {
toast.loading(data.message, { id: loadingToast });
}