Skip to content

Commit a543657

Browse files
committed
Address comments
1 parent 7fa556f commit a543657

2 files changed

Lines changed: 80 additions & 17 deletions

File tree

lib/action/client.js

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ class ActionClient extends Entity {
7070
this._pendingGoalRequests = new Map();
7171
this._pendingCancelRequests = new Map();
7272
this._pendingResultRequests = new Map();
73+
this._filterGoalIds = new Set();
74+
this._filterGoalIdBuffers = new Map();
7375

7476
// Setup options defaults
7577
this._options = this._options || {};
@@ -509,25 +511,53 @@ class ActionClient extends Entity {
509511
this._pendingCancelRequests.delete(sequenceNumber);
510512
}
511513

514+
/**
515+
* Disable feedback optimization and best-effort remove all tracked goal IDs
516+
* from the native filter so the subscription reverts to unfiltered state.
517+
* @ignore
518+
* @param {string} reason - Warning message describing why optimization was disabled.
519+
*/
520+
_disableFeedbackMsgOptimization(reason) {
521+
this._enableFeedbackMsgOptimization = false;
522+
523+
// Best-effort remove every goal ID still in the native filter so that
524+
// the subscription reverts to an unfiltered state and future feedback
525+
// is not silently dropped.
526+
for (const [uuid, goalIdBuf] of this._filterGoalIdBuffers) {
527+
try {
528+
rclnodejs.actionConfigureFeedbackSubFilterRemoveGoalId(
529+
this.handle,
530+
goalIdBuf
531+
);
532+
} catch {
533+
// Intentionally swallowed — we are already disabling.
534+
}
535+
}
536+
this._filterGoalIds.clear();
537+
this._filterGoalIdBuffers.clear();
538+
539+
this._node
540+
.getLogger()
541+
.warn(
542+
`${reason}\nFeedback message optimization is automatically disabled.`
543+
);
544+
}
545+
512546
/**
513547
* Add a goal ID to the feedback subscription content filter.
514548
* @ignore
515549
* @param {object} goalId - The goal UUID message.
516550
*/
517551
_feedbackSubFilterAddGoalId(goalId) {
518552
if (!this._enableFeedbackMsgOptimization) return;
553+
const uuid = ActionUuid.fromMessage(goalId).toString();
554+
const buf = Buffer.from(goalId.uuid);
519555
try {
520-
rclnodejs.actionConfigureFeedbackSubFilterAddGoalId(
521-
this.handle,
522-
Buffer.from(goalId.uuid)
523-
);
556+
rclnodejs.actionConfigureFeedbackSubFilterAddGoalId(this.handle, buf);
557+
this._filterGoalIds.add(uuid);
558+
this._filterGoalIdBuffers.set(uuid, buf);
524559
} catch (e) {
525-
this._enableFeedbackMsgOptimization = false;
526-
this._node
527-
.getLogger()
528-
.warn(
529-
`${e.message}\nFeedback message optimization is automatically disabled.`
530-
);
560+
this._disableFeedbackMsgOptimization(e.message);
531561
}
532562
}
533563

@@ -538,18 +568,18 @@ class ActionClient extends Entity {
538568
*/
539569
_feedbackSubFilterRemoveGoalId(goalId) {
540570
if (!this._enableFeedbackMsgOptimization) return;
571+
const uuid = ActionUuid.fromMessage(goalId).toString();
572+
if (!this._filterGoalIds.has(uuid)) return;
573+
this._filterGoalIds.delete(uuid);
574+
const buf = this._filterGoalIdBuffers.get(uuid);
575+
this._filterGoalIdBuffers.delete(uuid);
541576
try {
542577
rclnodejs.actionConfigureFeedbackSubFilterRemoveGoalId(
543578
this.handle,
544-
Buffer.from(goalId.uuid)
579+
buf || Buffer.from(goalId.uuid)
545580
);
546581
} catch (e) {
547-
this._enableFeedbackMsgOptimization = false;
548-
this._node
549-
.getLogger()
550-
.warn(
551-
`${e.message}\nFeedback message optimization is automatically disabled.`
552-
);
582+
this._disableFeedbackMsgOptimization(e.message);
553583
}
554584
}
555585

test/test-subscription-content-filter.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,36 @@ describe('subscription content-filtering', function () {
480480
done();
481481
});
482482
});
483+
484+
describe('subscription isContentFilterSupported', function () {
485+
this.timeout(30 * 1000);
486+
487+
beforeEach(async function () {
488+
await rclnodejs.init();
489+
this.node = new Node('cft_support_test_node');
490+
});
491+
492+
afterEach(function () {
493+
this.node.destroy();
494+
rclnodejs.shutdown();
495+
});
496+
497+
it('isContentFilterSupported returns boolean matching RMW capability', function (done) {
498+
const typeclass = 'std_msgs/msg/Int16';
499+
const subscription = this.node.createSubscription(
500+
typeclass,
501+
TOPIC,
502+
(msg) => {}
503+
);
504+
505+
const supported = subscription.isContentFilterSupported();
506+
assert.strictEqual(typeof supported, 'boolean');
507+
508+
// isContentFilterSupported requires rolling; on older distros it returns false
509+
const isRolling = DistroUtils.getDistroId() >= DistroUtils.DistroId.ROLLING;
510+
const expectedSupported = isRolling && isContentFilteringSupported();
511+
assert.strictEqual(supported, expectedSupported);
512+
513+
done();
514+
});
515+
});

0 commit comments

Comments
 (0)