|
1 |
| -var BIT_16 = Math.pow(2, 16); |
2 |
| -var BIT_24 = Math.pow(2, 24); |
3 |
| -var BUFFER_ALLOC_SIZE = Math.pow(2, 8); |
| 1 | +var BIT_16 = Math.pow(2, 16); |
| 2 | +var BIT_24 = Math.pow(2, 24); |
| 3 | +var BUFFER_ALLOC_SIZE = Math.pow(2, 8); |
| 4 | +var COMPRESSED_PACKET_HEADER_LENGTH = 7; |
4 | 5 | // The maximum precision JS Numbers can hold precisely
|
5 | 6 | // Don't panic: Good enough to represent byte values up to 8192 TB
|
6 | 7 | var IEEE_754_BINARY_64_PRECISION = Math.pow(2, 53);
|
| 8 | +var PACKET_HEADER_LENGTH = 4; |
7 | 9 | var MAX_PACKET_LENGTH = Math.pow(2, 24) - 1;
|
8 |
| -var Buffer = require('safe-buffer').Buffer; |
| 10 | + |
| 11 | +var Buffer = require('safe-buffer').Buffer; |
| 12 | +var BufferList = require('./BufferList'); |
| 13 | +var EventEmitter = require('events').EventEmitter; |
| 14 | +var Util = require('util'); |
| 15 | +var Zlib = require('zlib'); |
9 | 16 |
|
10 | 17 | module.exports = PacketWriter;
|
11 | 18 | function PacketWriter() {
|
12 |
| - this._buffer = null; |
13 |
| - this._offset = 0; |
| 19 | + this._buffer = null; |
| 20 | + this._deflateQueue = []; |
| 21 | + this._deflating = false; |
| 22 | + this._offset = 0; |
| 23 | + this._sync = false; |
14 | 24 | }
|
| 25 | +Util.inherits(PacketWriter, EventEmitter); |
15 | 26 |
|
16 |
| -PacketWriter.prototype.toBuffer = function toBuffer(parser) { |
| 27 | +PacketWriter.prototype.finalize = function finalize(parser) { |
17 | 28 | if (!this._buffer) {
|
18 | 29 | this._buffer = Buffer.alloc(0);
|
19 | 30 | this._offset = 0;
|
20 | 31 | }
|
21 | 32 |
|
| 33 | + var maxPacketLength = parser._compressed |
| 34 | + ? MAX_PACKET_LENGTH - PACKET_HEADER_LENGTH |
| 35 | + : MAX_PACKET_LENGTH; |
| 36 | + |
22 | 37 | var buffer = this._buffer;
|
23 | 38 | var length = this._offset;
|
24 |
| - var packets = Math.floor(length / MAX_PACKET_LENGTH) + 1; |
25 |
| - |
26 |
| - this._buffer = Buffer.allocUnsafe(length + packets * 4); |
27 |
| - this._offset = 0; |
| 39 | + var packets = Math.floor(length / maxPacketLength) + 1; |
28 | 40 |
|
29 | 41 | for (var packet = 0; packet < packets; packet++) {
|
30 | 42 | var isLast = (packet + 1 === packets);
|
31 | 43 | var packetLength = (isLast)
|
32 |
| - ? length % MAX_PACKET_LENGTH |
33 |
| - : MAX_PACKET_LENGTH; |
| 44 | + ? length % maxPacketLength |
| 45 | + : maxPacketLength; |
34 | 46 |
|
35 |
| - var packetNumber = parser.incrementPacketNumber(); |
| 47 | + var num = parser.incrementPacketNumber(); |
| 48 | + var start = packet * maxPacketLength; |
| 49 | + var end = start + packetLength; |
| 50 | + var buf = this._toPacket(num, buffer.slice(start, end)); |
| 51 | + |
| 52 | + if (parser._compressed) { |
| 53 | + num = parser.incrementCompressedPacketNumber(); |
| 54 | + |
| 55 | + if (this._sync) { |
| 56 | + buf = this._toCompressedPacket(num, buf); |
| 57 | + } else { |
| 58 | + this._toCompressedPacketAsync(num, buf); |
| 59 | + buf = null; |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + if (buf) { |
| 64 | + this.emit('data', buf); |
| 65 | + } |
| 66 | + } |
| 67 | +}; |
36 | 68 |
|
37 |
| - this.writeUnsignedNumber(3, packetLength); |
38 |
| - this.writeUnsignedNumber(1, packetNumber); |
| 69 | +PacketWriter.prototype.toBuffer = function toBuffer(parser) { |
| 70 | + var bufs = new BufferList(); |
39 | 71 |
|
40 |
| - var start = packet * MAX_PACKET_LENGTH; |
41 |
| - var end = start + packetLength; |
| 72 | + this.on('data', function (data) { |
| 73 | + bufs.push(data); |
| 74 | + }); |
| 75 | + |
| 76 | + this._sync = true; |
| 77 | + this.finalize(parser); |
42 | 78 |
|
43 |
| - this.writeBuffer(buffer.slice(start, end)); |
| 79 | + this._buffer = Buffer.allocUnsafe(bufs.size); |
| 80 | + this._offset = 0; |
| 81 | + |
| 82 | + while (bufs.size > 0) { |
| 83 | + this._offset += bufs.shift().copy(this._buffer, this._offset); |
44 | 84 | }
|
45 | 85 |
|
46 | 86 | return this._buffer;
|
@@ -209,3 +249,71 @@ PacketWriter.prototype._allocate = function _allocate(bytes) {
|
209 | 249 | this._buffer = Buffer.alloc(newSize);
|
210 | 250 | oldBuffer.copy(this._buffer);
|
211 | 251 | };
|
| 252 | + |
| 253 | +PacketWriter.prototype._deflateNextPacket = function _deflateNextPacket() { |
| 254 | + if (this._deflating) { |
| 255 | + return; |
| 256 | + } |
| 257 | + |
| 258 | + var item = this._deflateQueue.shift(); |
| 259 | + var buf = item[1]; |
| 260 | + var num = item[0]; |
| 261 | + var len = buf.length; |
| 262 | + var self = this; |
| 263 | + |
| 264 | + this._deflating = true; |
| 265 | + Zlib.deflate(buf, function (err, data) { |
| 266 | + if (err) { |
| 267 | + self.emit('error', err); |
| 268 | + return; |
| 269 | + } |
| 270 | + |
| 271 | + self._deflating = false; |
| 272 | + self.emit('data', self._toCompressedPacket(num, data, len)); |
| 273 | + self._deflateNextPacket(); |
| 274 | + }); |
| 275 | +}; |
| 276 | + |
| 277 | +PacketWriter.prototype._toCompressedPacket = function _toCompressedPacket(num, buf, len) { |
| 278 | + var origBuffer = this._buffer; |
| 279 | + var origOffset = this._offset; |
| 280 | + |
| 281 | + this._buffer = Buffer.allocUnsafe(buf.length + COMPRESSED_PACKET_HEADER_LENGTH); |
| 282 | + this._offset = 0; |
| 283 | + |
| 284 | + this.writeUnsignedNumber(3, buf.length); |
| 285 | + this.writeUnsignedNumber(1, num); |
| 286 | + this.writeUnsignedNumber(3, (len || 0)); |
| 287 | + this.writeBuffer(buf); |
| 288 | + |
| 289 | + var packet = this._buffer; |
| 290 | + |
| 291 | + this._buffer = origBuffer; |
| 292 | + this._offset = origOffset; |
| 293 | + |
| 294 | + return packet; |
| 295 | +}; |
| 296 | + |
| 297 | +PacketWriter.prototype._toCompressedPacketAsync = function _toCompressedPacketAsync(num, buf) { |
| 298 | + this._deflateQueue.push(buf); |
| 299 | + this._deflateNextPacket(); |
| 300 | +}; |
| 301 | + |
| 302 | +PacketWriter.prototype._toPacket = function _toPacket(num, buf) { |
| 303 | + var origBuffer = this._buffer; |
| 304 | + var origOffset = this._offset; |
| 305 | + |
| 306 | + this._buffer = Buffer.allocUnsafe(buf.length + PACKET_HEADER_LENGTH); |
| 307 | + this._offset = 0; |
| 308 | + |
| 309 | + this.writeUnsignedNumber(3, buf.length); |
| 310 | + this.writeUnsignedNumber(1, num); |
| 311 | + this.writeBuffer(buf); |
| 312 | + |
| 313 | + var packet = this._buffer; |
| 314 | + |
| 315 | + this._buffer = origBuffer; |
| 316 | + this._offset = origOffset; |
| 317 | + |
| 318 | + return packet; |
| 319 | +}; |
0 commit comments