From e28af3fbbcab576a3b2f873b35be00ebbf1d0dc4 Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Tue, 30 Jun 2020 15:58:51 +0800 Subject: [PATCH] feat: optimize process & plugin loader and scanner Signed-off-by: MiaoWoo --- packages/core/src/index.ts | 1 - packages/ployfill/src/node-shim.ts | 5 +-- packages/plugin/src/decorators.ts | 29 ++++++--------- packages/plugin/src/loader/basic-loader.ts | 4 +-- packages/plugin/src/manager.ts | 35 +++++++++++++------ .../src/internal/scanner/mysql-scanner.ts | 10 +++++- 6 files changed, 50 insertions(+), 34 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index a5495b37..382cac49 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -53,7 +53,6 @@ class MiaoScriptCore { console.i18n("ms.core.engine.disable") this.pluginManager.disable(this.pluginManager.getPlugins()) this.taskManager.disable() - process.emit('exit', 0) process.exit(0) } } diff --git a/packages/ployfill/src/node-shim.ts b/packages/ployfill/src/node-shim.ts index 7ce0b14f..67761407 100644 --- a/packages/ployfill/src/node-shim.ts +++ b/packages/ployfill/src/node-shim.ts @@ -28,8 +28,9 @@ class Process extends EventEmitter { queueMicrotask(func: Function) { microTaskPool.execute(func) } - exit() { - microTaskPool.shutdown(); + exit(code: number) { + process.emit('exit', code) + microTaskPool.shutdown() } } global.setGlobal('process', new Process(), {}) diff --git a/packages/plugin/src/decorators.ts b/packages/plugin/src/decorators.ts index e1ebdfd6..5259d328 100644 --- a/packages/plugin/src/decorators.ts +++ b/packages/plugin/src/decorators.ts @@ -79,23 +79,16 @@ export function config(metadata: interfaces.ConfigMetadata = {}) { } } -function stage(metadata: interfaces.ExecMetadata = {}, stage: string) { - return function (target: any, key: string, value: any) { - metadata.name = metadata.name || key - metadata.executor = key - const previousMetadata: interfaces.ExecMetadata[] = getPluginStageMetadata(target, stage) - Reflect.defineMetadata(METADATA_KEY.stage[stage], [metadata, ...previousMetadata], target.constructor) +function stage(stage: string) { + return (metadata: interfaces.ExecMetadata = {}) => { + return function (target: any, key: string, value: any) { + metadata.name = metadata.name || key + metadata.executor = key + const previousMetadata: interfaces.ExecMetadata[] = getPluginStageMetadata(target, stage) + Reflect.defineMetadata(METADATA_KEY.stage[stage], [metadata, ...previousMetadata], target.constructor) + } } } - -export function load(metadata: interfaces.ExecMetadata = {}) { - return stage(metadata, 'load') -} - -export function enable(metadata: interfaces.ExecMetadata = {}) { - return stage(metadata, 'enable') -} - -export function disable(metadata: interfaces.ExecMetadata = {}) { - return stage(metadata, 'disable') -} +export const load = stage('load') +export const enable = stage('enable') +export const disable = stage('disable') diff --git a/packages/plugin/src/loader/basic-loader.ts b/packages/plugin/src/loader/basic-loader.ts index 80b7645c..4bc3c25d 100644 --- a/packages/plugin/src/loader/basic-loader.ts +++ b/packages/plugin/src/loader/basic-loader.ts @@ -11,8 +11,8 @@ export class BasicLoader implements plugin.PluginLoader { this.pluginRequireMap = new Map() } require(loadMetadata: plugin.PluginLoadMetadata) { - let metadata = loadMetadata.instance.description - if (metadata && metadata.type == this.type) { + let metadata = loadMetadata.instance?.description + if (metadata?.type == this.type) { loadMetadata.metadata = metadata loadMetadata.loaded = true this.pluginRequireMap.set(metadata.source.toString(), loadMetadata.instance) diff --git a/packages/plugin/src/manager.ts b/packages/plugin/src/manager.ts index 1508a25a..98b5f43b 100644 --- a/packages/plugin/src/manager.ts +++ b/packages/plugin/src/manager.ts @@ -56,6 +56,7 @@ export class PluginManagerImpl implements plugin.PluginManager { this.loaderMap.set(loader.type, loader) }) this.initialized = true + process.emit('plugin.initialize') } } @@ -77,10 +78,12 @@ export class PluginManagerImpl implements plugin.PluginManager { console.ex(error) } } + process.emit('plugin.scan', folder) } build(): void { this.buildPlugins() + process.emit('plugin.build') } private logStage(plugin: plugin.Plugin, stage: string) { @@ -101,14 +104,25 @@ export class PluginManagerImpl implements plugin.PluginManager { } private loadPlugin(loadMetadata: plugin.PluginLoadMetadata) { + if (!loadMetadata) { throw new Error('loadMetadata can\'t be undefiend when loadPlugin!') } + if (loadMetadata.loaded) { throw new Error(`Plugin ${loadMetadata.name} is already loaded by ${loadMetadata.loader?.type}!`) } try { for (const [, loader] of this.loaderMap) { - if (loader.require(loadMetadata).loaded) { - loadMetadata.loader = loader - let metadata = loadMetadata.metadata - this.metadataMap.set(metadata.name, metadata) - metadata.loadMetadata = loadMetadata - return metadata + try { + if (loader.require(loadMetadata).loaded) { + loadMetadata.loader = loader + let metadata = loadMetadata.metadata + this.metadataMap.set(metadata.name, metadata) + metadata.loadMetadata = loadMetadata + return metadata + } + } catch (error) { + if (global.debug) { + console.console(`§6Loader §b${loader.type} §6load §a${loadMetadata.file} §cerror. §4Err: §c${error}`) + console.ex(error) + } else { + console.warn(`Loader ${loader.type} load ${loadMetadata.file} error. Err: ${error}`) + } } } } catch (error) { @@ -123,8 +137,8 @@ export class PluginManagerImpl implements plugin.PluginManager { * @param file java.io.File */ loadFromFile(file: string, scanner = this.sacnnerMap.get('file')): plugin.Plugin { - if (!file) { throw new Error('plugin file can\'t be null!') } - if (!scanner) { throw new Error('plugin scanner can\'t be null!') } + if (!file) { throw new Error('plugin file can\'t be undefiend!') } + if (!scanner) { throw new Error('plugin scanner can\'t be undefiend!') } let metadata = this.loadPlugin(scanner.read(file)) let plugin = metadata.loadMetadata.loader.build(metadata) this.load(plugin) @@ -162,7 +176,7 @@ export class PluginManagerImpl implements plugin.PluginManager { reload(...args: any[]): void { this.checkAndGet(args[0]).forEach((pl: plugin.Plugin) => { this.disable(pl) - this.loadFromFile(pl.description.source, pl.description.loadMetadata.scanner) + this.loadFromFile(pl.description.source.toString(), pl.description.loadMetadata.scanner) }) } @@ -184,10 +198,11 @@ export class PluginManagerImpl implements plugin.PluginManager { } private checkAndGet(name: string | plugin.Plugin | undefined | any): Map | plugin.Plugin[] { + if (name === undefined) throw new Error(`checkAndGet Plugin can't be undefiend!`) if (name == this.instanceMap) { return this.instanceMap } if (typeof name == 'string' && this.instanceMap.has(name)) { return [this.instanceMap.get(name)] } if (name instanceof interfaces.Plugin) { return [name as plugin.Plugin] } - if (name.description || name.description.name) { return [name as plugin.Plugin] } + if (name.description?.name) { return [name as plugin.Plugin] } throw new Error(`Plugin ${JSON.stringify(name)} not exist!`) } diff --git a/packages/spring/src/internal/scanner/mysql-scanner.ts b/packages/spring/src/internal/scanner/mysql-scanner.ts index e1b960f6..052b9cba 100644 --- a/packages/spring/src/internal/scanner/mysql-scanner.ts +++ b/packages/spring/src/internal/scanner/mysql-scanner.ts @@ -14,6 +14,7 @@ export class MySQLScanner implements plugin.PluginScanner { type: string = "mysql" private cacheDir = 'mysql-plugin-cache' + private cacheFileMap: Map = new Map() private target: string @inject(database.DataBaseManager) @@ -25,7 +26,14 @@ export class MySQLScanner implements plugin.PluginScanner { return plugins.map(p => this.read(p)) } read(mysqlPlugin: MySQLPlugin): plugin.PluginLoadMetadata { - return { name: mysqlPlugin.name, file: fs.concat(root, this.cacheDir, `${mysqlPlugin.name}.js`), type: this.type, mysqlPlugin, scanner: this } + // if invoke this function from loadFromFile mysqlPlugin is a string need read from cache + if (typeof mysqlPlugin == "string") { + if (!this.cacheFileMap.has(mysqlPlugin)) { throw new Error(`this file ${mysqlPlugin} is not read from mysql-scanner. can't reload from this scanner!`) } + mysqlPlugin = this.cacheFileMap.get(mysqlPlugin) + } + let cacheFile = fs.concat(root, this.cacheDir, `${mysqlPlugin.name}.js`) + this.cacheFileMap.set(cacheFile, mysqlPlugin) + return { name: mysqlPlugin.name, file: cacheFile, type: this.type, mysqlPlugin, scanner: this } } load(metadata: plugin.PluginLoadMetadata) { if (metadata.type !== this.type) { return }