diff --git a/lerna.json b/lerna.json index 2ac7c299..e6af12b5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,5 @@ { "version": "0.27.6", - "useWorkspaces": true, "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index a6c2dc64..f23c674b 100644 --- a/package.json +++ b/package.json @@ -10,18 +10,19 @@ "clean": "lerna run clean", "watch": "lerna run watch --parallel", "build": "lerna run build", - "ug": "yarn upgrade-interactive --latest", + "ug": "yarn upgrade-interactive", "np": "./script/push.sh", "lsp": "npm login -scope=@ccms", "lp": "lerna publish --verify-access --force-publish", "lpb": "lerna publish --preid beta --dist-tag beta --verify-access --force-publish", "lpc": "lerna publish --canary --preid beta --pre-dist-tag beta --verify-access --force-publish", - "lpf": "lerna publish from-package --yes" + "lpf": "lerna publish from-package --yes", + "sync": "./script/sync.sh" }, "workspaces": [ "packages/*" ], "devDependencies": { - "lerna": "^6.4.1" + "lerna": "^7.1.4" } } diff --git a/packages/api/src/event.ts b/packages/api/src/event.ts index 5b50e756..591fc9de 100644 --- a/packages/api/src/event.ts +++ b/packages/api/src/event.ts @@ -25,7 +25,7 @@ export namespace event { public EventPriority = EventPriority; private mapEvent = []; - private listenerMap = []; + private pluginEventMap = []; private cacheSlowEventKey = {}; protected baseEventDir = ''; @@ -130,7 +130,7 @@ export namespace event { if (!plugin || !plugin.description || !plugin.description.name) throw new TypeError(i18n.translate("ms.api.event.listen.plugin.name.empty")) var name = plugin.description.name var eventCls = this.name2Class(name, event) - if (!eventCls) { return } + if (!eventCls) { return () => { console.warn('event ' + event + ' not found ignore off listener.') } } if (typeof priority === 'boolean') { ignoreCancel = priority priority = EventPriority.NORMAL @@ -140,16 +140,15 @@ export namespace event { // @ts-ignore let executor = exec.name || exec.executor || '[anonymous]' // noinspection JSUnusedGlobalSymbols - var listener = this.register( + let listener = this.register( eventCls, this.createExecute(name, exec, eventCls), priority, ignoreCancel ) - var listenerMap = this.listenerMap // add to cache Be used for close plugin to close event - if (!listenerMap[name]) listenerMap[name] = [] - var off = () => { + if (!this.pluginEventMap[name]) this.pluginEventMap[name] = [] + let off = () => { if (off['offed']) return off['offed'] = true this.unregister(eventCls, listener) @@ -159,7 +158,7 @@ export namespace event { exec: executor })) } - listenerMap[name].push(off) + this.pluginEventMap[name].push(off) // noinspection JSUnresolvedVariable console.debug(i18n.translate("ms.api.event.register", { name, @@ -176,10 +175,10 @@ export namespace event { * @param plugin 插件 */ disable(plugin: any) { - var eventCache = this.listenerMap[plugin.description.name] + var eventCache = this.pluginEventMap[plugin.description.name] if (eventCache) { eventCache.forEach((off: () => any) => off()) - delete this.listenerMap[plugin.description.name] + delete this.pluginEventMap[plugin.description.name] } } diff --git a/packages/api/src/particle.ts b/packages/api/src/particle.ts index 86b8f404..98dc1d5d 100644 --- a/packages/api/src/particle.ts +++ b/packages/api/src/particle.ts @@ -11,6 +11,7 @@ export namespace particle { abstract spawn(location: any, particle: Particle) abstract spawnToPlayer(player: any, location: any, particle: Particle) } + /** * 表示一个特效对象 * diff --git a/packages/api/src/task.ts b/packages/api/src/task.ts index 983c3dbf..ce4c1c62 100644 --- a/packages/api/src/task.ts +++ b/packages/api/src/task.ts @@ -1,6 +1,8 @@ -import { plugin } from './index' +import { EventEmitter } from 'events' import { injectable } from '@ccms/container' +import { plugin } from './index' + const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger") export namespace task { @@ -79,7 +81,7 @@ export namespace task { /** * 任务抽象 */ - export abstract class Task implements Cancelable { + export abstract class Task extends EventEmitter implements Cancelable { protected func: Function protected isAsync: boolean = false; protected laterTime: number = 0; @@ -88,7 +90,10 @@ export namespace task { protected taskId: number protected innerTask: any + private cancelled: boolean = false + constructor(owner: plugin.Plugin, func: Function, id: number) { + super() this.owner = owner this.func = func this.taskId = id @@ -134,20 +139,35 @@ export namespace task { */ cancel(): boolean { let result = this.cancel0() - process.emit('task.finish', this) + this.finish() + this.cancelled = true return result } protected run(...args: any[]): void { try { + this.emit('before', this) + if (this.cancelled) { return } this.func(...args) - !this.interval && process.emit('task.finish', this) - } catch (ex: any) { - console.console('§4插件执行任务时发生错误', ex) - console.ex(ex) + this.emit('after', this) + } catch (error: any) { + this.emit('error', error) + if (!error.processed) { + console.console('§4插件执行任务时发生错误', error) + console.ex(error) + this.cancel() + } + } finally { + this.emit('finally', this) + if (!this.interval && !this.cancelled) { this.finish() } } } + protected finish() { + process.emit('task.finish', this) + this.emit('finish', this) + } + /** * 提交任务 * @param args 任务参数 diff --git a/packages/common/src/reflect.ts b/packages/common/src/reflect.ts index 6dfc2c58..3f5d1b7d 100644 --- a/packages/common/src/reflect.ts +++ b/packages/common/src/reflect.ts @@ -137,7 +137,7 @@ function declaredField(clazz: java.lang.Class, name: string | java.lang.Str } catch (error: any) { if (target === undefined) { break } target = target.getSuperclass() - console.debug(`切换到超类: ${target.getName()}`) + console.debug(`switch to super class: ${target.getName()}`) } } if (field === null) { @@ -174,7 +174,7 @@ function declaredMethod(clazz: java.lang.Class, nameOrIndex: string | numbe } catch (error) { if (target === undefined) { break } target = target.getSuperclass() - console.debug(`切换到超类: ${target.getName()}`) + console.debug(`switch to super class: ${target.getName()}`) } } } @@ -187,7 +187,7 @@ function declaredMethods(clazz: java.lang.Class) { } function mapToObject(javaObj) { - if (!Java.isJavaObject(javaObj)) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) } + if (!Java.isJavaObject(javaObj)) { throw new TypeError(`argument ${javaObj} is not a java object.`) } let target = Proxy.newProxy(javaObj, { apply: (target, name, args) => { return args ? javaObj[name](args) : javaObj[name]() } }) diff --git a/packages/container/src/index.ts b/packages/container/src/index.ts index 07bd752d..cce22c94 100644 --- a/packages/container/src/index.ts +++ b/packages/container/src/index.ts @@ -154,8 +154,10 @@ export const reduceMetadata = (ctx: interfaces.Context): any => { function initAutowired(container: Container) { container.bind(ioc.Autowired).toDynamicValue((ctx) => { var metadata: any = reduceMetadata(ctx) - let key = Object.toString.call(metadata.named) + let key = Object.prototype.toString.call(metadata.named) if (key === "[object Function]" || key === "[object Symbol]") { return container.get(metadata.named) } + console.warn('container Autowired', metadata.named, 'failed. Error: illegal serviceIdentifier type', key) + console.debug(metadata.named, 'metadata', JSON.stringify(metadata)) return undefined }) } diff --git a/packages/plugin/src/command.ts b/packages/plugin/src/command.ts index 0146850d..ae486cb9 100644 --- a/packages/plugin/src/command.ts +++ b/packages/plugin/src/command.ts @@ -15,51 +15,51 @@ export class PluginCommandManager { process.on('plugin.after.disable', this.unregistryCommand.bind(this)) } - private registryCommand(pluginInstance: plugin.Plugin) { - let cmds = getPluginCommandMetadata(pluginInstance) - let tabs = getPluginTabCompleterMetadata(pluginInstance) + public registryCommand(pluginInstance: plugin.Plugin, executor: any = pluginInstance) { + let cmds = getPluginCommandMetadata(executor) + let tabs = getPluginTabCompleterMetadata(executor) for (const cmd of cmds) { if (!this.ServerChecker.check(cmd.servers)) { console.debug(`[${pluginInstance.description.name}] ${cmd.target.constructor.name} incompatible command ${cmd.name} server(${cmd.servers}) ignore.`) continue } for (let command of [cmd.name, ...cmd.alias]) { - let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, cmd, tabs.get(command)) + let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, executor, cmd, tabs.get(command)) this.CommandManager.on(pluginInstance, command, { - cmd: cmdExecutor.bind(pluginInstance), - tab: cmdCompleter?.bind(pluginInstance) + cmd: cmdExecutor.bind(executor), + tab: cmdCompleter?.bind(executor) }) } } } - private unregistryCommand(pluginInstance: plugin.Plugin) { - let cmds = getPluginCommandMetadata(pluginInstance) + public unregistryCommand(pluginInstance: plugin.Plugin, executor: any = pluginInstance) { + let cmds = getPluginCommandMetadata(executor) for (const cmd of cmds) { if (!this.ServerChecker.check(cmd.servers)) { console.debug(`[${pluginInstance.description.name}] ${cmd.target.constructor.name} incompatible command ${cmd.name} server(${cmd.servers}) ignore.`) continue } for (let command of [cmd.name, ...cmd.alias]) { - this.CommandManager.off(pluginInstance, command) + this.CommandManager.off(executor, command) } } } - private generateAutoMainCommand(pluginInstance: plugin.Plugin, cmd: interfaces.CommandMetadata, tab: interfaces.CommandMetadata) { - let cmdExecutor = pluginInstance[cmd.executor] - let cmdCompleter = tab ? pluginInstance[tab.executor] : undefined - let cmdSubCache = Object.keys(pluginInstance.constructor.prototype).filter(s => s.startsWith('cmd')).map(s => s.substring(3)) + private generateAutoMainCommand(pluginInstance: plugin.Plugin, executor: any, cmd: interfaces.CommandMetadata, tab: interfaces.CommandMetadata) { + let cmdExecutor = executor[cmd.executor] + let cmdCompleter = tab ? executor[tab.executor] : undefined + let cmdSubCache = Object.keys(executor.constructor.prototype).filter(s => s.startsWith('cmd')).map(s => s.substring(3)) if (cmd.autoMain) { cmdExecutor = (sender: any, command: string, args: string[]) => { let subcommand = args[0] let cmdKey = 'cmd' + subcommand if (!cmdSubCache.includes(subcommand)) { - if (!pluginInstance[cmd.executor].apply(pluginInstance, [sender, command, args])) { + if (!executor[cmd.executor].apply(executor, [sender, command, args])) { subcommand && pluginInstance.logger.sender(sender, `§4未知的命令: §b/${command} §c${subcommand}`) pluginInstance.logger.sender( sender, - pluginInstance['cmdhelp'] ? + executor['cmdhelp'] ? `§6请执行 §b/${command} §ahelp §6查看帮助!` : [ `§6插件: §b${pluginInstance.description.name}`, @@ -69,7 +69,7 @@ export class PluginCommandManager { } return } - let subcommandexec = pluginInstance[cmdKey] + let subcommandexec = executor[cmdKey] let permission: string if (cmd.permission && sender.hasPermission) { if (typeof cmd.permission == "string") { @@ -82,7 +82,7 @@ export class PluginCommandManager { } } args.shift() - return subcommandexec.apply(pluginInstance, [sender, ...args]) + return subcommandexec.apply(executor, [sender, ...args]) } let originCompleter = cmdCompleter cmdCompleter = (sender: any, command: string, args: string[]) => { @@ -95,7 +95,7 @@ export class PluginCommandManager { } if (!sender.hasPermission(permission)) { return [] } } - return (args.length == 1 ? cmdSubCache : []).concat(originCompleter?.apply(pluginInstance, [sender, command, args]) || []) + return (args.length == 1 ? cmdSubCache : []).concat(originCompleter?.apply(executor, [sender, command, args]) || []) } } if (!cmdCompleter) { console.debug(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`) } diff --git a/packages/plugin/src/event.ts b/packages/plugin/src/event.ts index e0bbad35..663f7d32 100644 --- a/packages/plugin/src/event.ts +++ b/packages/plugin/src/event.ts @@ -11,6 +11,8 @@ export class PluginEventManager { @Autowired() private nativePluginChecker: server.NativePluginChecker + private listenerMap = []; + constructor() { process.on('plugin.before.enable', this.registryListener.bind(this)) process.on('plugin.after.disable', this.unregistryListener.bind(this)) @@ -20,8 +22,9 @@ export class PluginEventManager { return this.eventManager.mapEventName().toFixed(0) } - private registryListener(pluginInstance: plugin.Plugin) { - let events = getPluginListenerMetadata(pluginInstance) + public registryListener(pluginInstance: plugin.Plugin, listener: any = pluginInstance) { + let events = getPluginListenerMetadata(listener) + let execes = [] for (const event of events) { // ignore space listener if (!this.serverChecker.check(event.servers)) { @@ -35,13 +38,25 @@ export class PluginEventManager { } // here must bind this to pluginInstance let exec = event.target[event.executor] - let execBinded = exec.bind(pluginInstance) + let execBinded = exec.bind(listener) execBinded.executor = event.executor exec.off = this.eventManager.listen(pluginInstance, event.name, execBinded, event.priority, event.ignoreCancel) + execes.push(exec) } + let off = () => { + if (off['offed']) return + off['offed'] = true + execes.forEach((exec: { off: () => void }) => exec.off()) + } + listener.off = off } - private unregistryListener(pluginInstance: plugin.Plugin) { - this.eventManager.disable(pluginInstance) + private unregistryListener(pluginInstance: plugin.Plugin, listener: any = pluginInstance) { + if (listener && listener.off) { + listener.off() + } + if (pluginInstance) { + this.eventManager.disable(pluginInstance) + } } } diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 6b8993d0..b574e1d8 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -10,6 +10,9 @@ export * from './manager' export * from './decorators' export * from './interfaces' +export * from './event' +export * from './command' + export { plugin as JSPlugin, cmd as Cmd, diff --git a/packages/plugin/src/interfaces.ts b/packages/plugin/src/interfaces.ts index ce3f287f..535ebaca 100644 --- a/packages/plugin/src/interfaces.ts +++ b/packages/plugin/src/interfaces.ts @@ -8,7 +8,7 @@ export namespace interfaces { @injectable() export abstract class Plugin implements plugin.Plugin { public description: plugin.PluginMetadata - public logger: Console + public logger: MiaoScriptConsole @inject(server.Console) private Console: MiaoScriptConsole @@ -28,6 +28,11 @@ export namespace interfaces { return dataFolder.getAbsolutePath() } + public registryCommand(executor: any) { } + public unregistryCommand(executor: any) { } + public registryListener(listener: any) { } + public unregistryListener(listener: any) { } + public load() { } public enable() { } public disable() { } diff --git a/script/push.sh b/script/push.sh index 732ec405..6b93bdc8 100755 --- a/script/push.sh +++ b/script/push.sh @@ -1,3 +1,4 @@ +#!/bin/bash for package in `ls packages`; do echo $package pushd packages/$package diff --git a/script/sync.sh b/script/sync.sh old mode 100644 new mode 100755 index b80977f2..29b69ee9 --- a/script/sync.sh +++ b/script/sync.sh @@ -1,3 +1,4 @@ +#!/bin/bash for PACKAGE in `ls packages`;do echo "${PACKAGE} $(curl -s "https://registry-direct.npmmirror.com/@ccms/${PACKAGE}/sync?sync_upstream=true" -X 'PUT')" done