const protobuf = require('protobufjs'); const ws = require('nodejs-websocket'); class ClientNet { constructor(url, protoPbFile, msgIdPbFile) { this.url = url; this.conn = null; this.protoPbFile = protoPbFile; this.msgIdPbFile = msgIdPbFile; this.protoPb = null; this.msgIdPb = null; this.cmMsgId = null; this.smMsgId = null; this.recvBuf = Buffer.alloc(0); } async init() { { const {err, root} = await protobuf.load(this.protoPbFile); this.protoPb = root; } { const {err, root} = await protobuf.load(this.msgIdPbFile); this.msgIdPb = root; this.cmMsgId = this.msgIdPb.lookup('CMMessageId_e'); this.smMsgId = this.msgIdPb.lookup('SMMessageId_e'); } } async connect() { this.conn = await ws.connect(this.url); this.on('binary', this.#onReceive.bind(this)); } async #onReceive(inStream) { inStream.on('readable', async () => { console.log('inStream.readable'); const newData = inStream.read(); if (newData) { this.recvBuf = Buffer.concat([this.recvBuf, newData]); await this.#onParsePacket(); } }); inStream.on('end', () => { console.log('inStream.end', this.recvBuf.length); }); inStream.on('close', () => { console.log('inStream.close'); }); } async #onParsePacket() { while (this.recvBuf.length > 12) { const msgSize = this.recvBuf.readUInt16LE(0); const msgId = this.recvBuf.readUInt16LE(2); const seqId = this.recvBuf.readUInt32LE(4); const magicCode = this.recvBuf.readUInt16LE(8); const ext = this.recvBuf.readUInt16LE(10); if (this.recvBuf.length >= 12 + msgSize) { this.recvBuf = this.recvBuf.slice(12 + msgSize); } } } on(eventName, cb) { this.conn.on(eventName, cb); } async sendMsg(name, msg) { const msgType = this.protoPb.lookupType(name); const msgId = this.cmMsgId.values['_' + name]; const msgPb = msgType.create(msg); const msgBuf = msgType.encode(msg).finish(); let buf = Buffer.alloc(12); buf.writeInt16LE(msgBuf.length, 0); buf.writeInt16LE(msgId, 2); buf.writeInt32LE(0, 4); buf.writeUInt8('K'.charCodeAt(0), 8); buf.writeUInt8('S'.charCodeAt(0), 9); buf.writeInt16LE(0, 10); this.conn.sendBinary(Buffer.concat([buf, msgBuf])); } } module.exports = ClientNet;