import Application from '../application'; import { encodeRemoteData } from './msgCoder'; import * as path from 'path'; import * as fs from 'fs'; import define = require('../util/define'); import { I_encodeDecodeConfig } from '../util/interfaceDefine'; import { Session, initSessionApp } from './session'; import * as protocol from '../connector/protocol'; export class BackendServer { private readonly app: Application; private msgHandler: Record = {}; constructor(app: Application) { this.app = app; initSessionApp(this.app); protocol.init(this.app); const defaultEncodeDecode: Required = protocol.default_encodeDecode; const encodeDecodeConfig = this.app.someconfig.encodeDecode || {}; this.app.protoEncode = encodeDecodeConfig.protoEncode || defaultEncodeDecode.protoEncode; this.app.msgEncode = encodeDecodeConfig.msgEncode || defaultEncodeDecode.msgEncode; this.app.protoDecode = encodeDecodeConfig.protoDecode || defaultEncodeDecode.protoDecode; this.app.msgDecode = encodeDecodeConfig.msgDecode || defaultEncodeDecode.msgDecode; this.loadHandler(); } /** * Back-end server load routing processing */ private loadHandler() { const dirName = path.join(this.app.base, define.some_config.File_Dir.Servers, this.app.serverType, 'handler'); const exists = fs.existsSync(dirName); if (exists) { const self = this; fs.readdirSync(dirName).forEach(function (filename) { if (!filename.endsWith('.js')) { return; } const name = path.basename(filename, '.js'); const handler = require(path.join(dirName, filename)); if (handler.default && typeof handler.default === 'function') { // eslint-disable-next-line new-cap self.msgHandler[name] = new handler.default(self.app); } }); } } /** * The back-end server receives the client message forwarded by the front-end server */ handleMsg(id: string, msg: Buffer) { const sessionLen = msg.readUInt16BE(1); const sessionBuf = msg.slice(3, 3 + sessionLen); const session = new Session(); session.setAll(JSON.parse(sessionBuf.toString())); const cmd = msg.readUInt16BE(3 + sessionLen); const cmdArr = this.app.routeConfig2[cmd]; const data = this.app.msgDecode(cmd, msg.slice(5 + sessionLen)); this.app.filter.beforeFilter(cmd, data, session, (hasError) => { if (hasError) { return; } this.msgHandler[cmdArr[1]][cmdArr[2]](data, session, this.callback(id, cmd, session)); }); } private callback(id: string, cmd: number, session: Session) { const self = this; return function (msg: any) { if (msg === undefined) { msg = null; } const msgBuf = self.app.protoEncode(cmd, msg); const buf = encodeRemoteData([session.uid], msgBuf); self.app.rpcPool.sendMsg(id, buf); self.app.filter.afterFilter(cmd, msg, session); }; } /** * Synchronize back-end session to front-end */ sendSession(sid: string, sessionBuf: Buffer) { const buf = Buffer.allocUnsafe(5 + sessionBuf.length); buf.writeUInt32BE(1 + sessionBuf.length, 0); buf.writeUInt8(define.Rpc_Msg.applySession, 4); sessionBuf.copy(buf, 5); this.app.rpcPool.sendMsg(sid, buf); } /** * The back-end server sends a message to the client */ sendMsgByUidSid(cmd: number, msg: any, uidsid: Array<{ 'uid': number; 'sid': string }>) { const groups: Record = {}; let group: number[]; let one: { 'uid': number; 'sid': string }; for (one of uidsid) { if (!one.sid) { continue; } group = groups[one.sid]; if (!group) { group = []; groups[one.sid] = group; } group.push(one.uid); } const app = this.app; const msgBuf: Buffer = app.protoEncode(cmd, msg); let sid: string; let buf: Buffer; for (sid in groups) { buf = encodeRemoteData(groups[sid], msgBuf); app.rpcPool.sendMsg(sid, buf); } } /** * The back-end server sends a message to the client */ sendMsgByGroup(cmd: number, msg: any, group: Record) { const app = this.app; const msgBuf: Buffer = app.protoEncode(cmd, msg); let sid: string; let buf: Buffer; for (sid in group) { if (group[sid].length === 0) { continue; } buf = encodeRemoteData(group[sid], msgBuf); app.rpcPool.sendMsg(sid, buf); } } }