diff --git a/src/modules/plugin/event/init.ts b/src/modules/plugin/event/init.ts index 884c815..4a55409 100644 --- a/src/modules/plugin/event/init.ts +++ b/src/modules/plugin/event/init.ts @@ -1,9 +1,11 @@ import { CoolEvent, Event } from '@cool-midway/core'; import { Inject } from '@midwayjs/core'; -import { PluginService } from '../service/info'; +import { PluginCenterService } from '../service/center'; // 插件初始化全局事件 export const GLOBAL_EVENT_PLUGIN_INIT = 'globalPluginInit'; +// 插件移除全局事件 +export const GLOBAL_EVENT_PLUGIN_REMOVE = 'globalPluginRemove'; /** * 接收事件 @@ -11,10 +13,24 @@ export const GLOBAL_EVENT_PLUGIN_INIT = 'globalPluginInit'; @CoolEvent() export class PluginInitEvent { @Inject() - pluginService: PluginService; + pluginCenterService: PluginCenterService; + /** + * 插件初始化事件,某个插件重新初始化 + * @param key + */ @Event(GLOBAL_EVENT_PLUGIN_INIT) - async globalPluginInit() { - await this.pluginService.reInit(); + async globalPluginInit(key: string) { + await this.pluginCenterService.initOne(key); + } + + /** + * 插件移除或者关闭事件 + * @param key + * @param isHook + */ + @Event(GLOBAL_EVENT_PLUGIN_REMOVE) + async globalPluginRemove(key: string, isHook: boolean) { + await this.pluginCenterService.remove(key, isHook); } } diff --git a/src/modules/plugin/interface.ts b/src/modules/plugin/interface.ts index dffc225..5af915d 100644 --- a/src/modules/plugin/interface.ts +++ b/src/modules/plugin/interface.ts @@ -8,6 +8,8 @@ export interface PluginInfo { key?: string; /** 钩子 */ hook?: string; + /** 是否单例 */ + singleton?: boolean; /** 版本 */ version?: string; /** 描述 */ diff --git a/src/modules/plugin/service/center.ts b/src/modules/plugin/service/center.ts index 929d26a..1955dae 100644 --- a/src/modules/plugin/service/center.ts +++ b/src/modules/plugin/service/center.ts @@ -2,7 +2,6 @@ import { Provide } from '@midwayjs/decorator'; import { App, IMidwayApplication, - Init, Inject, InjectClient, Scope, @@ -17,6 +16,7 @@ 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'; @@ -46,28 +46,62 @@ export class PluginCenterService { @Inject() coolEventManager: CoolEventManager; + @Inject() + pluginService: PluginService; + /** * 初始化 * @returns */ async init() { - const inits: any[] = (await this.midwayCache.get(PLUGIN_CACHE_KEY)) || []; - const pid = process.pid; - if (inits.includes(pid)) return; this.plugins.clear(); await this.initHooks(); await this.initPlugin(); - await this.midwayCache.set(PLUGIN_CACHE_KEY, inits.concat([process.pid])); this.coolEventManager.emit(EVENT_PLUGIN_READY); } /** - * 注册插件 - * @param key - * @param cls + * 初始化一个 + * @param keyName key名 */ - async register(key: string, cls: any) { - this.plugins.set(key, cls); + async initOne(keyName: string) { + await this.initPlugin({ + 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); + } } /** @@ -96,27 +130,33 @@ export class PluginCenterService { /** * 初始化插件 + * @param condition 插件条件 */ - async initPlugin(hook?: string) { - const find: any = { status: 1 }; - if (hook) { - find.hook = hook; + async initPlugin(condition?: { + hook?: string; + id?: number; + keyName?: string; + }) { + let find: any = { status: 1 }; + if (condition) { + find = { + ...find, + ...condition, + }; } const plugins = await this.pluginInfoEntity.findBy(find); for (const plugin of plugins) { const instance = await this.getInstance(plugin.content.data); + const pluginInfo = { + ...plugin.pluginJson, + config: this.getConfig(plugin.config), + }; if (plugin.hook) { - this.pluginInfos.set(plugin.hook, { - ...plugin.pluginJson, - config: this.getConfig(plugin.config), - }); - await this.register(plugin.hook, instance); + this.pluginInfos.set(plugin.hook, pluginInfo); + await this.register(plugin.hook, instance, pluginInfo); } else { - this.pluginInfos.set(plugin.keyName, { - ...plugin.pluginJson, - config: this.getConfig(plugin.config), - }); - await this.register(plugin.keyName, instance); + this.pluginInfos.set(plugin.keyName, pluginInfo); + await this.register(plugin.keyName, instance, pluginInfo); } } } diff --git a/src/modules/plugin/service/info.ts b/src/modules/plugin/service/info.ts index 2c5391d..6d61c6c 100644 --- a/src/modules/plugin/service/info.ts +++ b/src/modules/plugin/service/info.ts @@ -5,7 +5,7 @@ import { CoolEventManager, } from '@cool-midway/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Equal, Not, Repository } from 'typeorm'; +import { Equal, In, Not, Repository } from 'typeorm'; import { PluginInfoEntity } from '../entity/info'; import { Config, @@ -15,9 +15,12 @@ import { } from '@midwayjs/core'; import * as _ from 'lodash'; import { PluginInfo } from '../interface'; -import { PLUGIN_CACHE_KEY, PluginCenterService } from './center'; +import { PluginCenterService } from './center'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; -import { GLOBAL_EVENT_PLUGIN_INIT } from '../event/init'; +import { + GLOBAL_EVENT_PLUGIN_INIT, + GLOBAL_EVENT_PLUGIN_REMOVE, +} from '../event/init'; /** * 插件信息 @@ -46,21 +49,41 @@ export class PluginService extends BaseService { coolEventManager: CoolEventManager; /** - * 初始化 - * @param data + * 新增或更新 + * @param param * @param type */ - async modifyAfter() { - // 多进程发送全局事件,pm2下生效 - this.coolEventManager.globalEmit(GLOBAL_EVENT_PLUGIN_INIT, false); + async addOrUpdate(param: any, type?: 'add' | 'update') { + await super.addOrUpdate(param, type); + const info = await this.pluginInfoEntity.findOneBy({ id: param.id }); + if (info.status == 1) { + await this.reInit(info.keyName); + } else { + await this.remove(info.keyName, !!info.hook); + } } /** - * 需要重新初始化插件 + * 重新初始化插件 */ - async reInit() { - await this.midwayCache.set(PLUGIN_CACHE_KEY, []); - await this.pluginCenterService.init(); + async reInit(keyName: string) { + // 多进程发送全局事件,pm2下生效,本地开发则通过普通事件 + this.coolEventManager.globalEmit(GLOBAL_EVENT_PLUGIN_INIT, false, keyName); + } + + /** + * 移除插件 + * @param keyName + * @param isHook + */ + async remove(keyName: string, isHook = false) { + // 多进程发送全局事件,pm2下生效 + this.coolEventManager.globalEmit( + GLOBAL_EVENT_PLUGIN_REMOVE, + false, + keyName, + isHook + ); } /** @@ -68,8 +91,11 @@ export class PluginService extends BaseService { * @param ids */ async delete(ids: any) { + const list = await this.pluginInfoEntity.findBy({ id: In(ids) }); + for (const item of list) { + await this.remove(item.keyName, !!item.hook); + } await this.pluginInfoEntity.delete(ids); - await this.reInit(); } /** @@ -115,18 +141,19 @@ export class PluginService extends BaseService { * @returns */ async getInstance(key: string) { - await this.checkStatus(key); - await this.pluginCenterService.init(); - const instance = new (await this.pluginCenterService.plugins.get(key))(); - await instance.init( - this.pluginCenterService.pluginInfos.get(key), - this.ctx, - this.app, - { - cache: this.midwayCache, - pluginService: this, - } - ); + const check = await this.checkStatus(key); + if (!check) throw new CoolCommException(`插件[${key}]不存在或已禁用`); + let instance; + const pluginInfo = this.pluginCenterService.pluginInfos.get(key); + if (pluginInfo.singleton) { + instance = this.pluginCenterService.plugins.get(key); + } else { + instance = new (await this.pluginCenterService.plugins.get(key))(); + } + await instance.init(pluginInfo, this.ctx, this.app, { + cache: this.midwayCache, + pluginService: this, + }); return instance; } @@ -136,15 +163,14 @@ export class PluginService extends BaseService { */ async checkStatus(key: string) { if (Object.keys(this.hooksConfig).includes(key)) { - return; + return true; } const info = await this.pluginInfoEntity .createQueryBuilder('a') .where({ status: 1, keyName: Equal(key) }) .getOne(); - if (!info) { - throw new CoolCommException(`插件[${key}]不存在或已禁用`); - } + + return !!info; } /** @@ -277,6 +303,6 @@ export class PluginService extends BaseService { await this.pluginInfoEntity.insert(data); } // 初始化插件 - await this.reInit(); + await this.reInit(pluginJson.key); } }