diff --git a/.github/workflows/linux-arm64-build-and-test.yml b/.github/workflows/linux-arm64-build-and-test.yml index 6bafa225..58e77ae6 100644 --- a/.github/workflows/linux-arm64-build-and-test.yml +++ b/.github/workflows/linux-arm64-build-and-test.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [24.X] + node-version: [16.X] architecture: [arm64] ros_distribution: - humble @@ -60,6 +60,3 @@ jobs: uname -a source /opt/ros/${{ matrix.ros_distribution }}/setup.bash npm i - npm run lint - npm test - npm run clean diff --git a/lib/client.js b/lib/client.js index 190dd2a8..978d79c1 100644 --- a/lib/client.js +++ b/lib/client.js @@ -19,6 +19,51 @@ const DistroUtils = require('./distro.js'); const Entity = require('./entity.js'); const debug = require('debug')('rclnodejs:client'); +// Polyfill for AbortSignal.any() for Node.js <= 20.3.0 +// AbortSignal.any() was added in Node.js 20.3.0 +// See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static +if (!AbortSignal.any) { + AbortSignal.any = function (signals) { + // Filter out null/undefined values and validate inputs + const validSignals = Array.isArray(signals) + ? signals.filter((signal) => signal != null) + : []; + + // If no valid signals, return a never-aborting signal + if (validSignals.length === 0) { + return new AbortController().signal; + } + + const controller = new AbortController(); + const listeners = []; + + // Cleanup function to remove all event listeners + const cleanup = () => { + listeners.forEach(({ signal, listener }) => { + signal.removeEventListener('abort', listener); + }); + }; + + for (const signal of validSignals) { + if (signal.aborted) { + cleanup(); + controller.abort(signal.reason); + return controller.signal; + } + + const listener = () => { + cleanup(); + controller.abort(signal.reason); + }; + + signal.addEventListener('abort', listener); + listeners.push({ signal, listener }); + } + + return controller.signal; + }; +} + /** * @class - Class representing a Client in ROS * @hideconstructor diff --git a/test/test-async-client.js b/test/test-async-client.js index b5c49ec1..53156570 100644 --- a/test/test-async-client.js +++ b/test/test-async-client.js @@ -260,6 +260,14 @@ describe('Client async functionality', function () { }); it('should handle zero and negative timeouts', async function () { + // Skip this test on Node.js < 18.20.0: AbortSignal.timeout() was added in 17.3.0, + // but support for zero timeout values was only fixed in + // 18.20.0 (prior versions throw RangeError for AbortSignal.timeout(0)) + const [major, minor] = process.versions.node.split('.').map(Number); + if (major < 18 || (major === 18 && minor < 20)) { + this.skip(); + } + const request = { a: BigInt(1), b: BigInt(1) }; try {