index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.PacketLengthParser = void 0;
  4. const stream_1 = require("stream");
  5. /**
  6. * A transform stream that decodes packets with a delimiter and length of payload
  7. * specified within the data stream.
  8. * @extends Transform
  9. * @summary Decodes packets of the general form:
  10. * [delimiter][len][payload0] ... [payload0 + len]
  11. *
  12. * The length field can be up to 4 bytes and can be at any offset within the packet
  13. * [delimiter][header0][header1][len0][len1[payload0] ... [payload0 + len]
  14. *
  15. * The offset and number of bytes of the length field need to be provided in options
  16. * if not 1 byte immediately following the delimiter.
  17. */
  18. class PacketLengthParser extends stream_1.Transform {
  19. buffer;
  20. start;
  21. opts;
  22. constructor(options = {}) {
  23. super(options);
  24. const { delimiter = [0xaa], delimiterBytes = 1, packetOverhead = 2, lengthBytes = 1, lengthOffset = 1, maxLen = 0xff } = options;
  25. this.opts = {
  26. delimiter: [].concat(delimiter),
  27. delimiterBytes,
  28. packetOverhead,
  29. lengthBytes,
  30. lengthOffset,
  31. maxLen,
  32. };
  33. this.buffer = Buffer.alloc(0);
  34. this.start = false;
  35. }
  36. _transform(chunk, encoding, cb) {
  37. for (let ndx = 0; ndx < chunk.length; ndx++) {
  38. const byte = chunk[ndx];
  39. if (true === this.start) {
  40. this.buffer = Buffer.concat([this.buffer, Buffer.from([byte])]);
  41. if (this.buffer.length >= this.opts.lengthOffset + this.opts.lengthBytes) {
  42. const len = this.buffer.readUIntLE(this.opts.lengthOffset, this.opts.lengthBytes);
  43. if (this.buffer.length == len + this.opts.packetOverhead || len > this.opts.maxLen) {
  44. this.push(this.buffer);
  45. this.buffer = Buffer.alloc(0);
  46. this.start = false;
  47. }
  48. }
  49. }
  50. else {
  51. this.buffer = Buffer.concat([Buffer.from([byte]), this.buffer]);
  52. if (this.buffer.length === this.opts.delimiterBytes) {
  53. const delimiter = this.buffer.readUIntLE(0, this.opts.delimiterBytes);
  54. if (this.opts.delimiter.includes(delimiter)) {
  55. this.start = true;
  56. this.buffer = Buffer.from([...this.buffer].reverse());
  57. }
  58. else {
  59. this.buffer = Buffer.from(this.buffer.subarray(1, this.buffer.length));
  60. }
  61. }
  62. }
  63. }
  64. cb();
  65. }
  66. _flush(cb) {
  67. this.push(this.buffer);
  68. this.buffer = Buffer.alloc(0);
  69. cb();
  70. }
  71. }
  72. exports.PacketLengthParser = PacketLengthParser;