From 16fcbfa69c5c8abbe2703ef3ce1399ef863e2c18 Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Tue, 2 Jun 2020 17:50:47 +0800 Subject: [PATCH] feat: complate server & update spring Signed-off-by: MiaoWoo --- packages/api/src/interfaces/server/index.ts | 139 +++++++++++++++++--- packages/bukkit/src/server.ts | 46 +------ packages/sponge/src/server.ts | 46 +------ packages/spring/src/command.ts | 12 +- packages/spring/src/index.ts | 5 +- packages/spring/src/internal/command.ts | 59 +++++++++ packages/spring/src/server.ts | 35 ++--- packages/spring/src/task.ts | 12 +- packages/websocket/src/tomcat/server.ts | 2 +- 9 files changed, 230 insertions(+), 126 deletions(-) create mode 100644 packages/spring/src/internal/command.ts diff --git a/packages/api/src/interfaces/server/index.ts b/packages/api/src/interfaces/server/index.ts index 1e05f7ba..1c52d4c4 100644 --- a/packages/api/src/interfaces/server/index.ts +++ b/packages/api/src/interfaces/server/index.ts @@ -1,38 +1,143 @@ +import * as reflect from '@ccms/common/dist/reflect' +import { injectable } from '@ccms/container' + import { NativePluginManager } from './native_plugin' +import { constants } from '../../constants' export namespace server { /** * Runtime ServerType */ - export const ServerType = Symbol("ServerType"); + export const ServerType = Symbol("ServerType") /** * Runtime Console */ - export const Console = Symbol("Console"); + export const Console = Symbol("Console") /** * MiaoScript Server */ - export const Server = Symbol("Server"); + export const Server = Symbol("Server") /** * Runtime Server Instance */ - export const ServerInstance = Symbol("ServerInstance"); + export const ServerInstance = Symbol("ServerInstance") /** * MiaoScript Server */ export interface Server { - getVersion(): string; - getPlayer(name: string): any; - getOnlinePlayers(): any[]; - getConsoleSender(): any; - getService(service: string): any; - dispatchCommand(sender: string | any, command: string): boolean; - dispatchConsoleCommand(command: string): boolean; - getPluginsFolder(): string; - getNativePluginManager(): NativePluginManager; - getNettyPipeline(): any; - getRootLogger(): any; - sendJson(sender: string | any, json: object | string): void; - tabComplete?(sender: string | any, input: string, index?: number); + getVersion(): string + getPlayer(name: string): any + getOnlinePlayers(): any[] + getConsoleSender(): any + getService(service: string): any + dispatchCommand(sender: string | any, command: string): boolean + dispatchConsoleCommand(command: string): boolean + getPluginsFolder(): string + getNativePluginManager(): NativePluginManager + getDedicatedServer?(): any + getNettyPipeline(): any + getRootLogger(): any + sendJson(sender: string | any, json: object | string): void + tabComplete?(sender: string | any, input: string, index?: number) + } + @injectable() + export abstract class ReflectServer implements server.Server { + protected pipeline: any + protected rootLogger: any + + constructor() { + this.reflect() + } + + getVersion(): string { + throw new Error("Method not implemented.") + } + getPlayer(name: string) { + throw new Error("Method not implemented.") + } + getOnlinePlayers(): any[] { + throw new Error("Method not implemented.") + } + getConsoleSender() { + throw new Error("Method not implemented.") + } + getService(service: string) { + throw new Error("Method not implemented.") + } + dispatchCommand(sender: any, command: string): boolean { + throw new Error("Method not implemented.") + } + dispatchConsoleCommand(command: string): boolean { + throw new Error("Method not implemented.") + } + getPluginsFolder(): string { + throw new Error("Method not implemented.") + } + getNativePluginManager(): NativePluginManager { + throw new Error("Method not implemented.") + } + getDedicatedServer() { + throw new Error("Method not implemented.") + } + getNettyPipeline() { + throw new Error("Method not implemented.") + } + getRootLogger() { + throw new Error("Method not implemented.") + } + sendJson(sender: any, json: string | object): void { + throw new Error("Method not implemented.") + } + tabComplete?(sender: any, input: string, index?: number) { + throw new Error("Method not implemented.") + } + protected reflect() { + try { + let consoleServer = this.getDedicatedServer() + this.reflectPipeline(consoleServer) + this.reflectRootLogger(consoleServer) + } catch (error) { + console.error('Error When Reflect MinecraftServer!', error) + console.ex(error) + } + } + protected reflectPipeline(consoleServer: any) { + let connection: any + let promise: any + for (const method of constants.Reflect.Method.getServerConnection) { + try { + connection = reflect.on(consoleServer).call(method).get() + if (connection.class.name.indexOf('ServerConnection') !== -1 + || connection.class.name.indexOf('NetworkSystem') !== -1) { break } + connection = undefined + } catch (error) { } + } + if (!connection) { console.error("Can't found ServerConnection!"); return } + for (const field of constants.Reflect.Field.listeningChannels) { + try { + promise = reflect.on(connection).get(field).get().get(0) + if (promise.class.name.indexOf('Promise') !== -1) { break } + promise = undefined + } catch (error) { } + } + if (!promise) { console.error("Can't found listeningChannels!"); return } + this.pipeline = reflect.on(promise).get('channel').get().pipeline() + } + protected reflectRootLogger(consoleServer: any) { + try { + this.rootLogger = reflect.on(consoleServer).get('LOGGER').get().parent + } catch (error) { + try { this.rootLogger = reflect.on(consoleServer).get(0).get().parent } catch (error) { } + } + if (this.rootLogger && this.rootLogger.class.name.indexOf('Logger') === -1) { + console.error('Error Logger Class: ' + this.rootLogger.class.name) + this.rootLogger = undefined + } + // get root logger + for (let index = 0; index < 5 && this.rootLogger.parent; index++) { + this.rootLogger = this.rootLogger.parent + } + if (!this.rootLogger) { console.error("Can't found rootLogger!") } + } } } diff --git a/packages/bukkit/src/server.ts b/packages/bukkit/src/server.ts index 61307d90..44fc0686 100644 --- a/packages/bukkit/src/server.ts +++ b/packages/bukkit/src/server.ts @@ -7,14 +7,12 @@ import chat from './enhance/chat' let Bukkit = org.bukkit.Bukkit; @provideSingleton(server.Server) -export class BukkitServer implements server.Server { +export class BukkitServer extends server.ReflectServer { private pluginsFolder: string; - private pipeline: any; - private rootLogger: any; constructor() { + super(); this.pluginsFolder = Bukkit.getUpdateFolderFile().getParentFile().getCanonicalPath(); - this.reflect() } getPlayer(name: string) { @@ -47,6 +45,9 @@ export class BukkitServer implements server.Server { getNativePluginManager() { return Bukkit.getPluginManager() as any; } + getDedicatedServer() { + return reflect.on(Bukkit.getServer()).get('console').get() + } getNettyPipeline() { return this.pipeline; } @@ -62,41 +63,4 @@ export class BukkitServer implements server.Server { this.dispatchConsoleCommand(result) } } - - private reflect() { - let consoleServer = reflect.on(Bukkit.getServer()).get('console').get() - this.reflectPipeline(consoleServer) - this.reflectRootLogger(consoleServer) - } - - private reflectPipeline(consoleServer: any) { - let connection: any; - let promise: any; - for (const method of constants.Reflect.Method.getServerConnection) { - try { - connection = reflect.on(consoleServer).call(method).get() - if (connection.class.name.indexOf('ServerConnection') !== -1 - || connection.class.name.indexOf('NetworkSystem') !== -1) { break; } - connection = undefined; - } catch (error) { } - } - if (!connection) { console.error("Can't found ServerConnection!"); return } - for (const field of constants.Reflect.Field.listeningChannels) { - try { - promise = reflect.on(connection).get(field).get().get(0); - if (promise.class.name.indexOf('Promise') !== -1) { break; } - promise = undefined; - } catch (error) { } - } - if (!promise) { console.error("Can't found listeningChannels!"); return } - this.pipeline = reflect.on(promise).get('channel').get().pipeline() - } - - private reflectRootLogger(consoleServer: any) { - try { - this.rootLogger = reflect.on(consoleServer).get('LOGGER').get().parent - } catch (error) { - console.error("Can't found rootLogger!") - } - } } diff --git a/packages/sponge/src/server.ts b/packages/sponge/src/server.ts index 151d2192..33f84a3f 100644 --- a/packages/sponge/src/server.ts +++ b/packages/sponge/src/server.ts @@ -8,14 +8,12 @@ const TextSerializers = org.spongepowered.api.text.serializer.TextSerializers; const File = Java.type("java.io.File"); @provideSingleton(server.Server) -export class SpongeServer implements server.Server { +export class SpongeServer extends server.ReflectServer { private pluginsFolder: string; - private pipeline: any; - private rootLogger: any; constructor() { + super(); this.pluginsFolder = new File(base.getInstance().getClass().getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile().getCanonicalPath() - this.reflect() } getPlayer(name: string) { @@ -37,10 +35,10 @@ export class SpongeServer implements server.Server { if (typeof sender === 'string') { sender = this.getPlayer(sender) } - return Sponge.getCommandManager().process(sender, command).getQueryResult() + return Sponge.getCommandManager().process(sender, command).getQueryResult().get() } dispatchConsoleCommand(command: string): boolean { - return Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command).getQueryResult() + return Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command).getQueryResult().get() } getPluginsFolder(): string { return this.pluginsFolder; @@ -48,6 +46,9 @@ export class SpongeServer implements server.Server { getNativePluginManager() { return Sponge.getPluginManager() as any; } + getDedicatedServer() { + return reflect.on(Sponge.getServer()).get() + } getNettyPipeline() { return this.pipeline; } @@ -60,37 +61,4 @@ export class SpongeServer implements server.Server { } sender.sendMessage(TextSerializers.JSON.deserialize(json)) } - private reflect() { - let consoleServer = reflect.on(Sponge.getServer()).get() - this.reflectPipeline(consoleServer) - this.reflectRootLogger(consoleServer) - } - private reflectPipeline(consoleServer: any) { - let connection: any; - let promise: any; - for (const method of constants.Reflect.Method.getServerConnection) { - try { - connection = reflect.on(consoleServer).call(method).get() - if (connection.class.name.indexOf('NetworkSystem') !== -1) { break; } - connection = undefined; - } catch (error) { } - } - if (!connection) { console.error("Can't found ServerConnection!"); return } - for (const field of constants.Reflect.Field.listeningChannels) { - try { - promise = reflect.on(connection).get(field).get().get(0); - if (promise.class.name.indexOf('Promise') !== -1) { break; } - promise = undefined; - } catch (error) { } - } - if (!promise) { console.error("Can't found listeningChannels!"); return } - this.pipeline = reflect.on(promise).get('channel').get().pipeline() - } - private reflectRootLogger(consoleServer: any) { - try { - this.rootLogger = reflect.on(consoleServer).get('LOGGER').get().parent - } catch (error) { - console.error("Can't found rootLogger!") - } - } } diff --git a/packages/spring/src/command.ts b/packages/spring/src/command.ts index ab05d5af..6e0834be 100644 --- a/packages/spring/src/command.ts +++ b/packages/spring/src/command.ts @@ -3,21 +3,25 @@ import '@ccms/nashorn' import { command, plugin } from '@ccms/api' import { inject, provideSingleton, postConstruct } from '@ccms/container' +import { CommandMap } from './internal/command' + @provideSingleton(command.Command) export class SpringCommand extends command.Command { @inject(plugin.PluginInstance) private pluginInstance: any + @inject(CommandMap) + private commandMap: CommandMap = new CommandMap() protected create(plugin: any, command: string) { - console.console('§4Spring暂不支持create命令!') + return this.commandMap.register(plugin, command) } protected remove(plugin: any, command: string) { - console.console('§4Spring暂不支持remove命令!') + this.commandMap.unregister(plugin, command) } protected onCommand(plugin: any, command: any, executor: Function) { - console.console('§4Spring暂不支持onCommand!') + command.setExecutor(super.setExecutor(plugin, command, executor)) } protected onTabComplete(plugin: any, command: any, tabCompleter: Function) { - console.console('§4Spring暂不支持onTabComplete!') + command.setTabCompleter(super.setExecutor(plugin, command, tabCompleter)) } } diff --git a/packages/spring/src/index.ts b/packages/spring/src/index.ts index d70928b4..8f8df628 100644 --- a/packages/spring/src/index.ts +++ b/packages/spring/src/index.ts @@ -1,5 +1,6 @@ -import { server, plugin } from '@ccms/api' +import { server } from '@ccms/api' import { Container } from '@ccms/container' +import '@ccms/database' import { SpringConsole } from './console'; import './event'; @@ -7,8 +8,6 @@ import './server'; import './command'; import './task'; -const BeanKit = Java.type('com.sixi.micro.common.kits.BeanKit') - export default function SpringImpl(container: Container) { container.bind(server.Console).toConstantValue(SpringConsole) } diff --git a/packages/spring/src/internal/command.ts b/packages/spring/src/internal/command.ts new file mode 100644 index 00000000..21d75401 --- /dev/null +++ b/packages/spring/src/internal/command.ts @@ -0,0 +1,59 @@ +import { provideSingleton } from "@ccms/container" +import { plugin } from "@ccms/api" + +type CommandExec = (sender: any, _: any, command: string, args: string[]) => boolean +type TabCompleter = (sender: any, _: any, command: string, args: string[]) => string[] +type CommandStore = { [key: string]: SpringCommand } + +@provideSingleton(CommandMap) +export class CommandMap { + private commands: CommandStore = {} + private pluginCommands: { [key: string]: CommandStore } = {} + + register(plugin: plugin.Plugin, command: string) { + let springCommand = new SpringCommand(plugin, command) + this.commands[command] = springCommand + if (!this.pluginCommands[plugin.description.name]) { this.pluginCommands[plugin.description.name] = {} } + this.pluginCommands[plugin.description.name][command] = springCommand + return springCommand + } + + unregister(plugin: plugin.Plugin, command: string) { + delete this.commands[command] + delete this.pluginCommands[plugin.description.name][command] + } + + dispatch(sender: any, command: string, args: string[]): boolean { + if (command === "help") { + sender.sendMessage('§e--------- §rHelp: Index §e---------------------------') + sender.sendMessage('Use /help [n] to get page n of help.') + for (const cmdName of Object.getOwnPropertyNames(this.commands)) { + sender.sendMessage(`§6/${cmdName}: §rA command provided by plugin §b${this.commands[cmdName].plugin.description.name}§r.`) + } + return + } + let exists = this.commands[command] + if (exists) { + return exists.executor(sender, '', command, Java.to(args)) + } else { + sender.sendMessage && sender.sendMessage(`Unknown command. Type "/help" for help.`) + return false + } + } +} + +export class SpringCommand { + public plugin: plugin.Plugin + public name: string + public executor: CommandExec + public tabCompleter: TabCompleter + + constructor(plugin: plugin.Plugin, command: string, description: string = '暂无描述!') { + this.plugin = plugin + this.name = command + } + + setExecutor = (executor: CommandExec) => this.executor = executor + setTabCompleter = (tabCompleter: TabCompleter) => this.tabCompleter = tabCompleter + toString = () => `SpringCommand(${this.name})` +} \ No newline at end of file diff --git a/packages/spring/src/server.ts b/packages/spring/src/server.ts index d8dee048..98ec5742 100644 --- a/packages/spring/src/server.ts +++ b/packages/spring/src/server.ts @@ -1,50 +1,55 @@ import { server } from '@ccms/api' -import { provideSingleton } from '@ccms/container'; -import { NativePluginManager } from '@ccms/api/dist/interfaces/server/native_plugin'; +import { provideSingleton, inject } from '@ccms/container' +import { NativePluginManager } from '@ccms/api/dist/interfaces/server/native_plugin' +import { CommandMap } from './internal/command' @provideSingleton(server.Server) export class SpringServer implements server.Server { + @inject(CommandMap) + private commandMap: CommandMap + constructor() { } getVersion(): string { return "SpringFramework" } getPlayer(name: string) { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } getOnlinePlayers(): any[] { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } getConsoleSender() { - return undefined; + return { + sendMessage: (message: string) => console.console(message) + } } getService(service: string) { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } dispatchCommand(sender: any, command: string): boolean { - console.console('§4Spring暂不支持dispatchCommand!') - return false; + let cmd_args = command.split(" ") + return this.commandMap.dispatch(sender, cmd_args.shift(), cmd_args || []) } dispatchConsoleCommand(command: string): boolean { - console.console('§4Spring暂不支持dispatchConsoleCommand!') - return false; + return this.dispatchCommand(this.getConsoleSender(), command) } getPluginsFolder(): string { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } getNativePluginManager(): NativePluginManager { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } getNettyPipeline() { return base.getInstance().getAutowireCapableBeanFactory() } getRootLogger() { - return global.logger + return Packages.org.slf4j.LoggerFactory.getLogger("root") || global.logger } sendJson(sender: any, json: string | object): void { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } tabComplete(sender: any, input: string, index?: number) { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } } diff --git a/packages/spring/src/task.ts b/packages/spring/src/task.ts index 9548a824..2289bdde 100644 --- a/packages/spring/src/task.ts +++ b/packages/spring/src/task.ts @@ -34,7 +34,7 @@ export class SpringTaskManager implements task.TaskManager { return func() } disable() { - Object.values(tasks).forEach((task) => task.cancel()) + Object.values(tasks).forEach((task) => task?.cancel()) executor.shutdown(); } } @@ -43,7 +43,7 @@ export class SpringTask extends task.Task { public id = taskId++ private running = new AtomicBoolean(true) - run() { + run(...args: any[]) { if (this.laterTime > 0) { try { Thread.sleep(this.laterTime) @@ -53,7 +53,7 @@ export class SpringTask extends task.Task { } while (this.running.get()) { try { - this.func() + this.func(...args) } catch (t) { console.error("Task exec error:", t) console.ex(t) @@ -72,13 +72,13 @@ export class SpringTask extends task.Task { cancel(): any { var wasRunning = this.running.getAndSet(false) if (wasRunning) { - tasks[this.id] = undefined + delete tasks[this.id] } } - submit(): task.Cancelable { + submit(...args: any[]): task.Cancelable { tasks[this.id] = this - executor.execute(this.run.bind(this)) + executor.execute(() => this.run(...args)) return { cancel: () => { return this.cancel() diff --git a/packages/websocket/src/tomcat/server.ts b/packages/websocket/src/tomcat/server.ts index 53121142..cede0af4 100644 --- a/packages/websocket/src/tomcat/server.ts +++ b/packages/websocket/src/tomcat/server.ts @@ -28,7 +28,7 @@ class TomcatWebSocketServer extends EventEmitter { let NashornWebSocketServerProxy = Java.extend(WebSocketServerProxy, { onOpen: (session: TomcatWebSocketSession) => { let tomcatClient = new TomcatClient(this, session) - this.allClients[tomcatClient.id] = tomcatClient + this.allClients[session.getId()] = tomcatClient this.emit(ServerEvent.connect, tomcatClient) }, onMessage: (session: TomcatWebSocketSession, message: string) => {