/** * app class */ import * as path from 'path'; import { I_someConfig, I_clientSocket, I_connectorConfig, I_encodeDecodeConfig, I_rpcConfig, ServerInfo, loggerLevel } from './util/interfaceDefine'; import * as appUtil from './util/appUtil'; import { EventEmitter } from 'events'; import { RpcSocketPool } from './components/rpcSocketPool'; import { FrontendServer } from './components/frontendServer'; import { BackendServer } from './components/backendServer'; import { Session } from './components/session'; import { Filter, I_before, I_after, I_globalBefore } from './components/filter'; declare global { interface Rpc { } } export default class Application extends EventEmitter { appName: string = 'hello world'; // App name hasStarted: boolean = false; // Whether has started main: string = ''; // Startup file base: string = path.dirname((require.main as any).filename); // Root path routeConfig: string[] = []; // route.ts masterConfig!: ServerInfo; // master.ts serversConfig: Record = {}; // servers.ts routeConfig2: string[][] = []; // route.ts (split) clientNum: number = 0; // Number of all socket connections clients = new Map(); // Sockets that have been binded settings = new Map(); // User set,get servers: Record = {}; // All user servers that are running serversIdMap = new Map(); // All user servers that are running (Dictionary format) serverInfo!: ServerInfo; // The configuration of this server isDaemon: boolean = false; // Whether to run in the background env: string = ''; // environment serverId: string = ''; // Server name id, the unique identifier of the server serverType: string = ''; // Server type frontend: boolean = false; // Is it a front-end server startMode: 'all' | 'alone' = 'all'; // Start Mode: all / alone startTime: number = 0; // Start time router: Record string> = {}; // Pre-selection when routing messages to the backend rpc: (serverId: string) => Rpc = null as any; // Rpc packaging rpcPool: RpcSocketPool = new RpcSocketPool(); // Rpc socket pool logger: (level: loggerLevel, err: Error | string) => void = function () { }; // Internal msg log output msgEncode: Required['msgEncode'] = null as any; msgDecode: Required['msgDecode'] = null as any; protoEncode: Required['protoEncode'] = null as any; protoDecode: Required['protoDecode'] = null as any; someconfig: I_someConfig = {} as any; // Partially open configuration noRpcMatrix: Record = {}; // The configuration of not establishing a socket connection between servers frontendServer: FrontendServer = null as any; backendServer: BackendServer = null as any; filter = new Filter(); constructor() { super(); appUtil.defaultConfiguration(this); } /** * Start up */ start() { if (this.hasStarted) { console.error('the app has already started'); return; } this.hasStarted = true; this.startTime = new Date().getTime(); appUtil.startServer(this); } setConfig(key: keyof I_someConfig, value: any): void { this.someconfig[key] = value; if (key === 'logger') { this.logger = value; } else if (key === 'rpc') { const noRpcMatrix = value.noRpcMatrix || {}; for (const svrT1 in noRpcMatrix) { const arr = noRpcMatrix[svrT1]; for (const svrT2 of arr) { this.noRpcMatrix[appUtil.getNoRpcKey(svrT1, svrT2)] = true; } } } } /** * Set key-value pairs */ set(key: string | number, value: any) { this.settings.set(key, value); return value; } /** * Get the value corresponding to the key */ get(key: string | number) { return this.settings.get(key); } /** * Delete a key-value pair */ delete(key: string | number) { this.settings.delete(key); } /** * Get the server array according to the server type */ getServersByType(serverType: string) { return this.servers[serverType] || []; } /** * Get a server configuration */ getServerById(serverId: string) { return this.serversIdMap.get(serverId); } /** * Routing configuration (deciding which backend to call) * @param serverType Back-end server type * @param routeFunc Configuration function */ route(serverType: string, routeFunc: (session: Session) => string) { this.router[serverType] = routeFunc; } /** * get session by uid */ getSession(uid: number) { const client = this.clients.get(uid); if (client) { return client.session; } else { return null; } } /** * get all clients */ getAllClients() { return this.clients; } /** * Send a message to the client * @param cmd cmd * @param msg message * @param uids uid array [1,2] */ sendMsgByUid(cmd: number, msg: any, uids: number[]) { if (msg === undefined) { msg = null; } const msgBuf = this.protoEncode(cmd, msg); let client: I_clientSocket | undefined; let i: number; for (i = 0; i < uids.length; i++) { client = this.clients.get(uids[i]); if (client) { client.send(msgBuf); } } } /** * Send messages to all clients * @param cmd cmd * @param msg message */ sendAll(cmd: number, msg: any) { if (msg === undefined) { msg = null; } const data = this.protoEncode(cmd, msg); for (const c of this.clients.values()) { c.send(data); } } /** * Send a message to the client * @param cmd cmd * @param msg message * @param uidsid uidsid array */ sendMsgByUidSid(cmd: number, msg: any, uidsid: Array<{ 'uid': number; 'sid': string }>) { if (msg === undefined) { msg = null; } this.backendServer.sendMsgByUidSid(cmd, msg, uidsid); } /** * Send a message to the client * @param cmd cmd * @param msg message * @param group { sid : uid[] } */ sendMsgByGroup(cmd: number, msg: any, group: Record) { if (msg === undefined) { msg = null; } this.backendServer.sendMsgByGroup(cmd, msg, group); } /** * Configure server execution function * @param type Server type: "all" or "gate|connector" like * @param cb Execution function */ configure(type: string, cb: Function) { if (type === 'all') { cb.call(this); return; } const ts = type.split('|'); for (let i = 0; i < ts.length; i++) { if (this.serverType === ts[i].trim()) { cb.call(this); break; } } } /** * Some front work before message processing * @param filter */ before(filter: { 'before': I_before }) { this.filter.before(filter); } /** * Some post work after message processing * @param filter */ after(filter: { 'after': I_after }) { this.filter.after(filter); } /** * Some processing of the message when it first reaches the gateway server * @param filter */ globalBefore(filter: { 'before': I_globalBefore }) { this.filter.globalBefore(filter); } }