import {ConnectionHandler} from "../ConnectionHandler"; import {CommandResult} from "../connection/ServerConnectionDeclaration"; import {AbstractCommandHandler} from "../connection/AbstractCommandHandler"; import {AbstractServerConnection, ServerCommand} from "../connection/ConnectionBase"; import { tra } from "tc-shared/i18n/localize"; export interface PluginCommandInvoker { clientId: number; clientUniqueId: string; clientName: string; } export abstract class PluginCmdHandler { protected readonly channel: string; protected currentServerConnection: AbstractServerConnection; protected constructor(channel: string) { this.channel = channel; } handleHandlerUnregistered() {} handleHandlerRegistered() {} getChannel() { return this.channel; } abstract handlePluginCommand(data: string, invoker: PluginCommandInvoker); protected sendPluginCommand(data: string, mode: "server" | "view" | "channel" | "private", clientId?: number) : Promise { if(!this.currentServerConnection) throw "plugin command handler not registered"; return this.currentServerConnection.send_command("plugincmd", { data: data, name: this.channel, targetmode: mode === "server" ? 1 : mode === "view" ? 3 : mode === "channel" ? 0 : 2, target: clientId }); } } class PluginCmdRegistryCommandHandler extends AbstractCommandHandler { private readonly callback: (channel: string, data: string, invoker: PluginCommandInvoker) => void; constructor(connection, callback) { super(connection); this.callback = callback; } handle_command(command: ServerCommand): boolean { if(command.command !== "notifyplugincmd") return false; const channel = command.arguments[0]["name"]; const payload = command.arguments[0]["data"]; const invoker = { clientId: parseInt(command.arguments[0]["invokerid"]), clientUniqueId: command.arguments[0]["invokeruid"], clientName: command.arguments[0]["invokername"] } as PluginCommandInvoker; this.callback(channel, payload, invoker); return false; } } export class PluginCmdRegistry { readonly connection: ConnectionHandler; private readonly handler: PluginCmdRegistryCommandHandler; private handlerMap: {[key: string]: PluginCmdHandler} = {}; constructor(connection: ConnectionHandler) { this.connection = connection; this.handler = new PluginCmdRegistryCommandHandler(connection.serverConnection, this.handlePluginCommand.bind(this)); this.connection.serverConnection.command_handler_boss().register_handler(this.handler); } destroy() { this.connection.serverConnection.command_handler_boss().unregister_handler(this.handler); Object.keys(this.handlerMap).map(e => this.handlerMap[e]).forEach(handler => { handler["currentServerConnection"] = undefined; handler.handleHandlerUnregistered(); }); this.handlerMap = {}; } registerHandler(handler: PluginCmdHandler) { if(this.handlerMap[handler.getChannel()] !== undefined) { throw tra("A handler for channel {} already exists", handler.getChannel()); } this.handlerMap[handler.getChannel()] = handler; handler["currentServerConnection"] = this.connection.serverConnection; handler.handleHandlerRegistered(); } unregisterHandler(handler: PluginCmdHandler) { if(this.handlerMap[handler.getChannel()] !== handler) { return; } handler["currentServerConnection"] = undefined; handler.handleHandlerUnregistered(); delete this.handlerMap[handler.getChannel()]; } private handlePluginCommand(channel: string, payload: string, invoker: PluginCommandInvoker) { const handler = this.handlerMap[channel] as PluginCmdHandler; handler?.handlePluginCommand(payload, invoker); } getPluginHandler(channel: string) : T | undefined { return this.handlerMap[channel] as T; } }