From 079a4af73027146ed91c5c23fff9e94bde54766a Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Mon, 22 Jul 2024 19:25:22 +1000 Subject: [PATCH] support the `using` operator --- CHANGELOG.md | 1 + package-lock.json | 16 ++++++++-------- package.json | 2 +- readme.md | 16 ++++++++++++++++ src/receiver.ts | 2 ++ src/sender.ts | 2 ++ test/integration.test.ts | 30 ++++++++++++++++++++++++++++++ tsconfig.json | 1 + 8 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad19260..d6e4813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#54]: Added option to use raw dmx values - [#53]: Allow sending data to a specific IP instead of the whole LAN - [#57]: Export `Sender` props +- Support the `using` operator - Minor performance improvements - Minor improvements to type defintions and integration tests diff --git a/package-lock.json b/package-lock.json index 580fffb..958aa09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "jest": "^27.5.1", "ts-jest": "^27.1.4", "ts-node": "^10.7.0", - "typescript": "^4.6.2" + "typescript": "^5.5.3" }, "engines": { "node": ">=10.0.0" @@ -6296,16 +6296,16 @@ } }, "node_modules/typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "version": "5.5.3", + "resolved": "http://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -11353,9 +11353,9 @@ } }, "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "version": "5.5.3", + "resolved": "http://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true }, "unbox-primitive": { diff --git a/package.json b/package.json index 31aec80..c2ee26f 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "jest": "^27.5.1", "ts-jest": "^27.1.4", "ts-node": "^10.7.0", - "typescript": "^4.6.2" + "typescript": "^5.5.3" }, "eslintConfig": { "extends": "kyle", diff --git a/readme.md b/readme.md index 2fbf35b..3ba4946 100644 --- a/readme.md +++ b/readme.md @@ -130,6 +130,22 @@ main(); // wrapped in a main() function so that we can `await` the promise | `minRefreshRate` | `number` | Optional. How often the data should be re-sent (*in Hertz/Hz*), even if it hasn't changed. By default data will only be sent once (equivilant of setting `refreshRate: 0`). To re-send data 5 times per second (`5Hz`), set `refreshRate: 5`. This is equivilant to `200ms`. | `0` | `useUnicastDestination`| `string` | Optional. Setting this attribute to an IPv4 address will cause data to be sent directly to that device, instead of broadcasting to the whole LAN. | +## `using` operator + +This library supports [the `using` operator](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html). This means you don't have to explicitly call `.close()`. + +```ts +async function main() { + using sender = new Sender({ /* ... */ }); + + await sender.send({ /* ... */ }); + + // you don't need to call sender.close(), it's automatically + // closed when the block ends, thanks to the `using` keyword +} + +``` + # Contribute ```bash diff --git a/src/receiver.ts b/src/receiver.ts index d49dc7c..66db160 100644 --- a/src/receiver.ts +++ b/src/receiver.ts @@ -127,4 +127,6 @@ export class Receiver extends EventEmitter { this.socket.close(callback); return this; } + + [Symbol.dispose] = this.close; } diff --git a/src/sender.ts b/src/sender.ts index 8161451..0b2fb53 100644 --- a/src/sender.ts +++ b/src/sender.ts @@ -131,4 +131,6 @@ export class Sender { this.socket.close(); return this; } + + [Symbol.dispose] = this.close; } diff --git a/test/integration.test.ts b/test/integration.test.ts index 1f29ab1..3d78eba 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -2,6 +2,10 @@ import assert from 'assert'; import { networkInterfaces } from 'os'; import { Receiver, Sender, Packet } from '../src'; +// @ts-expect-error -- polyfill +Symbol.dispose ||= Symbol("dispose"); + +// TODO: switch to `node:timers/promises` once we drop support for node14 const sleep = (ms: number) => new Promise((cb) => setTimeout(cb, ms)); function collectErrors(Rx: Receiver, errors: Error[]) { @@ -42,6 +46,32 @@ describe('Receiver & Sender (integration test)', () => { } }); + it("supports Symbol.dipose", async () => { + using Tx1 = new Sender({ universe: 1, reuseAddr: true }); + using Tx2 = new Sender({ universe: 2, reuseAddr: true }); + using Rx = new Receiver({ + universes: [1, 3], // not listening to universe 2 + reuseAddr: true, + }); + + const received: Packet[] = []; + const errors: Error[] = []; + Rx.on('packet', (packet) => received.push(packet)); + collectErrors(Rx, errors); + + // stuff takes time + await sleep(3500); + await Tx1.send({ payload: { 1: 100 } }); + await Tx1.send({ payload: { 4: 25.1, 5: 0 } }); + await Tx2.send({ payload: { 512: 100 } }); + await sleep(3500); + + assert.strictEqual(errors.length, 0); + assert.strictEqual(received.length, 2); + assert.deepStrictEqual(received[0]!.payload, { 1: 100 }); + assert.deepStrictEqual(received[1]!.payload, { 4: 25.1 }); + }); + it('re-sends the packet data if minRefreshRate is supplied', async () => { const Tx = new Sender({ universe: 1, minRefreshRate: 1, reuseAddr: true }); const Rx = new Receiver({ universes: [1], reuseAddr: true }); diff --git a/tsconfig.json b/tsconfig.json index ea35d13..dc24d08 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "outDir": "./dist", "module": "commonjs", "target": "es2015", + "lib": ["esnext"], "strict": true, "esModuleInterop": true, "moduleResolution": "node",