chore: src/modules/plugin/service/center.ts

This commit is contained in:
2026-07-01 17:57:04 +08:00
parent 5b7ce22be0
commit 077eb3a7cd
+224
View File
@@ -0,0 +1,224 @@
import {
App,
IMidwayApplication,
Inject,
InjectClient,
Scope,
Provide,
ScopeEnum,
} from '@midwayjs/core';
import * as fs from 'fs';
import * as path from 'path';
import { PluginInfoEntity } from '../entity/info';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { PluginInfo } from '../interface';
import * as _ from 'lodash';
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
import { CoolEventManager } from '@cool-midway/core';
import { PluginService } from './info';
export const PLUGIN_CACHE_KEY = 'plugin:init';
export const EVENT_PLUGIN_READY = 'EVENT_PLUGIN_READY';
/**
* 插件中心
*/
@Provide()
@Scope(ScopeEnum.Singleton)
export class PluginCenterService {
// 插件列表
plugins: Map<string, any> = new Map();
// 插件配置
pluginInfos: Map<string, PluginInfo> = new Map();
@App()
app: IMidwayApplication;
@InjectEntityModel(PluginInfoEntity)
pluginInfoEntity: Repository<PluginInfoEntity>;
@InjectClient(CachingFactory, 'default')
midwayCache: MidwayCache;
@Inject()
coolEventManager: CoolEventManager;
@Inject()
pluginService: PluginService;
/**
* 初始化
* @returns
*/
async init() {
this.plugins.clear();
await this.initHooks();
await this.initPlugin();
this.coolEventManager.emit(EVENT_PLUGIN_READY);
}
/**
* 初始化一个
* @param keyName key名
*/
async initOne(keyName: string) {
await this.initPlugin({
keyName,
});
this.coolEventManager.emit(EVENT_PLUGIN_READY, keyName);
}
/**
* 移除插件
* @param keyName
* @param isHook
*/
async remove(keyName: string, isHook = false) {
this.plugins.delete(keyName);
this.pluginInfos.delete(keyName);
if (isHook) {
await this.initHooks();
}
}
/**
* 注册插件
* @param key 唯一标识
* @param cls 类
* @param pluginInfo 插件信息
*/
async register(key: string, cls: any, pluginInfo?: PluginInfo) {
// 单例插件
if (pluginInfo?.singleton) {
const instance = new cls();
await instance.init(this.pluginInfos.get(key), null, this.app, {
cache: this.midwayCache,
pluginService: this.pluginService,
});
this.plugins.set(key, instance);
} else {
// 普通插件
this.plugins.set(key, cls);
}
}
/**
* 初始化钩子
*/
async initHooks() {
const hooksPath = path.join(
this.app.getBaseDir(),
'modules',
'plugin',
'hooks'
);
for (const key of fs.readdirSync(hooksPath)) {
const stat = fs.statSync(path.join(hooksPath, key));
if (!stat.isDirectory()) {
continue;
}
const { Plugin } = await import(path.join(hooksPath, key, 'index'));
await this.register(key, Plugin);
this.pluginInfos.set(key, {
name: key,
config: this.app.getConfig('module.plugin.hooks.' + key),
});
}
}
/**
* 初始化插件
* @param condition 插件条件
*/
async initPlugin(condition?: {
hook?: string;
id?: number;
keyName?: string;
}) {
let find: any = { status: 1 };
if (condition) {
find = {
...find,
...condition,
};
}
const plugins = await this.pluginInfoEntity.find({
where: find,
select: [
'id',
'name',
'description',
'keyName',
'hook',
'version',
'pluginJson',
'config',
],
});
for (const plugin of plugins) {
const data = await this.pluginService.getData(plugin.keyName);
if (!data) {
continue;
}
const instance = await this.getInstance(data.content.data);
const pluginInfo = {
...plugin.pluginJson,
config: this.getConfig(plugin.config),
};
if (plugin.hook) {
this.pluginInfos.set(plugin.hook, pluginInfo);
await this.register(plugin.hook, instance, pluginInfo);
} else {
this.pluginInfos.set(plugin.keyName, pluginInfo);
await this.register(plugin.keyName, instance, pluginInfo);
}
}
}
/**
* 获得配置
* @param config
* @returns
*/
private getConfig(config: any) {
// 处理配置为字符串的情况
if (typeof config === 'string') {
try {
config = JSON.parse(config);
} catch (e) {
return {};
}
}
// 如果配置为空或非对象类型,则返回空对象
if (!config || typeof config !== 'object') {
return {};
}
const env = this.app.getEnv();
let isMulti = false;
for (const key in config) {
if (key.includes('@')) {
isMulti = true;
break;
}
}
return isMulti ? config[`@${env}`] : config;
}
/**
* 获得实例
* @param content
* @returns
*/
async getInstance(content: string) {
let _instance;
const script = `
${content}
_instance = Plugin;
`;
eval(script);
return _instance;
}
}