-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: inter byte timeout parser (#1779)
Emits data if there is a pause between packets for the specified amount of time.
- v13.0.0
- v12.0.0
- v11.0.1
- v11.0.0
- v10.5.0
- v10.4.0
- v10.3.0
- v10.2.2
- v10.2.1
- v10.2.0
- v10.1.0
- v10.0.2
- v10.0.1
- v10.0.0
- v9.2.8
- v9.2.7
- v9.2.5
- v9.2.4
- v9.2.3
- v9.2.1
- v9.2.0
- v9.1.0
- v9.0.9
- v9.0.8
- v9.0.7
- v9.0.6
- v9.0.5
- v9.0.4
- v9.0.3
- v9.0.2
- v9.0.1
- v9.0.0
- v8.0.8
- v8.0.7
- v8.0.6
- v8.0.5
- v8.0.4
- v8.0.3
- v8.0.2
- v8.0.1
- serialport@8.0.0
- serialport@7.1.5
- serialport@7.1.4
- @serialport/terminal@2.0.0
- @serialport/terminal@1.1.5
- @serialport/terminal@1.1.4
- @serialport/stream@3.0.0
- @serialport/stream@2.0.5
- @serialport/repl@2.0.0
- @serialport/repl@1.1.5
- @serialport/repl@1.1.4
- @serialport/parser-slip-encoder@3.0.0
- @serialport/parser-regex@3.0.0
- @serialport/parser-ready@3.0.0
- @serialport/parser-readline@3.0.0
- @serialport/parser-inter-byte-timeout@2.0.0
- @serialport/parser-inter-byte-timeout@1.1.0
- @serialport/parser-delimiter@3.0.0
- @serialport/parser-cctalk@3.0.0
- @serialport/parser-byte-length@3.0.0
- @serialport/list@2.0.0
- @serialport/list@1.1.5
- @serialport/list@1.1.4
- @serialport/bindings@10.0.1
- @serialport/bindings@10.0.0
- @serialport/bindings@9.2.8
- @serialport/bindings@9.2.7
- @serialport/bindings@9.2.5
- @serialport/bindings@9.2.4
- @serialport/bindings@9.2.1
- @serialport/bindings@9.2.0
- @serialport/bindings@9.1.0
- @serialport/bindings@9.0.8
- @serialport/bindings@9.0.7
- @serialport/bindings@9.0.4
- @serialport/bindings@9.0.4beta
- @serialport/bindings@9.0.3
- @serialport/bindings@9.0.2
- @serialport/bindings@9.0.1
- @serialport/bindings@9.0.0
- @serialport/bindings@8.0.9-beta2
- @serialport/bindings@8.0.9-beta
- @serialport/bindings@8.0.8
- @serialport/bindings@8.0.7
- @serialport/bindings@8.0.6
- @serialport/bindings@8.0.4
- @serialport/bindings@8.0.3
- @serialport/bindings@8.0.2
- @serialport/bindings@8.0.1
- @serialport/bindings@3.0.0
- @serialport/bindings@2.0.8
- @serialport/bindings@2.0.7
- @serialport/binding-mock@3.0.0
- @serialport/binding-mock@2.0.5
- @serialport/binding-abstract@3.0.0
- @serialport/binding-abstract@2.0.5
- force-build
1 parent
dd08fea
commit cbb8e41
Showing
7 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
id: api-parser-inter-byte-timeout | ||
title: InterByteTimeout Parser | ||
--- | ||
```typescript | ||
new InterByteTimeout(options) | ||
``` | ||
Emits data if there is a pause between packets for the specified amount of time. | ||
|
||
A transform stream that emits data as a buffer after not recieving any bytes for the specified amount of time. | ||
|
||
Arguments | ||
- `options.interval: number` the period of silence in milliseconds after which data is emited | ||
- `options.maxBufferSize: number` the maximum number of bytes after which data will be emited. Defaults to 65536. | ||
|
||
## Example | ||
```js | ||
const SerialPort = require('serialport') | ||
const InterByteTimeout = require('@serialport/parser-inter-byte-timeout') | ||
const port = new SerialPort('/dev/tty-usbserial1') | ||
const parser = port.pipe(new InterByteTimeout({interval: 30})) | ||
parser.on('data', console.log) // will emit data if there is a pause between packets of at least 30ms |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.test.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
See our api docs https://serialport.io/docs/api-parser-inter-byte-timeout |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const Transform = require('stream').Transform | ||
|
||
/** | ||
* Emits data if there is a pause between packets for the specified amount of time. | ||
* @extends Transform | ||
* @param {Object} options parser options object | ||
* @param {Number} options.interval the period of silence in milliseconds after which data is emited | ||
* @param {Number} options.maxBufferSize the maximum number of bytes after which data will be emited. Defaults to 65536. | ||
* @summary A transform stream that emits data as a buffer after not receiving any bytes for the specified amount of time. | ||
* @example | ||
const SerialPort = require('serialport') | ||
const InterByteTimeout = require('@serialport/parser-inter-byte-timeout') | ||
const port = new SerialPort('/dev/tty-usbserial1') | ||
const parser = port.pipe(new InterByteTimeout({interval: 30})) | ||
parser.on('data', console.log) // will emit data if there is a pause between packets greater than 30ms | ||
*/ | ||
|
||
class InterByteTimeoutParser extends Transform { | ||
constructor(options) { | ||
super() | ||
options = Object.assign({ maxBufferSize: 65536 }, options) | ||
if (!options.interval) { | ||
throw new TypeError('"interval" is required') | ||
} | ||
|
||
if (typeof options.interval !== 'number' || Number.isNaN(options.interval)) { | ||
throw new TypeError('"interval" is not a number') | ||
} | ||
|
||
if (options.interval < 1) { | ||
throw new TypeError('"interval" is not greater than 0') | ||
} | ||
|
||
if (typeof options.maxBufferSize !== 'number' || Number.isNaN(options.maxBufferSize)) { | ||
throw new TypeError('"maxBufferSize" is not a number') | ||
} | ||
|
||
if (options.maxBufferSize < 1) { | ||
throw new TypeError('"maxBufferSize" is not greater than 0') | ||
} | ||
|
||
this.maxBufferSize = options.maxBufferSize | ||
this.currentPacket = [] | ||
this.interval = options.interval | ||
this.intervalID = -1 | ||
} | ||
_transform(chunk, encoding, cb) { | ||
clearTimeout(this.intervalID) | ||
for (let offset = 0; offset < chunk.length; offset++) { | ||
this.currentPacket.push(chunk[offset]) | ||
if (this.currentPacket.length >= this.maxBufferSize) { | ||
this.emitPacket() | ||
} | ||
} | ||
this.intervalID = setTimeout(this.emitPacket.bind(this), this.interval) | ||
cb() | ||
} | ||
emitPacket() { | ||
clearTimeout(this.intervalID) | ||
if (this.currentPacket.length > 0) { | ||
this.push(Buffer.from(this.currentPacket)) | ||
} | ||
this.currentPacket = [] | ||
} | ||
_flush(cb) { | ||
this.emitPacket() | ||
cb() | ||
} | ||
} | ||
|
||
module.exports = InterByteTimeoutParser |
82 changes: 82 additions & 0 deletions
82
packages/parser-inter-byte-timeout/inter-byte-timeout.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* eslint-disable no-new */ | ||
|
||
const sinon = require('sinon') | ||
const InterByteTimeoutParser = require('./inter-byte-timeout') | ||
|
||
function wait(interval) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(resolve, interval) | ||
if (interval < 1) reject() | ||
}) | ||
} | ||
|
||
describe('InterByteTimeoutParser', () => { | ||
it('emits data events after a pause of 30ms', () => { | ||
const spy = sinon.spy() | ||
const parser = new InterByteTimeoutParser({ interval: 30 }) | ||
parser.on('data', spy) | ||
parser.write(Buffer.from('I love robots Each')) | ||
parser.write(Buffer.from('and Every One')) | ||
wait(30).then(() => { | ||
parser.write(Buffer.from('even you!')) | ||
parser.write(Buffer.from('The angry red robot')) | ||
wait(30).then(() => { | ||
assert(spy.calledTwice, 'expecting 2 data events') | ||
}) | ||
}) | ||
}) | ||
|
||
it('throws when interval is not a number or negative', () => { | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ interval: -20 }) | ||
}) | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ interval: NaN }) | ||
}) | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ interval: 'hello' }) | ||
}) | ||
assert.throws(() => { | ||
new InterByteTimeoutParser() | ||
}) | ||
}) | ||
|
||
it('throws when maxBufferSize is not a number or negative', () => { | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ maxBufferSize: -20, interval: 15 }) | ||
}) | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ maxBufferSize: NaN, interval: 15 }) | ||
}) | ||
assert.throws(() => { | ||
new InterByteTimeoutParser({ maxBufferSize: 'hello', interval: 15 }) | ||
}) | ||
}) | ||
|
||
it('emits data events when buffer is full', () => { | ||
const spy = sinon.spy() | ||
const parser = new InterByteTimeoutParser({ maxBufferSize: 2, interval: 15 }) | ||
parser.on('data', spy) | ||
parser.write(Buffer.from([1, 2, 3, 4, 5, 6])) | ||
wait(15).then(() => { | ||
assert(spy.calledThrice, 'expecting 3 data events') | ||
}) | ||
}) | ||
|
||
it('emits all buffered data when stream ends', () => { | ||
const spy = sinon.spy() | ||
const parser = new InterByteTimeoutParser({ interval: 15 }) | ||
parser.on('data', spy) | ||
parser.write('Oh wow.') | ||
parser.end() | ||
assert(spy.calledOnce, 'expecting 1 data event') | ||
}) | ||
it('emits all buffered data when stream ends', () => { | ||
const spy = sinon.spy() | ||
const parser = new InterByteTimeoutParser({ interval: 15 }) | ||
parser.on('data', spy) | ||
parser.write('') | ||
parser.end() | ||
assert(spy.notCalled, 'expecting no data events') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "@serialport/parser-inter-byte-timeout", | ||
"version": "1.0.0", | ||
"main": "inter-byte-timeout.js", | ||
"engines": { | ||
"node": ">=6.0.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/node-serialport/node-serialport.git" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters