diff --git a/packages/api/src/console.ts b/packages/api/src/console.ts index 13f0895b..321aa0ea 100644 --- a/packages/api/src/console.ts +++ b/packages/api/src/console.ts @@ -26,6 +26,7 @@ global.setGlobal('MiaoScriptSourceFileMaps', sourceFileMaps) export namespace jsconsole { export function readSourceMap(fileName: string, lineNumber: any) { + if (lineNumber == 1) return { fileName, lineNumber } try { if (fileName.endsWith('js') || fileName.endsWith('ms')) { if (sourceMaps[fileName] === undefined) { @@ -68,10 +69,7 @@ export namespace jsconsole { console.ex(error) } } - return { - fileName, - lineNumber - } + return { fileName, lineNumber } } export function getStackTrace(ex: Error, color: boolean = true): string[] { diff --git a/packages/api/src/plugin.ts b/packages/api/src/plugin.ts index b1d4b3c3..27d75273 100644 --- a/packages/api/src/plugin.ts +++ b/packages/api/src/plugin.ts @@ -19,14 +19,23 @@ export namespace plugin { @injectable() export abstract class PluginManager { abstract scan(folder: string): void - abstract build(): void abstract loadFromFile(file: string, ext?: any): Plugin - abstract load(...args: any[]): void - abstract enable(...args: any[]): void - abstract disable(...args: any[]): void - abstract reload(...args: any[]): void + abstract require(loadMetadata: PluginLoadMetadata): PluginMetadata + abstract build(metadata: PluginMetadata): Plugin + abstract rebuild(plugin: plugin.Plugin): void + abstract load(plugin: plugin.Plugin): void + abstract enable(plugin: plugin.Plugin): void + abstract disable(plugin: plugin.Plugin): void + abstract reload(plugin: plugin.Plugin): void + abstract has(name: string): boolean + abstract get(name: string): plugin.Plugin abstract getPlugin(name: string): plugin.Plugin abstract getPlugins(): Map + abstract buildPlugins(): void + abstract rebuildPlugins(): void + abstract loadPlugins(): void + abstract enablePlugins(): void + abstract disablePlugins(): void } export const PluginScanner = Symbol("PluginScanner") /** @@ -38,9 +47,13 @@ export namespace plugin { */ type: string /** - * 插件文件 + * 插件文件(java.io.File) */ - file?: string + file?: any + /** + * 插件规范路径 canonicalPath + */ + path?: string /** * 插件实例 */ @@ -122,11 +135,6 @@ export namespace plugin { * @param plugin 插件 */ disable?(plugin: Plugin): void - /** - * Reload 阶段 - * @param plugin 插件 - */ - reload?(plugin: Plugin): void } export interface Plugin { description: PluginMetadata diff --git a/packages/api/src/task.ts b/packages/api/src/task.ts index f5c11cab..4b63237e 100644 --- a/packages/api/src/task.ts +++ b/packages/api/src/task.ts @@ -14,6 +14,7 @@ export namespace task { constructor() { this.taskId = new AtomicInteger(0) + process.on('core.disable', () => { this.disable() }) process.on('task.finish', (task: task.Task) => { let taskId = task.getTaskId() this.cacheTasks.delete(taskId) @@ -24,28 +25,6 @@ export namespace task { }) } - protected pluginCreate(plugin: plugin.Plugin, task: task.Task) { - if (!this.pluginCacheTasks.has(plugin.description.name)) { - this.pluginCacheTasks.set(plugin.description.name, new Map()) - } - this.pluginCacheTasks.get(plugin.description.name).set(task.getTaskId(), task) - return task - } - - protected pluginDisable(plugin: plugin.Plugin) { - if (this.pluginCacheTasks.has(plugin.description.name)) { - this.pluginCacheTasks.get(plugin.description.name).forEach((task) => task.cancel()) - this.pluginCacheTasks.delete(plugin.description.name) - } - } - - /** - * 获得自增的任务ID - */ - protected nextId() { - return this.taskId.incrementAndGet() - } - /** * 创建任务 * @param func 任务内容 @@ -73,6 +52,28 @@ export namespace task { if (plugin) { return this.pluginDisable(plugin) } this.disable0() } + + protected pluginCreate(plugin: plugin.Plugin, task: task.Task) { + if (!this.pluginCacheTasks.has(plugin.description.name)) { + this.pluginCacheTasks.set(plugin.description.name, new Map()) + } + this.pluginCacheTasks.get(plugin.description.name).set(task.getTaskId(), task) + return task + } + + protected pluginDisable(plugin: plugin.Plugin) { + if (this.pluginCacheTasks.has(plugin.description.name)) { + this.pluginCacheTasks.get(plugin.description.name).forEach((task) => task.cancel()) + this.pluginCacheTasks.delete(plugin.description.name) + } + } + + /** + * 获得自增的任务ID + */ + protected nextId() { + return this.taskId.incrementAndGet() + } protected abstract create0(owner: plugin.Plugin, func: Function, id: number): task.Task protected abstract disable0() } @@ -95,6 +96,9 @@ export namespace task { this.owner = owner this.func = func this.taskId = id + this.on('finish', () => { + process.emit('task.finish', this) + }) } getOwner() { @@ -163,7 +167,6 @@ export namespace task { } protected finish() { - process.emit('task.finish', this) this.emit('finish', this) } diff --git a/packages/compile/package.json b/packages/compile/package.json index a76e4642..26b835c2 100644 --- a/packages/compile/package.json +++ b/packages/compile/package.json @@ -23,24 +23,5 @@ "build": "pnpm clean && tsc", "test": "echo \"Error: run tests from root\" && exit 1" }, - "devDependencies": { - "@ccms/api": "^0.28.0-beta.8", - "@ccms/bukkit": "^0.28.0-beta.8", - "@ccms/bungee": "^0.28.0-beta.8", - "@ccms/common": "^0.28.0-beta.8", - "@ccms/container": "^0.28.0-beta.8", - "@ccms/core": "^0.28.0-beta.8", - "@ccms/database": "^0.28.0-beta.8", - "@ccms/i18n": "^0.28.0-beta.8", - "@ccms/molang": "^0.28.0-beta.8", - "@ccms/nashorn": "^0.28.0-beta.8", - "@ccms/nodejs": "^0.28.0-beta.8", - "@ccms/nukkit": "^0.28.0-beta.8", - "@ccms/plugin": "^0.28.0-beta.8", - "@ccms/polyfill": "^0.28.0-beta.8", - "@ccms/protocol": "^0.28.0-beta.8", - "@ccms/qrcode": "^0.28.0-beta.8", - "@ccms/sponge": "^0.28.0-beta.8", - "@ccms/websocket": "^0.28.0-beta.8" - } + "devDependencies": {} } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3fdb710f..1928ed90 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -6,7 +6,6 @@ console.i18n("ms.core.ioc.completed", { scope: global.scope, time: (Date.now() - import * as yaml from 'js-yaml' import http from '@ccms/common/dist/http' import * as fs from '@ccms/common/dist/fs' -import { VersionUtils } from '@ccms/common/dist/version' const UUID = Java.type('java.util.UUID') const MiaoScriptAPI = Java.type('pw.yumc.MiaoScript.api.MiaoScriptAPI') @@ -15,22 +14,18 @@ const MiaoScriptAPI = Java.type('pw.yumc.MiaoScript.api.MiaoScriptAPI') class MiaoScriptCore { @Autowired(server.Console) private Console: Console - @Autowired(plugin.PluginFolder) - private pluginFolder: string - @Autowired() - private taskManager: task.TaskManager @Autowired() private pluginManager: plugin.PluginManager enable() { - process.emit('core.before.enable') + process.emit('core.before.enable', this) this.loadServerConsole() try { MiaoScriptAPI.setPluginManager(this.pluginManager) } catch (error) { } - this.loadPlugins() - process.emit('core.after.enable') + process.emit('core.enable', this) + process.emit('core.after.enable', this) console.i18n("ms.core.engine.completed", { loader: base.version, version: 'v' + global.ScriptEngineVersion, @@ -40,40 +35,28 @@ class MiaoScriptCore { } loadServerConsole() { - process.emit('core.before.load.console') + process.emit('core.before.load.console', this) //@ts-ignore global.setGlobal('console', new this.Console(), { writable: false, configurable: false }) - process.emit('core.after.load.console') - } - - loadPlugins() { - process.emit('core.before.load.plugins') - let loadPluginStartTime = new Date().getTime() - console.i18n("ms.core.plugin.initialize") - this.pluginManager.scan(this.pluginFolder) - this.pluginManager.build() - this.pluginManager.load(this.pluginManager.getPlugins()) - this.pluginManager.enable(this.pluginManager.getPlugins()) - console.i18n("ms.core.plugin.completed", { time: (new Date().getTime() - loadPluginStartTime) / 1000 }) - process.emit('core.after.load.plugins') + process.emit('core.after.load.console', this) } disable() { - process.emit('core.before.disable') + process.emit('core.before.disable', this) let disableStartTime = Date.now() console.i18n("ms.core.engine.disable") - this.pluginManager.disable(this.pluginManager.getPlugins()) - this.taskManager.disable() - process.emit('core.after.disable') + process.emit('core.disable', this) + process.emit('core.after.disable', this) loadCoreScript('exit') - process.emit('core.before.exit') + process.emit('core.before.exit', this) process.exit(0) + process.emit('core.exit', this) console.i18n("ms.core.engine.disable.finish", { loader: base.version, version: 'v' + global.ScriptEngineVersion, time: (new Date().getTime() - disableStartTime) / 1000 }) - process.emit('core.after.exit') + process.emit('core.after.exit', this) } } @@ -166,14 +149,12 @@ function initialize() { global.setGlobal('loadCoreScript', loadCoreScript) loadCoreScript('initialize') try { - let core = createCore() - return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable() + return createCore() } catch (error: any) { - let core = { enable: () => () => console.i18n('ms.core.engine.disable.abnormal') } console.i18n("core.initialize.error", { error }) jsconsole.getStackTrace(error, false).forEach(line => console.log(line)) process.emit('core.initialize.error') - return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable() + return { enable: () => () => console.i18n('ms.core.engine.disable.abnormal') } } finally { process.emit('core.after.initialize') } diff --git a/packages/plugin/src/config.ts b/packages/plugin/src/config.ts index 47df238b..12d16088 100644 --- a/packages/plugin/src/config.ts +++ b/packages/plugin/src/config.ts @@ -13,6 +13,8 @@ import './config/loader' export class PluginConfigManager { @Autowired(ContainerInstance) private container: Container + @Autowired(plugin.PluginFolder) + private pluginFolder: string private configLoaderMap = new Map() @@ -31,7 +33,7 @@ export class PluginConfigManager { } getConfigLoader(format: string) { - if (!this.configLoaderMap.has(format)) { throw new Error(`Unsupport config format ${format} !`) } + if (!this.configLoaderMap.has(format)) { throw new Error(`unsupport config format ${format} !`) } return this.configLoaderMap.get(format) } @@ -68,7 +70,8 @@ export class PluginConfigManager { try { let defaultValue = metadata.default ?? plugin[metadata.variable] metadata.file = fs.concat( - fs.file(plugin.description.loadMetadata.file).parent, + root, + this.pluginFolder, plugin.description.name, metadata.filename ) @@ -85,7 +88,7 @@ export class PluginConfigManager { if (metadata.migrate && defaultValue && this.setDefaultValue(configValue, defaultValue, !!metadata.default)) { base.save(metadata.file, configLoader.dump(configValue)) } - console.debug(`[${plugin.description.name}] Load Config ${metadata.variable} from file ${metadata.file}`) + console.debug(`[${plugin.description.name}] load config ${metadata.variable} from file ${metadata.file}`) this.defienConfigProp(plugin, metadata, configValue) } catch (error: any) { console.i18n("ms.plugin.manager.config.load.error", { @@ -118,7 +121,7 @@ export class PluginConfigManager { metadata.file = fs.concat(fs.file(plugin.description.loadMetadata.file).parent, plugin.description.name, metadata.filename) let result = this.getConfigLoader(metadata.format).dump(plugin[metadata.variable]) base.save(metadata.file, result) - console.debug(`[${plugin.description.name}] Save Config ${metadata.variable} to file ${metadata.file} => + console.debug(`[${plugin.description.name}] save config ${metadata.variable} to file ${metadata.file} => ${result.substring(0, 500)}`) return true } catch (error: any) { diff --git a/packages/plugin/src/loader/basic-loader.ts b/packages/plugin/src/loader/basic-loader.ts index b56babbd..88008b91 100644 --- a/packages/plugin/src/loader/basic-loader.ts +++ b/packages/plugin/src/loader/basic-loader.ts @@ -17,11 +17,11 @@ export class BasicLoader implements plugin.PluginLoader { if (metadata?.type == this.type) { loadMetadata.metadata = metadata loadMetadata.loaded = true - this.pluginRequireMap.set(metadata.source.toString(), loadMetadata.instance) + this.pluginRequireMap.set(loadMetadata.path, loadMetadata.instance) } return loadMetadata } build(metadata: plugin.PluginMetadata) { - return this.pluginRequireMap.get(metadata.source.toString()) + return this.pluginRequireMap.get(metadata.loadMetadata.path) } } diff --git a/packages/plugin/src/loader/ioc-loader.ts b/packages/plugin/src/loader/ioc-loader.ts index 9909bab4..34914828 100644 --- a/packages/plugin/src/loader/ioc-loader.ts +++ b/packages/plugin/src/loader/ioc-loader.ts @@ -21,8 +21,8 @@ export class IocLoader implements plugin.PluginLoader { } require(loadMetadata: plugin.PluginLoadMetadata) { - let metadata = this.pluginMetadataMap.get(loadMetadata.file.toString()) - if (metadata && metadata.type == this.type) { + let metadata = this.pluginMetadataMap.get(loadMetadata.path) + if (metadata?.type == this.type) { loadMetadata.metadata = metadata loadMetadata.loaded = true } @@ -54,13 +54,6 @@ export class IocLoader implements plugin.PluginLoader { disable(plugin: plugin.Plugin): void { this.stage(plugin, 'disable') } - reload(plugin: plugin.Plugin): void { - this.disable(plugin) - //@ts-ignore - require(plugin.description.source, { cache: false }) - this.load(plugin) - this.enable(plugin) - } private bindPlugin(metadata: plugin.PluginMetadata) { if (this.container.isBoundNamed(plugin.Plugin, metadata.name)) { diff --git a/packages/plugin/src/manager.ts b/packages/plugin/src/manager.ts index 71219245..f917f57c 100644 --- a/packages/plugin/src/manager.ts +++ b/packages/plugin/src/manager.ts @@ -18,6 +18,8 @@ export class PluginManagerImpl implements plugin.PluginManager { private pluginInstance: any @Autowired(server.ServerType) private serverType: string + @Autowired(plugin.PluginFolder) + private pluginFolder: string @Autowired() private serverChecker: server.ServerChecker @@ -58,6 +60,21 @@ export class PluginManagerImpl implements plugin.PluginManager { this.eventManager this.configManager this.commandManager + process.on('core.enable', (core) => { + process.emit('core.before.load.plugins') + let loadPluginStartTime = new Date().getTime() + console.i18n("ms.core.plugin.initialize") + process.emit('core.load.plugins', this.pluginFolder) + console.i18n("ms.core.plugin.completed", { time: (new Date().getTime() - loadPluginStartTime) / 1000 }) + process.emit('core.after.load.plugins') + }) + process.on('core.load.plugins', (pluginFolder) => { + this.scan(pluginFolder) + this.buildPlugins() + this.loadPlugins() + this.enablePlugins() + }) + process.on('core.disable', () => { this.disablePlugins() }) } initialize() { @@ -86,7 +103,7 @@ export class PluginManagerImpl implements plugin.PluginManager { } scan(folder: string): void { - if (!folder) { throw new Error('plugin scan folder can\'t be empty!') } + if (!folder) { throw new Error("plugin scan folder can't be undefiend.") } this.initialize() process.emit('plugin.manager.before.scan', folder, this) for (const [, scanner] of this.sacnnerMap) { @@ -96,7 +113,7 @@ export class PluginManagerImpl implements plugin.PluginManager { console.i18n('ms.plugin.manager.scan.finish', { scanner: scanner.type, folder, size: loadMetadatas.length }) for (const loadMetadata of loadMetadatas) { try { - this.loadAndRequirePlugin(loadMetadata) + this.require(loadMetadata) } catch (error: any) { console.console(`§c扫描器 §4${scanner.type} §c文件 §4${loadMetadata.file.toString().replace(root, '')} §c编译失败 请提供下列错误给开发者`) console.ex(error) @@ -109,12 +126,6 @@ export class PluginManagerImpl implements plugin.PluginManager { process.emit('plugin.manager.after.scan', folder, this) } - build(): void { - process.emit('plugin.manager.before.build', this) - this.buildPlugins() - process.emit('plugin.manager.after.build', this) - } - private logStage(plugin: plugin.Plugin, stage: string) { console.i18n("ms.plugin.manager.stage", { stage, plugin: plugin.description.name, version: plugin.description.version, author: plugin.description.author }) } @@ -134,9 +145,9 @@ 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 file ${loadMetadata.file} is already loaded by ${loadMetadata.loader?.type}!`) } + private loadPlugin(loadMetadata: plugin.PluginLoadMetadata): plugin.PluginMetadata { + if (!loadMetadata) { throw new Error("loadMetadata can't be undefiend when loadPlugin.") } + if (loadMetadata.loaded) { throw new Error(`plugin file ${loadMetadata.file} is already loaded by ${loadMetadata.loader?.type}.`) } process.emit(`plugin.before.require`, loadMetadata) try { for (const [, loader] of this.loaderMap) { @@ -145,6 +156,8 @@ export class PluginManagerImpl implements plugin.PluginManager { } catch (error: any) { console.i18n("ms.plugin.manager.initialize.error", { name: loadMetadata.file, ex: error }) console.ex(error) + } finally { + process.emit(`plugin.after.require`, loadMetadata) } } @@ -155,19 +168,18 @@ export class PluginManagerImpl implements plugin.PluginManager { let metadata = loadMetadata.metadata if (this.metadataMap.has(metadata.name) && this.instanceMap.has(metadata.name)) { let oldMetadata = this.metadataMap.get(metadata.name) - throw new Error(`Plugin ${oldMetadata.name} is already load from ${oldMetadata.source}...`) + throw new Error(`plugin ${oldMetadata.name} is already load from ${oldMetadata.source}.`) } this.metadataMap.set(metadata.name, metadata) metadata.loadMetadata = loadMetadata - process.emit(`plugin.after.require`, loadMetadata) } return loadMetadata } catch (error: any) { if (global.debug) { - console.console(`§6Loader §b${loader.type} §6load §a${loadMetadata.file} §cerror. §4Err: §c${error}`) + 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}`) + console.warn(`loader ${loader.type} load ${loadMetadata.file} error. Err: ${error}`) } } } @@ -175,10 +187,10 @@ export class PluginManagerImpl implements plugin.PluginManager { private loadAndRequirePlugin(loadMetadata: plugin.PluginLoadMetadata) { let startTime = Date.now() let metadata = this.loadPlugin(loadMetadata.scanner.load(loadMetadata)) - if (!metadata) { throw new Error('load plugin metadata failed.') } + if (!metadata) { throw new Error(`can't load plugin from metadata: ${JSON.stringify(loadMetadata)}`) } console.i18n('ms.plugin.manager.build', { - name: loadMetadata.metadata.name, - version: loadMetadata.metadata.version, + name: metadata.name, + version: metadata.version, file: loadMetadata.file.toString().replace(root, ''), scanner: loadMetadata.scanner.type, loader: loadMetadata.loader.type, @@ -192,39 +204,54 @@ export class PluginManagerImpl implements plugin.PluginManager { * @param file java.io.File */ loadFromFile(file: string, ext: any = 'js'): plugin.Plugin { - if (!file) { throw new Error('plugin file can\'t be undefiend.') } + if (!file) { throw new Error("plugin file can't be undefiend.") } let scanner = this.sacnnerMap.get(ext) - if (!scanner) { throw new Error(`plugin scanner ${ext} can't found in sacnnerMap.`) } + if (!scanner) { throw new Error(`scanner ${ext} can't found in sacnnerMap.`) } let metadata = this.loadAndRequirePlugin(scanner.read(file)) this.buildPlugin(metadata) let plugin = metadata.target - if (!plugin) { throw new Error(`plugin scanner ${ext} can't found in sacnnerMap.`) } + if (!plugin) { throw new Error(`loader ${metadata.loadMetadata.loader.type} build plugin ${metadata.name} failed.`) } this.load(plugin) this.enable(plugin) return plugin } - load(...args: any[]): void { - this.checkAndGet(args[0]).forEach((plugin: plugin.Plugin) => this.runPluginStage(plugin, 'load')) + load(plugin: plugin.Plugin): void { + this.runPluginStage(plugin, 'load') } - enable(...args: any[]): void { - this.checkAndGet(args[0]).forEach((plugin: plugin.Plugin) => this.runPluginStage(plugin, 'enable')) + enable(plugin: plugin.Plugin): void { + this.runPluginStage(plugin, 'enable') } - disable(...args: any[]): void { - this.checkAndGet(args[0]).forEach((plugin: plugin.Plugin) => { - this.runPluginStage(plugin, 'disable') - this.metadataMap.delete(plugin.description.name) - this.instanceMap.delete(plugin.description.name) - }) + disable(plugin: plugin.Plugin): void { + this.runPluginStage(plugin, 'disable') + this.metadataMap.delete(plugin.description.name) + this.instanceMap.delete(plugin.description.name) } - reload(...args: any[]): void { - this.checkAndGet(args[0]).forEach((pl: plugin.Plugin) => { - this.disable(pl) - this.loadFromFile(pl.description.loadMetadata.file, pl.description.loadMetadata.scanner.type) - }) + reload(plugin: plugin.Plugin): void { + this.rebuild(plugin) + } + + require(loadMetadata: plugin.PluginLoadMetadata): plugin.PluginMetadata { + return this.loadAndRequirePlugin(loadMetadata) + } + + build(metadata: plugin.PluginMetadata): plugin.Plugin { + try { + return this.buildPlugin(metadata) + } catch (error: any) { + console.ex(error) + } + } + + rebuild(plugin: plugin.Plugin): void { + if (!plugin) { throw new Error(`can't run reload plugin because plugin is ${plugin}`) } + this.disable(plugin) + let loadMetadata = plugin.description.loadMetadata + delete require.cache[loadMetadata.path] + this.loadFromFile(loadMetadata.file) } has(name: string) { @@ -232,44 +259,63 @@ export class PluginManagerImpl implements plugin.PluginManager { } get(name: string) { - return this.instanceMap.get(name) || null + return this.instanceMap.get(name) } getPlugin(name: string) { - return this.instanceMap.get(name) || null + return this.instanceMap.get(name) } getPlugins() { return this.instanceMap } - private runCatch(pl: any, func: string) { - try { - if (pl[func]) pl[func].call(pl) - } catch (ex: any) { - console.i18n("ms.plugin.manager.stage.exec.error", { plugin: pl.description.name, executor: func, error: ex }) - console.ex(ex) + buildPlugins() { + process.emit('plugin.manager.before.build', this) + for (const [key, metadata] of this.metadataMap) { + if (metadata.depends?.length) { + this.lazyMetadataMap.set(key, metadata) + } else { + this.build(metadata) + } + } + for (const metadata of this.lazyMetadataMap.values()) { + this.build(metadata) + } + process.emit('plugin.manager.after.build', this) + } + + rebuildPlugins() { + for (const plugin of this.instanceMap.values()) { + this.rebuild(plugin) } } - 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) { return [name as plugin.Plugin] } - throw new Error(`Plugin ${JSON.stringify(name)} not exist.`) + loadPlugins() { + for (const plugin of this.instanceMap.values()) { + this.load(plugin) + } } - private buildPlugins() { - this.metadataMap.forEach((metadata, key) => { - if (metadata?.depends?.length) { - this.lazyMetadataMap.set(key, metadata) - } else { - this.tryBuildPlugin(metadata) - } - }) - this.lazyMetadataMap.forEach((metadata, key) => this.tryBuildPlugin(metadata)) + enablePlugins() { + for (const plugin of this.instanceMap.values()) { + this.enable(plugin) + } + } + + disablePlugins() { + for (const plugin of this.instanceMap.values()) { + this.disable(plugin) + } + } + + private runCatch(plugin: any, fn: string) { + try { + if (plugin[fn]) plugin[fn].call(plugin) + } catch (ex: any) { + console.i18n("ms.plugin.manager.stage.exec.error", { plugin: plugin.description.name, executor: fn, error: ex }) + console.ex(ex) + } } private checkDepends(depends: string | string[]) { @@ -280,18 +326,11 @@ export class PluginManagerImpl implements plugin.PluginManager { } private checkNativeDepends(depends: string | string[]) { if (!depends) return [] - let loseDepends = [] - for (const depend of depends) { if (!this.nativePluginManager.has(depend)) loseDepends.push(depend) } - return loseDepends + let loseNativeDepends = [] + for (const depend of depends) { if (!this.nativePluginManager.has(depend)) loseNativeDepends.push(depend) } + return loseNativeDepends } - private tryBuildPlugin(metadata: plugin.PluginMetadata) { - try { - return this.buildPlugin(metadata) - } catch (error: any) { - console.ex(error) - } - } private buildPlugin(metadata: plugin.PluginMetadata) { process.emit(`plugin.before.build`, metadata) @@ -304,6 +343,7 @@ export class PluginManagerImpl implements plugin.PluginManager { if (loseNativeDepends.length) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3[${loseNativeDepends.join(',')}] §4是否安装完整!`) } let pluginInstance = this.loaderMap.get(metadata.type).build(metadata) if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) } + process.emit(`plugin.build`, pluginInstance) metadata.target = pluginInstance this.instanceMap.set(metadata.name, pluginInstance) process.emit(`plugin.after.build`, metadata, pluginInstance) diff --git a/packages/plugin/src/scanner/js-scanner.ts b/packages/plugin/src/scanner/js-scanner.ts index c3e9a9fa..d9d1c5c9 100644 --- a/packages/plugin/src/scanner/js-scanner.ts +++ b/packages/plugin/src/scanner/js-scanner.ts @@ -13,15 +13,21 @@ export class JSFileScanner implements plugin.PluginScanner { } read(file: any): plugin.PluginLoadMetadata { - return { file, type: this.type, scanner: this, loaded: false } + return { + file, + path: file.canonicalPath || file.toString(), + type: this.type, + scanner: this, + loaded: false + } } - load(metadata: plugin.PluginLoadMetadata): plugin.PluginLoadMetadata { - if (metadata.type !== this.type) { return } - this.updatePlugin(metadata.file) - //@ts-ignore load plugin not use cache - metadata.instance = require(metadata.file.toString(), { cache: false }) - return metadata + load(loadMetadata: plugin.PluginLoadMetadata): plugin.PluginLoadMetadata { + if (loadMetadata.type !== this.type) { return } + this.updatePlugin(loadMetadata.file) + delete require.cache[loadMetadata.path] + loadMetadata.instance = require(loadMetadata.path) + return loadMetadata } private scanFolder(folder: any): string[] { @@ -45,7 +51,7 @@ export class JSFileScanner implements plugin.PluginScanner { } private updatePlugin(file: any) { - var update = fs.file(fs.file(fs.file(file).parentFile, 'update'), file.name) + var update = fs.file(fs.concat(file.parentFile, 'update', file.name)) if (update.exists()) { console.i18n("ms.plugin.manager.build.update", { name: file.name }) fs.move(update, file, true) diff --git a/packages/polyfill/package.json b/packages/polyfill/package.json index 5493a445..06a583fc 100644 --- a/packages/polyfill/package.json +++ b/packages/polyfill/package.json @@ -21,7 +21,7 @@ "dependencies": { "@ccms/i18n": "^0.28.0-beta.8", "@ccms/nodejs": "^0.28.0-beta.8", - "core-js": "^3.33.1" + "core-js": "^3.33.2" }, "devDependencies": { "@ccms/nashorn": "^0.28.0-beta.8" diff --git a/packages/polyfill/src/core-js.ts b/packages/polyfill/src/core-js.ts index a95f3c45..4cf620cb 100644 --- a/packages/polyfill/src/core-js.ts +++ b/packages/polyfill/src/core-js.ts @@ -1,4 +1,6 @@ 'use strict'; +// @ts-ignore +require.internal.versionLockModules['core-js'] = '3.32.2' import 'core-js/modules/es.symbol'; import 'core-js/modules/es.symbol.description'; import 'core-js/modules/es.symbol.async-iterator'; diff --git a/packages/polyfill/src/node-shim.ts b/packages/polyfill/src/node-shim.ts index 7f52b41b..622f8af6 100644 --- a/packages/polyfill/src/node-shim.ts +++ b/packages/polyfill/src/node-shim.ts @@ -18,10 +18,17 @@ const JavaScriptTask = Java.type(base.getJavaScriptTaskClass().name) const threadCount = new AtomicInteger(0) const threadGroup = new ThreadGroup("@ccms/micro-task") const microTaskPool = new ThreadPoolExecutor( - 100, 200, 60, TimeUnit.SECONDS, - new LinkedBlockingQueue(1024), + 16, 32, 64, TimeUnit.SECONDS, + new LinkedBlockingQueue(64), new ThreadFactory((run: any) => new Thread(threadGroup, run, "@ccms/micro-task-" + threadCount.incrementAndGet())) ) + +declare global { + interface Function { + thread: any; + } +} + class Process extends EventEmitter { readonly version = base.version readonly versions = [] @@ -72,6 +79,7 @@ class Process extends EventEmitter { try { microTaskPool.submit(new Callable({ call: () => { + callback.thread = Thread.currentThread(); try { callback(args) } catch (origin: any) { @@ -89,6 +97,9 @@ class Process extends EventEmitter { return console.warn(`FixedThreadPool isInterrupted exit! Task ${callback.name || ''} exec exit!`) } if (error instanceof TimeoutException) { + if (callback.thread instanceof Thread) { + console.debug(console.stack(callback.thread as any)) + } return console.warn(`Task ${callback.name || ''} => ${callback} exec time greater than ${this.queueMicrotaskExecuteTimeout}ms!`) } throw error.getCause && error.getCause() || error @@ -146,8 +157,8 @@ class EventLoop { constructor() { this.taskExecuteTimeout = parseInt(process.env.MS_TASK_EXECUTE_TIMEOUT) || 3000 this.fixedThreadPool = new ThreadPoolExecutor( - 8, 16, 0, TimeUnit.SECONDS, - new LinkedBlockingQueue(1024), + 4, 16, 32, TimeUnit.SECONDS, + new LinkedBlockingQueue(32), new ThreadFactory((run: any) => { let thread = new Thread(run, "@ccms/event-loop-" + this.threadCount.incrementAndGet()) thread.setDaemon(true) @@ -207,6 +218,7 @@ class EventLoop { try { this.fixedThreadPool.submit(new Callable({ call: () => { + callback.thread = Thread.currentThread(); try { callback.apply(undefined, args) } catch (cause: any) { @@ -225,6 +237,9 @@ class EventLoop { return console.warn(`FixedThreadPool isInterrupted exit! Task ${name} exec exit!`) } if (error instanceof TimeoutException) { + if (callback.thread instanceof Thread) { + console.debug(console.stack(callback.thread as any).join('\n')) + } return console.warn(`Task ${name} => ${callback} exec time greater than ${this.taskExecuteTimeout}ms!`) } throw error.getCause && error.getCause() || error diff --git a/packages/runtime/package.json b/packages/runtime/package.json new file mode 100644 index 00000000..cecb0ee5 --- /dev/null +++ b/packages/runtime/package.json @@ -0,0 +1,46 @@ +{ + "name": "@ccms/runtime", + "version": "0.28.0-beta.8", + "description": "development runtime", + "keywords": [ + "miaoscript", + "minecraft", + "bukkit", + "sponge" + ], + "author": "MiaoWoo ", + "homepage": "https://github.com/circlecloud/ms.git", + "license": "ISC", + "main": "dist/index.js", + "files": [ + "dist/**/*.js", + "dist/**/*.ts", + "dist/**/*.map" + ], + "scripts": { + "clean": "rimraf dist", + "watch": "tsc --watch", + "build": "pnpm clean && tsc", + "test": "echo \"Error: run tests from root\" && exit 1" + }, + "devDependencies": { + "@ccms/api": "^0.28.0-beta.8", + "@ccms/bukkit": "^0.28.0-beta.8", + "@ccms/bungee": "^0.28.0-beta.8", + "@ccms/common": "^0.28.0-beta.8", + "@ccms/container": "^0.28.0-beta.8", + "@ccms/core": "^0.28.0-beta.8", + "@ccms/database": "^0.28.0-beta.8", + "@ccms/i18n": "^0.28.0-beta.8", + "@ccms/molang": "^0.28.0-beta.8", + "@ccms/nashorn": "^0.28.0-beta.8", + "@ccms/nodejs": "^0.28.0-beta.8", + "@ccms/nukkit": "^0.28.0-beta.8", + "@ccms/plugin": "^0.28.0-beta.8", + "@ccms/polyfill": "^0.28.0-beta.8", + "@ccms/protocol": "^0.28.0-beta.8", + "@ccms/qrcode": "^0.28.0-beta.8", + "@ccms/sponge": "^0.28.0-beta.8", + "@ccms/websocket": "^0.28.0-beta.8" + } +} diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json new file mode 100644 index 00000000..7aae5d2b --- /dev/null +++ b/packages/runtime/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": "src", + "outDir": "dist" + } +} \ No newline at end of file diff --git a/packages/websocket/src/client/netty/index.ts b/packages/websocket/src/client/netty/index.ts index ec7ec1a8..6f57bdbc 100644 --- a/packages/websocket/src/client/netty/index.ts +++ b/packages/websocket/src/client/netty/index.ts @@ -147,7 +147,7 @@ export class NettyWebSocket extends Transport { })) } abortHandshake(reason: Error): void { - this.handler.abortHandshake(reason) + if (this.handler) this.handler.abortHandshake(reason) } getChannel() { return this.channel diff --git a/packages/websocket/src/client/transport.ts b/packages/websocket/src/client/transport.ts index 1e949590..056fe3f3 100644 --- a/packages/websocket/src/client/transport.ts +++ b/packages/websocket/src/client/transport.ts @@ -56,7 +56,8 @@ export abstract class Transport extends EventEmitter { this.abortHandshake(new Error(msg)); return; } - if (code != 1000 && (code < 3000 || code > 4999)) { + // if socket is clean ignore code check + if (code != 1000 && (code < 3000 || code > 4999) && !wasClean) { throw new Error(`The code must be either 1000, or between 3000 and 4999. ${code} is neither.`) } this.readyState = WebSocket.CLOSING diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13b19269..87e3ce93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,16 +42,16 @@ importers: packages/api: dependencies: '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container '@ccms/i18n': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../i18n '@ccms/polyfill': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../polyfill base64-js: specifier: ^1.5.1 @@ -67,13 +67,13 @@ importers: packages/bukkit: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container devDependencies: '@javatypes/spigot-api': @@ -83,13 +83,13 @@ importers: packages/bungee: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container devDependencies: '@javatypes/bungee-api': @@ -99,68 +99,13 @@ importers: packages/common: devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn '@javatypes/jdk': specifier: ^0.0.3 version: 0.0.3 - packages/compile: - devDependencies: - '@ccms/api': - specifier: ^0.28.0-beta.5 - version: link:../api - '@ccms/bukkit': - specifier: ^0.28.0-beta.5 - version: link:../bukkit - '@ccms/bungee': - specifier: ^0.28.0-beta.5 - version: link:../bungee - '@ccms/common': - specifier: ^0.28.0-beta.5 - version: link:../common - '@ccms/container': - specifier: ^0.28.0-beta.5 - version: link:../container - '@ccms/core': - specifier: ^0.28.0-beta.5 - version: link:../core - '@ccms/database': - specifier: ^0.28.0-beta.5 - version: link:../database - '@ccms/i18n': - specifier: ^0.28.0-beta.5 - version: link:../i18n - '@ccms/molang': - specifier: ^0.28.0-beta.5 - version: link:../molang - '@ccms/nashorn': - specifier: ^0.28.0-beta.5 - version: link:../nashorn - '@ccms/nodejs': - specifier: ^0.28.0-beta.5 - version: link:../nodejs - '@ccms/nukkit': - specifier: ^0.28.0-beta.5 - version: link:../nukkit - '@ccms/plugin': - specifier: ^0.28.0-beta.5 - version: link:../plugin - '@ccms/polyfill': - specifier: ^0.28.0-beta.5 - version: link:../polyfill - '@ccms/protocol': - specifier: ^0.28.0-beta.5 - version: link:../protocol - '@ccms/qrcode': - specifier: ^0.28.0-beta.5 - version: link:../qrcode - '@ccms/sponge': - specifier: ^0.28.0-beta.5 - version: link:../sponge - '@ccms/websocket': - specifier: ^0.28.0-beta.5 - version: link:../websocket + packages/compile: {} packages/container: dependencies: @@ -172,19 +117,19 @@ importers: version: 4.0.0 devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn packages/core: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container js-yaml: specifier: ^4.1.0 @@ -206,10 +151,10 @@ importers: packages/database: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container devDependencies: '@javatypes/spring-jdbc': @@ -223,7 +168,7 @@ importers: version: 4.1.0 devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn '@types/js-yaml': specifier: ^4.0.5 @@ -240,19 +185,19 @@ importers: packages/nodejs: devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn packages/nukkit: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container devDependencies: '@javatypes/nukkit-api': @@ -262,16 +207,16 @@ importers: packages/plugin: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container '@ccms/i18n': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../i18n '@ccms/verify': specifier: ^0.26.1 @@ -293,33 +238,90 @@ importers: packages/polyfill: dependencies: '@ccms/i18n': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../i18n '@ccms/nodejs': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nodejs core-js: - specifier: ^3.32.2 - version: 3.32.2 + specifier: ^3.33.1 + version: 3.33.1 devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn packages/protocol: {} packages/qrcode: {} + packages/runtime: + devDependencies: + '@ccms/api': + specifier: ^0.28.0-beta.8 + version: link:../api + '@ccms/bukkit': + specifier: ^0.28.0-beta.8 + version: link:../bukkit + '@ccms/bungee': + specifier: ^0.28.0-beta.8 + version: link:../bungee + '@ccms/common': + specifier: ^0.28.0-beta.8 + version: link:../common + '@ccms/container': + specifier: ^0.28.0-beta.8 + version: link:../container + '@ccms/core': + specifier: ^0.28.0-beta.8 + version: link:../core + '@ccms/database': + specifier: ^0.28.0-beta.8 + version: link:../database + '@ccms/i18n': + specifier: ^0.28.0-beta.8 + version: link:../i18n + '@ccms/molang': + specifier: ^0.28.0-beta.8 + version: link:../molang + '@ccms/nashorn': + specifier: ^0.28.0-beta.8 + version: link:../nashorn + '@ccms/nodejs': + specifier: ^0.28.0-beta.8 + version: link:../nodejs + '@ccms/nukkit': + specifier: ^0.28.0-beta.8 + version: link:../nukkit + '@ccms/plugin': + specifier: ^0.28.0-beta.8 + version: link:../plugin + '@ccms/polyfill': + specifier: ^0.28.0-beta.8 + version: link:../polyfill + '@ccms/protocol': + specifier: ^0.28.0-beta.8 + version: link:../protocol + '@ccms/qrcode': + specifier: ^0.28.0-beta.8 + version: link:../qrcode + '@ccms/sponge': + specifier: ^0.28.0-beta.8 + version: link:../sponge + '@ccms/websocket': + specifier: ^0.28.0-beta.8 + version: link:../websocket + packages/sponge: dependencies: '@ccms/api': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../api '@ccms/common': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../common '@ccms/container': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../container devDependencies: '@javatypes/sponge-api': @@ -339,7 +341,7 @@ importers: version: 0.0.6 devDependencies: '@ccms/nashorn': - specifier: ^0.28.0-beta.5 + specifier: ^0.28.0-beta.8 version: link:../nashorn '@javatypes/tomcat-websocket-api': specifier: ^0.0.3 @@ -405,7 +407,7 @@ packages: dependencies: '@ccms/i18n': 0.27.6 '@ccms/nodejs': 0.27.6 - core-js: 3.32.2 + core-js: 3.33.1 dev: false /@ccms/verify@0.26.1: @@ -1776,8 +1778,8 @@ packages: meow: 8.1.2 dev: true - /core-js@3.32.2: - resolution: {integrity: sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==} + /core-js@3.33.1: + resolution: {integrity: sha512-qVSq3s+d4+GsqN0teRCJtM6tdEEXyWxjzbhVrCHmBS5ZTM0FS2MOS0D13dUXAWDUN6a+lHI/N1hF9Ytz6iLl9Q==} requiresBuild: true dev: false