支持单例插件,完善插件初始化方式

This commit is contained in:
cool 2024-03-26 16:29:35 +08:00
parent 64c00cbf16
commit aab2c47898
4 changed files with 142 additions and 58 deletions

View File

@ -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);
}
}

View File

@ -8,6 +8,8 @@ export interface PluginInfo {
key?: string;
/** 钩子 */
hook?: string;
/** 是否单例 */
singleton?: boolean;
/** 版本 */
version?: string;
/** 描述 */

View File

@ -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);
}
}
}

View File

@ -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);
}
}