Skip to content

Commit a875f5b

Browse files
bbeckreconbot
authored andcommitted
feat: add abilitiy for multiple delimitiers and multibyte delimiters to packet length parser
1 parent 929ebf8 commit a875f5b

File tree

4 files changed

+70
-20
lines changed

4 files changed

+70
-20
lines changed

packages/parser-packet-length/lib/index.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,45 @@ describe('DelimiterParser', () => {
9090
assert.deepEqual(spy.getCall(1).args[0], Buffer.concat([Buffer.from([0xaa, 0x02, 0x13, 0x00]), Buffer.from('Each and Every One\n')]))
9191
assert(spy.calledTwice)
9292
})
93+
94+
it('works with multiple delimiters', () => {
95+
const spy = sinon.spy()
96+
const parser = new PacketLengthParser({ delimiter: [0xaa, 0xbb], lengthOffset: 2, packetOverhead: 4, lengthBytes: 2 })
97+
parser.on('data', spy)
98+
parser.write(Buffer.from('\xbb\x01\x0d'))
99+
parser.write(Buffer.from('\x00I love hobits\xaa\x02\x13\x00Each '))
100+
parser.write(Buffer.from('and Every One\n'))
101+
102+
assert.deepEqual(spy.getCall(0).args[0], Buffer.concat([Buffer.from([0xbb, 0x01, 0x0d, 0x00]), Buffer.from('I love hobits')]))
103+
assert.deepEqual(spy.getCall(1).args[0], Buffer.concat([Buffer.from([0xaa, 0x02, 0x13, 0x00]), Buffer.from('Each and Every One\n')]))
104+
assert(spy.calledTwice)
105+
})
106+
107+
it('works with multibyte delimiters', () => {
108+
const spy = sinon.spy()
109+
const parser = new PacketLengthParser({ delimiter: [0xababba], delimiterBytes: 3, lengthOffset: 3, packetOverhead: 4, lengthBytes: 1 })
110+
parser.on('data', spy)
111+
parser.write(Buffer.from([0xab, 0xab, 0xba, 0x0d]))
112+
parser.write(Buffer.from('I love hobits'))
113+
parser.write(Buffer.from([0xab, 0xab, 0xba, 0x13]))
114+
parser.write(Buffer.from('Each and Every One\n'))
115+
116+
assert.deepEqual(spy.getCall(0).args[0], Buffer.concat([Buffer.from([0xab, 0xab, 0xba, 0x0d]), Buffer.from('I love hobits')]))
117+
assert.deepEqual(spy.getCall(1).args[0], Buffer.concat([Buffer.from([0xab, 0xab, 0xba, 0x13]), Buffer.from('Each and Every One\n')]))
118+
assert(spy.calledTwice)
119+
})
120+
121+
it('works with multiple multibyte delimiters', () => {
122+
const spy = sinon.spy()
123+
const parser = new PacketLengthParser({ delimiter: [0xababba, 0xbaddad], delimiterBytes: 3, lengthOffset: 3, packetOverhead: 4, lengthBytes: 1 })
124+
parser.on('data', spy)
125+
parser.write(Buffer.from([0xab, 0xab, 0xba, 0x0d]))
126+
parser.write(Buffer.from('I love hobits'))
127+
parser.write(Buffer.from([0xba, 0xdd, 0xad, 0x13]))
128+
parser.write(Buffer.from('Each and Every One\n'))
129+
130+
assert.deepEqual(spy.getCall(0).args[0], Buffer.concat([Buffer.from([0xab, 0xab, 0xba, 0x0d]), Buffer.from('I love hobits')]))
131+
assert.deepEqual(spy.getCall(1).args[0], Buffer.concat([Buffer.from([0xba, 0xdd, 0xad, 0x13]), Buffer.from('Each and Every One\n')]))
132+
assert(spy.calledTwice)
133+
})
93134
})

packages/parser-packet-length/lib/index.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Transform, TransformCallback, TransformOptions } from 'stream'
22

33
export interface PacketLengthOptions extends TransformOptions {
4-
/** delimiter to use defaults to 0xaa */
5-
delimiter?: number
4+
/** delimiter(s) to use defaults to 0xaa */
5+
delimiter?: number | number[]
6+
/** delimiter length in bytes defaults to 1 */
7+
delimiterBytes?: number
68
/** overhead of packet (including length, delimiter and any checksum / packet footer) defaults to 2 */
79
packetOverhead?: number
810
/** number of bytes containing length defaults to 1 */
@@ -29,14 +31,15 @@ export interface PacketLengthOptions extends TransformOptions {
2931
export class PacketLengthParser extends Transform {
3032
buffer: Buffer
3133
start: boolean
32-
opts: { delimiter: number, packetOverhead: number, lengthBytes: number, lengthOffset: number, maxLen: number }
34+
opts: { delimiter: number[], delimiterBytes: number, packetOverhead: number, lengthBytes: number, lengthOffset: number, maxLen: number }
3335
constructor(options: PacketLengthOptions = {}) {
3436
super(options)
3537

36-
const { delimiter = 0xaa, packetOverhead = 2, lengthBytes = 1, lengthOffset = 1, maxLen = 0xff } = options
38+
const { delimiter = [0xaa], delimiterBytes = 1, packetOverhead = 2, lengthBytes = 1, lengthOffset = 1, maxLen = 0xff } = options
3739

3840
this.opts = {
39-
delimiter,
41+
delimiter: ([] as number[]).concat(delimiter),
42+
delimiterBytes,
4043
packetOverhead,
4144
lengthBytes,
4245
lengthOffset,
@@ -51,13 +54,8 @@ export class PacketLengthParser extends Transform {
5154
for (let ndx = 0; ndx < chunk.length; ndx++) {
5255
const byte = chunk[ndx]
5356

54-
if (byte === this.opts.delimiter) {
55-
this.start = true
56-
}
57-
5857
if (true === this.start) {
5958
this.buffer = Buffer.concat([this.buffer, Buffer.from([byte])])
60-
6159
if (this.buffer.length >= this.opts.lengthOffset + this.opts.lengthBytes) {
6260
const len = this.buffer.readUIntLE(this.opts.lengthOffset, this.opts.lengthBytes)
6361

@@ -67,6 +65,17 @@ export class PacketLengthParser extends Transform {
6765
this.start = false
6866
}
6967
}
68+
} else {
69+
this.buffer = Buffer.concat([Buffer.from([byte]), this.buffer])
70+
if (this.buffer.length === this.opts.delimiterBytes) {
71+
const delimiter = this.buffer.readUIntLE(0, this.opts.delimiterBytes)
72+
if (this.opts.delimiter.includes(delimiter)) {
73+
this.start = true
74+
this.buffer = Buffer.from([...this.buffer].reverse())
75+
} else {
76+
this.buffer = Buffer.from(this.buffer.subarray(1, this.buffer.length))
77+
}
78+
}
7079
}
7180
}
7281

packages/parser-start-end/lib/index.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('StartEndParser', () => {
1717
parser.write(Buffer.from(`${STX}I love robots${ETX}${STX}Each `))
1818
parser.write(Buffer.from(`and Every One${ETX}`))
1919
parser.write(Buffer.from(STX))
20-
parser.write(Buffer.from(`even you!`))
20+
parser.write(Buffer.from('even you!'))
2121

2222
assert.deepEqual(spy.getCall(0).args[0], Buffer.from('I love robots'))
2323
assert.deepEqual(spy.getCall(1).args[0], Buffer.from('Each and Every One'))
@@ -35,7 +35,7 @@ describe('StartEndParser', () => {
3535
parser.write(Buffer.from(`${STX}I love robots${ETX}${STX}Each `))
3636
parser.write(Buffer.from(`and Every One${ETX}`))
3737
parser.write(Buffer.from(STX))
38-
parser.write(Buffer.from(`even you!`))
38+
parser.write(Buffer.from('even you!'))
3939

4040
assert.deepEqual(spy.getCall(0).args[0], Buffer.from(`${STX}I love robots`))
4141
assert.deepEqual(spy.getCall(1).args[0], Buffer.from(`${STX}Each and Every One`))
@@ -53,7 +53,7 @@ describe('StartEndParser', () => {
5353
parser.write(Buffer.from(`${STX}I love robots${ETX}${STX}Each `))
5454
parser.write(Buffer.from(`and Every One${ETX}`))
5555
parser.write(Buffer.from(STX))
56-
parser.write(Buffer.from(`even you!`))
56+
parser.write(Buffer.from('even you!'))
5757

5858
assert.deepEqual(spy.getCall(0).args[0], Buffer.from(`I love robots${ETX}`))
5959
assert.deepEqual(spy.getCall(1).args[0], Buffer.from(`Each and Every One${ETX}`))
@@ -72,7 +72,7 @@ describe('StartEndParser', () => {
7272
parser.write(Buffer.from(`${STX}I love robots${ETX}${STX}Each `))
7373
parser.write(Buffer.from(`and Every One${ETX}`))
7474
parser.write(Buffer.from(STX))
75-
parser.write(Buffer.from(`even you!`))
75+
parser.write(Buffer.from('even you!'))
7676

7777
assert.deepEqual(spy.getCall(0).args[0], Buffer.from(`${STX}I love robots${ETX}`))
7878
assert.deepEqual(spy.getCall(1).args[0], Buffer.from(`${STX}Each and Every One${ETX}`))
@@ -108,7 +108,7 @@ describe('StartEndParser', () => {
108108
})
109109
})
110110

111-
it(`throws when called with a 0 length startDelimiter`, () => {
111+
it('throws when called with a 0 length startDelimiter', () => {
112112
assert.throws(() => {
113113
new StartEndParser({
114114
startDelimiter: Buffer.alloc(0),
@@ -128,7 +128,7 @@ describe('StartEndParser', () => {
128128
})
129129
})
130130

131-
it(`throws when called with a 0 length endDelimiter`, () => {
131+
it('throws when called with a 0 length endDelimiter', () => {
132132
assert.throws(() => {
133133
new StartEndParser({
134134
endDelimiter: Buffer.alloc(0),
@@ -148,15 +148,15 @@ describe('StartEndParser', () => {
148148
})
149149
})
150150

151-
it(`allows setting of the startDelimiter and endDelimiter with strings`, () => {
151+
it('allows setting of the startDelimiter and endDelimiter with strings', () => {
152152
new StartEndParser({ startDelimiter: 'string', endDelimiter: 'string' })
153153
})
154154

155-
it(`allows setting of the startDelimiter and endDelimiter with buffers`, () => {
155+
it('allows setting of the startDelimiter and endDelimiter with buffers', () => {
156156
new StartEndParser({ startDelimiter: Buffer.from([1]), endDelimiter: Buffer.from([1]) })
157157
})
158158

159-
it(`allows setting of the startDelimiter and endDelimiter with arrays of bytes`, () => {
159+
it('allows setting of the startDelimiter and endDelimiter with arrays of bytes', () => {
160160
new StartEndParser({ startDelimiter: [1], endDelimiter: [1] })
161161
})
162162

packages/parser-start-end/lib/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class StartEndParser extends Transform {
6262
if (startIndex >= 0 && endIndex >= 0) {
6363
const block = data.slice(
6464
startIndex + (this.includeStartDelimiter ? 0 : this.startDelimiter.length),
65-
endIndex + (this.includeEndDelimiter ? this.endDelimiter.length : 0)
65+
endIndex + (this.includeEndDelimiter ? this.endDelimiter.length : 0),
6666
)
6767

6868
this.push(block)

0 commit comments

Comments
 (0)