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

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 { CoolEvent, Event } from '@cool-midway/core';
import { Inject } from '@midwayjs/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_INIT = 'globalPluginInit';
// 插件移除全局事件
export const GLOBAL_EVENT_PLUGIN_REMOVE = 'globalPluginRemove';
/** /**
* *
@ -11,10 +13,24 @@ export const GLOBAL_EVENT_PLUGIN_INIT = 'globalPluginInit';
@CoolEvent() @CoolEvent()
export class PluginInitEvent { export class PluginInitEvent {
@Inject() @Inject()
pluginService: PluginService; pluginCenterService: PluginCenterService;
/**
*
* @param key
*/
@Event(GLOBAL_EVENT_PLUGIN_INIT) @Event(GLOBAL_EVENT_PLUGIN_INIT)
async globalPluginInit() { async globalPluginInit(key: string) {
await this.pluginService.reInit(); 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; key?: string;
/** 钩子 */ /** 钩子 */
hook?: string; hook?: string;
/** 是否单例 */
singleton?: boolean;
/** 版本 */ /** 版本 */
version?: string; version?: string;
/** 描述 */ /** 描述 */

View File

@ -2,7 +2,6 @@ import { Provide } from '@midwayjs/decorator';
import { import {
App, App,
IMidwayApplication, IMidwayApplication,
Init,
Inject, Inject,
InjectClient, InjectClient,
Scope, Scope,
@ -17,6 +16,7 @@ import { PluginInfo } from '../interface';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
import { CoolEventManager } from '@cool-midway/core'; import { CoolEventManager } from '@cool-midway/core';
import { PluginService } from './info';
export const PLUGIN_CACHE_KEY = 'plugin:init'; export const PLUGIN_CACHE_KEY = 'plugin:init';
@ -46,28 +46,62 @@ export class PluginCenterService {
@Inject() @Inject()
coolEventManager: CoolEventManager; coolEventManager: CoolEventManager;
@Inject()
pluginService: PluginService;
/** /**
* *
* @returns * @returns
*/ */
async init() { async init() {
const inits: any[] = (await this.midwayCache.get(PLUGIN_CACHE_KEY)) || [];
const pid = process.pid;
if (inits.includes(pid)) return;
this.plugins.clear(); this.plugins.clear();
await this.initHooks(); await this.initHooks();
await this.initPlugin(); await this.initPlugin();
await this.midwayCache.set(PLUGIN_CACHE_KEY, inits.concat([process.pid]));
this.coolEventManager.emit(EVENT_PLUGIN_READY); this.coolEventManager.emit(EVENT_PLUGIN_READY);
} }
/** /**
* *
* @param key * @param keyName key名
* @param cls
*/ */
async register(key: string, cls: any) { async initOne(keyName: string) {
this.plugins.set(key, cls); 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) { async initPlugin(condition?: {
const find: any = { status: 1 }; hook?: string;
if (hook) { id?: number;
find.hook = hook; keyName?: string;
}) {
let find: any = { status: 1 };
if (condition) {
find = {
...find,
...condition,
};
} }
const plugins = await this.pluginInfoEntity.findBy(find); const plugins = await this.pluginInfoEntity.findBy(find);
for (const plugin of plugins) { for (const plugin of plugins) {
const instance = await this.getInstance(plugin.content.data); const instance = await this.getInstance(plugin.content.data);
const pluginInfo = {
...plugin.pluginJson,
config: this.getConfig(plugin.config),
};
if (plugin.hook) { if (plugin.hook) {
this.pluginInfos.set(plugin.hook, { this.pluginInfos.set(plugin.hook, pluginInfo);
...plugin.pluginJson, await this.register(plugin.hook, instance, pluginInfo);
config: this.getConfig(plugin.config),
});
await this.register(plugin.hook, instance);
} else { } else {
this.pluginInfos.set(plugin.keyName, { this.pluginInfos.set(plugin.keyName, pluginInfo);
...plugin.pluginJson, await this.register(plugin.keyName, instance, pluginInfo);
config: this.getConfig(plugin.config),
});
await this.register(plugin.keyName, instance);
} }
} }
} }

View File

@ -5,7 +5,7 @@ import {
CoolEventManager, CoolEventManager,
} from '@cool-midway/core'; } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from '@midwayjs/typeorm';
import { Equal, Not, Repository } from 'typeorm'; import { Equal, In, Not, Repository } from 'typeorm';
import { PluginInfoEntity } from '../entity/info'; import { PluginInfoEntity } from '../entity/info';
import { import {
Config, Config,
@ -15,9 +15,12 @@ import {
} from '@midwayjs/core'; } from '@midwayjs/core';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { PluginInfo } from '../interface'; import { PluginInfo } from '../interface';
import { PLUGIN_CACHE_KEY, PluginCenterService } from './center'; import { PluginCenterService } from './center';
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; 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; coolEventManager: CoolEventManager;
/** /**
* *
* @param data * @param param
* @param type * @param type
*/ */
async modifyAfter() { async addOrUpdate(param: any, type?: 'add' | 'update') {
// 多进程发送全局事件pm2下生效 await super.addOrUpdate(param, type);
this.coolEventManager.globalEmit(GLOBAL_EVENT_PLUGIN_INIT, false); 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() { async reInit(keyName: string) {
await this.midwayCache.set(PLUGIN_CACHE_KEY, []); // 多进程发送全局事件pm2下生效本地开发则通过普通事件
await this.pluginCenterService.init(); 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 * @param ids
*/ */
async delete(ids: any) { 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.pluginInfoEntity.delete(ids);
await this.reInit();
} }
/** /**
@ -115,18 +141,19 @@ export class PluginService extends BaseService {
* @returns * @returns
*/ */
async getInstance(key: string) { async getInstance(key: string) {
await this.checkStatus(key); const check = await this.checkStatus(key);
await this.pluginCenterService.init(); if (!check) throw new CoolCommException(`插件[${key}]不存在或已禁用`);
const instance = new (await this.pluginCenterService.plugins.get(key))(); let instance;
await instance.init( const pluginInfo = this.pluginCenterService.pluginInfos.get(key);
this.pluginCenterService.pluginInfos.get(key), if (pluginInfo.singleton) {
this.ctx, instance = this.pluginCenterService.plugins.get(key);
this.app, } else {
{ instance = new (await this.pluginCenterService.plugins.get(key))();
cache: this.midwayCache, }
pluginService: this, await instance.init(pluginInfo, this.ctx, this.app, {
} cache: this.midwayCache,
); pluginService: this,
});
return instance; return instance;
} }
@ -136,15 +163,14 @@ export class PluginService extends BaseService {
*/ */
async checkStatus(key: string) { async checkStatus(key: string) {
if (Object.keys(this.hooksConfig).includes(key)) { if (Object.keys(this.hooksConfig).includes(key)) {
return; return true;
} }
const info = await this.pluginInfoEntity const info = await this.pluginInfoEntity
.createQueryBuilder('a') .createQueryBuilder('a')
.where({ status: 1, keyName: Equal(key) }) .where({ status: 1, keyName: Equal(key) })
.getOne(); .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.pluginInfoEntity.insert(data);
} }
// 初始化插件 // 初始化插件
await this.reInit(); await this.reInit(pluginJson.key);
} }
} }