mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
449 lines
12 KiB
TypeScript
449 lines
12 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
|
import { DEFAULT_LOCAL_PLUGIN_PATH, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@common/utils/plugin.tsx";
|
|
import { useFetch } from "@common/hooks/http";
|
|
import { PluginConfigType, RouteConfig } from "@common/const/type.ts";
|
|
import { ApiparkPluginDriverType ,RouterMapConfig} from "@common/const/type";
|
|
import { usePluginEventHub } from "@common/contexts/PluginEventHubContext";
|
|
import { usePluginSlotHub } from "@common/contexts/PluginSlotHubContext";
|
|
import { App } from "antd";
|
|
|
|
const mockData = {
|
|
buildAt:'2024-09-13T03:51:25Z',
|
|
build_user:'gitlab-runner',
|
|
git_commint:'6438d5aaff146dc560ed0d8563788e64a49640a5',
|
|
goversion:'go version go1.21.4 linux/amd64',
|
|
guide:true,
|
|
plugins:[
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'guide',
|
|
router:[
|
|
{
|
|
path:'guide/*',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'team',
|
|
router:[
|
|
{
|
|
path:'team',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'service',
|
|
router:[
|
|
{
|
|
path:'service',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'datasourcing',
|
|
router:[
|
|
{
|
|
path:'datasourcing',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'cluster',
|
|
router:[
|
|
{
|
|
path:'cluster',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'aisetting',
|
|
router:[
|
|
{
|
|
path:'aisetting',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'cert',
|
|
router:[
|
|
{
|
|
path:'cert',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'serviceHub',
|
|
router:[
|
|
{
|
|
path:'serviceHub',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'commonsetting',
|
|
router:[
|
|
{
|
|
path:'commonsetting',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'consumer',
|
|
router:[
|
|
{
|
|
path:'consumer',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'member',
|
|
router:[
|
|
{
|
|
path:'member',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'role',
|
|
router:[
|
|
{
|
|
path:'role',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'analytics',
|
|
router:[
|
|
{
|
|
path:'analytics',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'template',
|
|
router:[
|
|
{
|
|
path:'template/:moduleId',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'logsettings',
|
|
router:[
|
|
{
|
|
path:'logsettings/*',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'resourcesettings',
|
|
router:[
|
|
{
|
|
path:'resourcesettings/*',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'userProfile',
|
|
router:[
|
|
{
|
|
path:'userProfile',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
driver:'apipark.builtIn.component',
|
|
name:'globalPolicy',
|
|
router:[
|
|
{
|
|
path:'globalPolicy',
|
|
type:'normal'
|
|
}
|
|
]
|
|
},
|
|
// {
|
|
// "driver": "apipark.remote.normal",
|
|
// "name": "remote",
|
|
// "router": [
|
|
// {
|
|
// "path": "remote",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// },
|
|
// {
|
|
// "driver": "apipark.local.preload",
|
|
// "name": "auth",
|
|
// "router": [
|
|
// {
|
|
// "expose": "AppModule",
|
|
// "path": "auth",
|
|
// "type": "root"
|
|
// },
|
|
// {
|
|
// "expose": "AuthInfoModule",
|
|
// "path": "auth-info",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// },
|
|
// {
|
|
// "driver": "apipark.builtIn.component",
|
|
// "name": "email",
|
|
// "router": [
|
|
// {
|
|
// "path": "system/email",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// },
|
|
// {
|
|
// "driver": "apipark.builtIn.module",
|
|
// "name": "open-api",
|
|
// "router": [
|
|
// {
|
|
// "path": "system/ext-app",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// },
|
|
// {
|
|
// "driver": "apipark.local.preload",
|
|
// "name": "remote",
|
|
// "router": [
|
|
// {
|
|
// "expose": "App",
|
|
// "path": "router1/*",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// },
|
|
// {
|
|
// "driver": "apipark.remote.normal",
|
|
// "name": "apispace",
|
|
// "router": [
|
|
// {
|
|
// "path": "remote/apispace",
|
|
// "type": "normal"
|
|
// }
|
|
// ]
|
|
// }
|
|
],
|
|
powered:'Powered by https://eolink.com',
|
|
product:'apipark',
|
|
version:'6438d5aa'
|
|
}
|
|
|
|
export type ExecutePluginType = PluginConfigType & {
|
|
expose:string,
|
|
bootstrap:string
|
|
}
|
|
|
|
const usePluginLoader = (apipark:ApiparkPluginDriverType,routerMap:Map<string, RouterMapConfig>) => {
|
|
const [modules, setModules] = useState(new Map());
|
|
const [executeList, setExecuteList] = useState<ExecutePluginType[]>([]);
|
|
const [baseHref, setBaseHref] = useState('');
|
|
const [pendingTasks, setPendingTasks] = useState(0);
|
|
const {fetchData} = useFetch();
|
|
const pluginProvider = useGlobalContext();
|
|
const pluginEventHub = usePluginEventHub();
|
|
const pluginSlotHub = usePluginSlotHub();
|
|
const { getMenuList,dispatch} = pluginProvider
|
|
const { modal,message } = App.useApp()
|
|
const [startLoadExecutePlugin, setStartLoadExecutePlugin] = useState<boolean>(false)
|
|
const messageService = message;
|
|
const modalService = modal;
|
|
let startInstallPlugin = false
|
|
|
|
useEffect(()=>{
|
|
if (startLoadExecutePlugin && pendingTasks === 0 && executeList.length > 0) {
|
|
loadExecutedPlugin();
|
|
}
|
|
},[pendingTasks, executeList])
|
|
|
|
|
|
const getModule = (routerPrefix:string, specific = false) => {
|
|
if (routerPrefix.startsWith('/')) {
|
|
routerPrefix = routerPrefix.substring(1);
|
|
}
|
|
if (specific) {
|
|
return modules.get(routerPrefix);
|
|
}
|
|
let matchedModule = null;
|
|
let matchedLength = 0;
|
|
|
|
modules.forEach((value, key) => {
|
|
if (routerPrefix.startsWith(key) && key.length > matchedLength) {
|
|
matchedModule = value;
|
|
matchedLength = key.length;
|
|
}
|
|
});
|
|
return matchedModule;
|
|
};
|
|
|
|
const loadModule = async (routerPrefix: string, pluginName: any, exposedModule: string , pluginPath: any) => {
|
|
if (!modules.get(routerPrefix)) {
|
|
try {
|
|
const loadedModule = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath));
|
|
const Module = loadedModule.default ?? loadedModule
|
|
let ModuleBootstrap;
|
|
try {
|
|
ModuleBootstrap = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, 'Bootstrap', pluginPath));
|
|
} catch (error) {
|
|
console.warn('Bootstrap module not found:', error);
|
|
}
|
|
setModules(prevModules => new Map(prevModules).set(routerPrefix,Module[exposedModule] ));
|
|
if (!validateExportLifecycle(Module)) {
|
|
console.error('需要导出插件生命周期函数');
|
|
return;
|
|
}
|
|
await Module.bootstrap?.({
|
|
pluginProvider,
|
|
pluginEventHub,
|
|
pluginSlotHub
|
|
});
|
|
return Module;
|
|
} catch (error) {
|
|
console.error('导入插件失败:', error);
|
|
}
|
|
}
|
|
return getModule(routerPrefix, true);
|
|
};
|
|
|
|
const loadExecutedPlugin = async () => {
|
|
setStartLoadExecutePlugin(true)
|
|
for (const plugin of executeList) {
|
|
try {
|
|
const Module = await loadRemoteModule(generateRemoteModuleTemplate(plugin.name, plugin?.expose || 'Bootstrap', plugin.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${plugin.name}/apipark.js`));
|
|
const bootstrap = Module.bootstrap;
|
|
if (!bootstrap) {
|
|
console.warn('立即执行插件未导出Bootstrap模块或bootstrap函数');
|
|
} else {
|
|
await bootstrap({
|
|
pluginEventHub,
|
|
pluginSlotHub,
|
|
pluginProvider,
|
|
platformProvider:null,
|
|
messageService,
|
|
modalService,
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('执行插件失败:', error);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
const loadPlugins = () => {
|
|
return new Promise((resolve) => {
|
|
if(startInstallPlugin) {
|
|
return resolve(true)
|
|
}
|
|
startInstallPlugin = true
|
|
installPlugin().then(async (res)=>{
|
|
// reset route after loading executed plugins
|
|
await loadExecutedPlugin();
|
|
return resolve(res)
|
|
})
|
|
});
|
|
};
|
|
|
|
const installPlugin = () => {
|
|
return new Promise((resolve, reject) => {
|
|
// fetchData('system/plugins',{method:'GET'}).then((resp) => {
|
|
// if (resp.code === 0){
|
|
const resp = {data:mockData}
|
|
dispatch({type:'UPDATE_VERSION',version:resp.data.version})
|
|
dispatch({type:'UPDATE_DATE',updateDate:resp.data.buildAt})
|
|
dispatch({type:'UPDATE_POWER',powered:resp.data.powered})
|
|
const driverMethod = { apipark: apipark };
|
|
const pluginConfigList = resp.data.plugins;
|
|
const pluginLoader = { loadModule };
|
|
const pluginLifecycleGuard ={};
|
|
const builtInPluginLoader = loadBuiltInModule;
|
|
pluginSlotHub.addSlot('renewMenu', () => {
|
|
getMenuList()
|
|
});
|
|
for (const plugin of pluginConfigList) {
|
|
try {
|
|
const driverName = plugin.driver;
|
|
if (!driverName) {
|
|
console.error('no driver name');
|
|
continue;
|
|
}
|
|
const driver = driverName.split('.').reduce((driverMethod: { [x: string]: any; }, driverName: string | number) => driverMethod[driverName], driverMethod);
|
|
if(driverName.split('.')[2] === 'preload'){
|
|
setPendingTasks(prev => prev + 1);
|
|
}
|
|
;(driver as Function )?.({ setExecuteList:(callback:ExecutePluginType[]) => {
|
|
setExecuteList(callback);
|
|
setPendingTasks(prev => prev - 1);
|
|
}, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin);
|
|
} catch (err) {
|
|
console.warn('安装插件出错:', err);
|
|
}
|
|
}
|
|
resolve(true);
|
|
// } else {
|
|
// messageService.error(resp.msg || '获取插件配置列表失败,请重试!');
|
|
// reject(new Error(resp.msg || '获取插件配置列表失败'));
|
|
// }
|
|
// });
|
|
}
|
|
);
|
|
};
|
|
|
|
const loadBuiltInModule = (pluginName: any) => {
|
|
try {
|
|
const { module } = routerMap.get(pluginName)!;
|
|
return module;
|
|
} catch (err) {
|
|
console.warn(`安装内置插件[${pluginName}]出错:`, err);
|
|
}
|
|
};
|
|
|
|
return {
|
|
loadPlugins,
|
|
loadModule,
|
|
loadExecutedPlugin,
|
|
setBaseHref,
|
|
getModule
|
|
};
|
|
};
|
|
|
|
export default usePluginLoader; |