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;