RangerMauve / mqtt-regex

Converts an MQTT topic with parameters into a regular expression.
MIT License
20 stars 1 forks source link

optional named parameters #3

Closed alexdmejias closed 8 years ago

alexdmejias commented 8 years ago

is it possible to have optional named parameters?

example: pattern = 'enslavement/+event/+type/to/+slaveId/from/+masterId' topics: enslavement/list/req or enslavement/list/req/to/ALL.

Right now when I try this, it fails and I get a undefined from an exec call.

const pattern = 'enslavement/+event/+type/to/+slaveId/from/+masterId';
const eventInfo = MqttRegex(pattern).exec;
const actualTopic = 'enslavement/list/req';
const params = eventInfo(actualTopic); //undefined
RangerMauve commented 8 years ago

For wildcards with a + you can only match if you have a value for each parameter. If you're missing parameters then the topic cannot match.

You could use enslavement/#paths and then extract the relevant sections from the resulting array.

var pattern = "enslavement/+event/+type/#otherstuff";

var eventInfo = MqttRegex(pattern).exec;

var actualTopoic = "enslavement/list/req";

var params = eventInfo(actualTopic);

var otherstuff= params.otherstuff;
if(otherstuff.length >= 2){
  var saveId = otherStuff[1];
}
if(otherstuff.length >= 4){
  var masterId = otherStuff[3];
}

But it really seems like you might be better off having more than one pattern.

Like:

var typePattern = "enslavement/+event/+type";
var toPattern = typePattern + "/to/+slaveId";
var messagePattern = toPattern + "/from/+masterId";

and then have mqtt-regex instances for each one.

However, you might be interested in mqtt-emitter which makes it easy to match a bunch of different patterns and react to them, while dispatching everything in one place.

You could just do

var emitter = new MQTTEmitter();

emitter.on("enslavement/+event/+type/to/+slaveId/from/+masterId", message_between_slave_and_master);
emitter.on("enslavement/+event/+type/to/+slaveId", message_to_slave);
emitter.on("enslavement/+event/+type", message_of_type);

emitter.emit("enslavement/list/req", "some payload for the event");
// WIll trigger the "message_of_type" function;
emitter.emit("enslavement/list/req/to/ALL", "some other payload");
// Will trigger the "message_to_slave" event

This way you can react to different types of events and have the routing handled for you as well as the parameter parsing just for the events that actually contain all the data needed for parameters.

I'd rather not add "optional parameters", however, because nothing like this exists in the MQTT spec, and I'd like to make things extra simple and as close as possible to the sorts of topics you would be able to subscribe to on an actual MQTT broker.

alexdmejias commented 8 years ago

Thanks for comprehensive response! I'm not sure how extensible the first solution might be, but the second one is definitely something that I'm interested on. I'm curious as how to a simple implementation with MQTT.js might look like. Like, how would MQTTEmitter know to emit an event with my mqtt instance

RangerMauve commented 8 years ago

Yup, I've been meaning to create a library that integrates them, but the code would just look like:

var emitter = new MQTTEmitter();
var client = mqtt.connect("ws://whatever");

client.on("message", function(topic, message){
  emitter.emit(topic, message)l
});

emitter.onadd = function (topic) {
    client.subscribe(topic);
}
emitter.onremove = function (topic) {
    client.unsubscribe(topic);
}

// Wait for the client to become connected before adding listeners

// Will subscribe on the topic "some/+/#"
emitter.on("some/+topic/#here", function(payload, params, topic){
  console.log(topic, params, payload);
});

// Will log: "some/foo/bar/baz" {topic:foo, here:[bar/baz]} "foobar"
client.publish("some/foo/bar/baz", "foobar");

Just keep in mind that you'll need to keep track of your subscriptions and call client.subscribe for all of them if the client disconnects/reconnects.

alexdmejias commented 8 years ago

Thanks for the help @RangerMauve, I ended up implementing something similar to what you mentioned and it seems to be working for now, I'll look into simplifying it later.