node-query/node_modules/mysql2/lib/packet_parser.js

84 lines
2.8 KiB
JavaScript

var Packet = require('./packets/packet');
// as this is very low level parser, EventEmitter is not used
// onPayload(sequenceId, payload) is called for each mysql packet
function PacketParser(onPacket)
{
// array of last payload chunks
// only used when corrent payload is not complete
this.buffer = [];
// total length of chunks on buffer
this.bufferLength = 0;
this.headerLen = 0;
this.headerBuff = Buffer(4);
this.state = 'head0';
// expected payload length
this.length = 0;
this.sequenceId = 0;
this.onPacket = onPacket;
}
PacketParser.prototype.execute = function(chunk, start, end) {
// node 0.11 has different ondata signature
if (!start && !end) {
start = 0;
end = chunk.length;
}
while (start < chunk.length) {
if (this.state == 'head0' && (end - start) > 3) {
this.length = chunk[start] + (chunk[start+1] << 8) + (chunk[start+2] << 16);
this.sequenceId = chunk[start+3];
var packetLength = this.length + 4;
if (end - start > packetLength) { // more than one packet in chunk
this.onPacket(new Packet(this.sequenceId, chunk, start + 4, start + packetLength));
start += packetLength;
} else if (end - start == packetLength) {
return this.onPacket(new Packet(this.sequenceId, chunk, start + 4, start + packetLength));
} else { // payload is incomplete
this.buffer = [chunk.slice(start + 4, end)];
this.bufferLength = end - start - 4;
this.state = 'payload';
return;
}
} else if (this.state == 'payload') {
var remainingPayload = this.length - this.bufferLength;
if (end - start >= remainingPayload) { // last chunk for payload
var payload = new Buffer(this.length);
var offset = 0;
for (var i=0; i < this.buffer.length; ++i) {
this.buffer[i].copy(payload, offset);
offset += this.buffer[i].length;
}
chunk.copy(payload, offset, start, start + remainingPayload);
this.onPacket(new Packet(this.sequenceId, payload, 0, this.length));
this.buffer = [];
this.bufferLength = 0;
start += remainingPayload;
this.state = 'head0';
} else {
this.buffer.push(chunk.slice(start, end));
this.bufferLength += end - start;
return;
}
} else { // length < 4 or state != header0
if (end - start + this.headerLen < 4) {
chunk.copy(this.headerBuff, this.headerLen, start, end);
this.headerLen += end - start;
this.state = 'head_';
return;
}
chunk.copy(this.headerBuff, this.headerLen, start, start + 4 - this.headerLen);
start += 4 - this.headerLen;
this.length = this.headerBuff[0] + (this.headerBuff[1] << 8) + (this.headerBuff[2] << 16);
this.headerLen = 0;
this.state = 'payload';
}
}
};
module.exports = PacketParser;