shanewholloway/js-u8-mqtt

Single and multi-level wildcards

Closed this issue · 4 comments

Can I use single- and multi-level wildcards (+ and #) as described in MQTT Spec v5?

What was the reasoning for relying on an ExpressJS-like parsing algorithm?

UPDATE: Actually it is possible to use # as wildcard subscription, the resulting value will be available in params as wild: 'matching-string'. However +name or just + doesn't work...

On the design choice of using ExpressJS-like path parsing, I found the matching logic for topics to handler functions very similar. I opted to re-use the broadly understood technique over reinventing something. Thanks for the question!

Regarding using MQTT wildcards, it is possible to send them to the MQTT server as-is. Instead of using the .subscribe_topic() wrapper method, use the .subscribe() and .on_topic() methods separately. The first sends the subscribe packet, and the .on_topic() allows hooking a corresponding handler. You could handle multiple different subscriptions in a single handler registered via .on_topic().

my_mqtt.on_topic('u8-mqtt-demo/*', pkt =>
    console.log(`Message`, pkt))

// ...
my_mqtt.subscribe('u8-mqtt-demo/part+/tail')

Also, I intended to have the ExpressJS router be an optional aspect of the library. Your question reminded me, and thus I did a bit of refactoring with my Saturday. u8-mqtt@0.4.0

Thank you for the quick response and the new minor version published yesterday. I did not find my way around the documentation so well, so maybe you could give an example of a handler without the expressJS-like logic that comes with .on_topic()? That should be possible now, right?

UPDATE: My bad, figured it out after upgrading to latest 0.4.0. One can use it as expected:

client.subscribe('v1/states/+/components/+/ios/channels/#')
client.on_topic('v1/states/+/components/#', (pkt, params) => {
   // params contains:
   // $1: 'value' ($n for each +)
   // wild: 'value'
})

This now also works: client.subscribe_topic('v1/states/+/components/#', (pkt: any, params: any) => {})

Very cool, thanks!

Fantastic! Glad you have that working. Your example illustrates how useful it can be to separate handler logic from subscription logic.

If you want, you can name those variables using the :param_name syntax:

client.subscribe('v1/states/+/components/+/ios/channels/#')

client.on_topic('v1/states/:state_name/components/#', (pkt, params) => {
   // params contains:
   // state_name: 'value'
   // wild: 'value'
})

Also, I add a demo of splitting the two method calls at demo/simple/nodejs-split.js for others to find.