Add opportunistic parsing.

This commit is contained in:
roblabla 2014-04-11 01:48:06 +02:00
parent 457df31b0b
commit 0a4b365242
2 changed files with 68 additions and 11 deletions

View File

@ -30,9 +30,48 @@ function Client(isServer) {
this.encryptionEnabled = false;
this.cipher = null;
this.decipher = null;
this.packetsToParse = {};
this.on('newListener', function(event, listener) {
var direction = this.isServer ? 'toServer' : 'toClient';
if (protocol.packetStates[direction].hasOwnProperty(event)) {
if (typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1;
else this.packetsToParse[event] += 1;
}
});
this.on('removeListener', function(event, listener) {
var direction = this.isServer ? 'toServer' : 'toClient';
if (protocol.packetStates[direction].hasOwnProperty(event)) {
this.packetsToParse[event] -= 1;
}
});
}
util.inherits(Client, EventEmitter);
// Transform weird "packet" types into string representing their type. Should be mostly retro-compatible
Client.prototype.on = function(type, func) {
var direction = this.isServer ? 'toServer' : 'toClient';
if (Array.isArray(type)) {
arguments[0] = protocol.packetNames[type[0]][direction][type[1]];
} else if (typeof type === "number") {
arguments[0] = protocol.packetNames[this.state][direction][type];
}
EventEmitter.prototype.on.apply(this, arguments);
};
Client.prototype.onRaw = function(type, func) {
var arg = "raw.";
if (Array.isArray(type)) {
arg += protocol.packetNames[type[0]][direction][type[1]];
} else if (typeof type === "number") {
arg += protocol.packetNames[this.state][direction][type];
} else {
arg += type;
}
arguments[0] = arg;
EventEmitter.prototype.on.apply(this, arguments);
};
Client.prototype.setSocket = function(socket) {
var self = this;
self.socket = socket;
@ -42,7 +81,7 @@ Client.prototype.setSocket = function(socket) {
incomingBuffer = Buffer.concat([incomingBuffer, data]);
var parsed, packet;
while (true) {
parsed = parsePacket(incomingBuffer, self.state, self.isServer);
parsed = parsePacket(incomingBuffer, self.state, self.isServer, self.packetsToParse);
if (! parsed) break;
if (parsed.error) {
this.emit('error', parsed.error);
@ -53,11 +92,8 @@ Client.prototype.setSocket = function(socket) {
incomingBuffer = incomingBuffer.slice(parsed.size);
var packetName = protocol.packetNames[self.state][self.isServer ? 'toServer' : 'toClient'][packet.id];
if (packetName !== undefined) self.emit(packetName, packet);
self.emit([self.state, packet.id], packet);
self.emit(packet.id, packet);
self.emit('packet', packet);
self.emit(packetName, packet);
self.emit('raw.' + packetName, parsed.buffer);
}
});
@ -120,3 +156,11 @@ Client.prototype.write = function(packetId, params) {
this.socket.write(out);
return true;
};
Client.prototype.writeRaw = function(buffer, shouldEncrypt) {
if (shouldEncrypt === null) {
shouldEncrypt = true;
}
var out = (shouldEncrypt && this.encryptionEnabled) ? new Buffer(this.cipher.update(buffer), 'binary') : buffer;
this.socket.write(out);
};

View File

@ -1270,7 +1270,7 @@ function createPacketBuffer(packetId, state, params, isServer) {
return buffer;
}
function parsePacket(buffer, state, isServer) {
function parsePacket(buffer, state, isServer, packetsToParse) {
if (state == null) state == states.PLAY;
var cursor = 0;
var lengthField = readVarInt(buffer, 0);
@ -1279,19 +1279,30 @@ function parsePacket(buffer, state, isServer) {
cursor += lengthField.size;
if (length + lengthField.size > buffer.length) return null;
var buffer = buffer.slice(0, length + cursor); // fail early if too much is read.
var packetIdField = readVarInt(buffer, lengthField.size);
var packetIdField = readVarInt(buffer, cursor);
var packetId = packetIdField.value;
cursor += packetIdField.size;
var results = { id: packetId };
// Only parse the packet if there is a need for it, AKA if there is a listener attached to it
var name = packetNames[state][isServer ? "toServer" : "toClient"][packetId];
if (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0) {
return {
size: length + lengthField.size,
buffer: buffer,
results: results
};
}
var packetInfo = get(packetId, state, isServer);
if (packetInfo === null) {
return {
error: new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")"),
size: length + lengthField.size,
buffer: buffer,
results: results
}
};
} else {
debug("read packetId " + packetId + " (0x" + packetId.toString(16) + ")");
}
@ -1323,6 +1334,7 @@ function parsePacket(buffer, state, isServer) {
return {
size: length + lengthField.size,
results: results,
buffer: buffer
};
}
@ -1336,6 +1348,7 @@ module.exports = {
packetIds: packetIds,
packetNames: packetNames,
packetFields: packetFields,
packetStates: packetStates,
states: states,
get: get,
debug: debug,