rxmqjs / rxmq.js

JavaScript pub/sub library based on RxJS
144 stars 22 forks source link

Wildcard for segment and all sub-segments #13

Closed memelet closed 7 years ago

memelet commented 7 years ago

We typically have sources producing events as part of the same overall logical group, but where only some topics need replay

topic: device.d1, subject: Subject
topic: device.d1.execution, subject: ReplaySubject

Most subscribers still need to subscribe to all events

Rx.merge(Rxmq.channel().observe('device.d1'), Rxmq.channel().observe('device.d1.#'))

It would be nice for the wildcards to support this semantic. Maybe like

Rxmq.channel().observe('device.d1>')

I'm thinking that in this case '>' is also a word separator. So the above would not match device.d123.

But I suppose to keep in line with the current regex parsing, maybe the syntax would need to be device.d1.>

memelet commented 7 years ago

So maybe something like in topicToRegex

    ...
    } else {
      if (segment.slice(-1) === '>') {
        res += segment.slice(0, -1);
        res += '[\\s\\S]*';
      } else {
        res += segment;
      }
    }
    ....

The optimization guards in compareTopics and Channel:observe need to be tweaked. But these tests now pass

            t.equal(compareTopics('test', 'test>'), true);
            t.equal(compareTopics('test.one', 'test>'), true);

And there should probably be a check that if '>' is present it is the last character.

yamalight commented 7 years ago

@memelet wouldn't it be simpler to create new topic and pipe data from that merge into it? e.g.

Rx.merge(Rxmq.channel().observe('device.d1'), Rxmq.channel().observe('device.d1.#'))
  .subscribe(Rxmq.channel().subject('device.all'))
memelet commented 7 years ago

That certainly works. But it breaks the contract with our source plugins, which get to decide what subtopics a specific event maps to.

memelet commented 7 years ago

But what we do now of course works

const stream = Rx.merge(
    Rxmq.channel().observe('device.d1'), 
    Rxmq.channel().observe('device.d1.#'))
yamalight commented 7 years ago

@memelet ah, true. Didn't think of that.

Just to elaborate on why I don't want to change current syntax: Currently the syntax pretty much follows AMQP topic syntax one-to-one. So, you can easily use rxmq as browser middleware for e.g. RabbitMQ. Changing that syntax would lead to incompatibility which is something I wouldn't want.

I'd say that the best way might be to write a channel plugin, that would e.g. allow something like this: Rxmq.channel().all('subj1', 'subj2', 'subj3')

memelet commented 7 years ago

@yamalight Understood, makes sense.

I thought that ActiveMQ had a syntax like this, but checking its more like Rabbit's -- just that '>' is used instead of '#'.

thanks!

yamalight commented 7 years ago

@memelet yeah, ActiveMQ syntax is also AMQP compliant as far as I know. just uses a different symbol. please, do let me know if you create and publish that plugin. Would love to feature it on rxmq readme 👍