227 lines
5.7 KiB
JavaScript
227 lines
5.7 KiB
JavaScript
const readline = require('readline');
|
|
const protobuf = require('protobufjs');
|
|
const ws = require('nodejs-websocket');
|
|
|
|
function prettyJsonEncode(obj) {
|
|
return JSON.stringify(obj, "", " ");
|
|
}
|
|
|
|
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);
|
|
this.uniqId = 1000;
|
|
this.msgHandlerMap = new Map();
|
|
this.rl = readline.createInterface({
|
|
input: process.stdin,
|
|
//output: process.stdout
|
|
});
|
|
this.rl.on("line", (line)=> {
|
|
this.parseCmdLine(line);
|
|
});
|
|
}
|
|
|
|
selfRegisterMsgHandle(msgName) {
|
|
this.registerMsgHandle(
|
|
msgName,
|
|
(msg) => {
|
|
if (this[msgName]) {
|
|
this[msgName](msg);
|
|
}
|
|
});
|
|
}
|
|
|
|
async init() {
|
|
{
|
|
this.protoPb = await (new protobuf.Root()).load
|
|
(this.protoPbFile,
|
|
{
|
|
'keepCase': true
|
|
}
|
|
);
|
|
}
|
|
{
|
|
this.msgIdPb = await (new protobuf.Root()).load
|
|
(this.msgIdPbFile,
|
|
{
|
|
'keepCase': true
|
|
}
|
|
);
|
|
this.cmMsgId = this.msgIdPb.lookup('CMMessageId_e');
|
|
this.smMsgId = this.msgIdPb.lookup('SMMessageId_e');
|
|
}
|
|
{
|
|
for (let id in this.smMsgId.valuesById) {
|
|
const msgName = this.smMsgId.valuesById[id];
|
|
this.selfRegisterMsgHandle(msgName.slice(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
async connect() {
|
|
this.conn = await ws.connect(this.url);
|
|
this.on('binary', this.onReceive.bind(this));
|
|
}
|
|
|
|
on(eventName, ...args) {
|
|
this.conn.on(eventName, ...args);
|
|
}
|
|
|
|
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() {
|
|
let offset = 0;
|
|
while (this.recvBuf.length > offset + 12) {
|
|
const msgSize = this.recvBuf.readUInt16LE(offset + 0);
|
|
const msgId = this.recvBuf.readUInt16LE(offset + 2);
|
|
const seqId = this.recvBuf.readUInt32LE(offset + 4);
|
|
const magicCode = this.recvBuf.readUInt16LE(offset + 8);
|
|
if (this.recvBuf.length >= offset + 12 + msgSize) {
|
|
await this.processMsg(msgId,
|
|
this.recvBuf.slice
|
|
(
|
|
offset + 12,
|
|
offset + 12 + msgSize)
|
|
);
|
|
offset += 12 + msgSize;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
this.recvBuf = this.recvBuf.slice(offset);
|
|
}
|
|
|
|
async processMsg(msgId, buff) {
|
|
const handlers = this.msgHandlerMap.get(msgId);
|
|
if (handlers) {
|
|
let msg = null;
|
|
handlers.forEach((value, key) => {
|
|
if (!msg) {
|
|
msg = value.msgType.decode(buff);
|
|
}
|
|
console.log(value.msgType['name'], prettyJsonEncode(msg));
|
|
value.cb(msg);
|
|
});
|
|
}
|
|
}
|
|
|
|
registerMsgHandle(msgName, cb) {
|
|
try {
|
|
const msgType = this.protoPb.lookupType(msgName);
|
|
const msgId = this.smMsgId.values['_' + msgName];
|
|
if (!msgId) {
|
|
return null;
|
|
}
|
|
const handle = {
|
|
msgId: msgId,
|
|
msgName: msgName,
|
|
msgType: msgType,
|
|
cb: cb,
|
|
uniqId: ++this.uniqId}
|
|
;
|
|
if (!this.msgHandlerMap.has(msgId)) {
|
|
this.msgHandlerMap.set(msgId, new Map([
|
|
[handle.uniqId, handle]
|
|
]));
|
|
} else {
|
|
this.msgHandlerMap.get(msgId).set(handle.uniqId, handle);
|
|
}
|
|
return handle;
|
|
} catch (err) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
unRegisterMsgHandle(handle) {
|
|
if (this.msgHandlerMap.has(handle.msgId)) {
|
|
if (this.msgHandlerMap[handle.msgId].has(handle.uniqId)) {
|
|
this.msgHandlerMap[handle.msgId].delete(handle.uniqId);
|
|
}
|
|
}
|
|
}
|
|
|
|
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.writeUInt16LE(msgBuf.length, 0);
|
|
buf.writeUInt16LE(msgId, 2);
|
|
buf.writeUInt32LE(0, 4);
|
|
buf.writeUInt8('K'.charCodeAt(0), 8);
|
|
buf.writeUInt8('S'.charCodeAt(0), 9);
|
|
buf.writeUInt16LE(0, 10);
|
|
this.conn.sendBinary(Buffer.concat([buf, msgBuf]));
|
|
console.log(name, msg, (Buffer.concat([buf, msgBuf])).length);
|
|
}
|
|
|
|
SMLogin(msg) {
|
|
if (msg.errcode) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
SMPing(msg) {
|
|
|
|
}
|
|
|
|
parseCmdLine(line) {
|
|
const params = line.split(' ');
|
|
if (params.length <= 0) {
|
|
console.log('unknown command');
|
|
return;
|
|
}
|
|
const msgName = params[0];
|
|
const msgFields = params.slice(1);
|
|
const msgType = this.protoPb.lookupType(msgName);
|
|
if (!msgType) {
|
|
console.log('unknown command');
|
|
return;
|
|
}
|
|
const msgBody = line.slice(line.indexOf(msgName) + msgName.length);
|
|
const msg = eval('({' + msgBody + '})');
|
|
/*const msg = {};
|
|
for (let i = 0; i < msgType.fieldsArray.length; ++i) {
|
|
if (i < msgFields.length) {
|
|
const name = msgType.fieldsArray[i].name;
|
|
const type = msgType.fieldsArray[i].type;
|
|
if (['int32', 'int', 'float', 'double'].indexOf(type) >= 0) {
|
|
msg[name] = Number(msgFields[i]);
|
|
} else {
|
|
msg[name] = msgFields[i];
|
|
}
|
|
}
|
|
}
|
|
console.log(msg);*/
|
|
this.sendMsg(msgName, msg);
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = ClientNet;
|