0

Is there a built in way to check with hivemq-mqtt-client if a specific topic matches another topic in advance?

For instance, a message published with topic:

publishedTopic= "sensors/sensor1";

A client that subscribes:

subscribedTopic = "sensors/#";

Is there something like

publishedTopic.matches(subscribedTopic)

?

The exact situation:

I run a broker in my house, several devices publish values with different topics. Some like sensor/humi[45], some like sensor/data[JSON Payload]. For my personal use I run an application using Java HiveQM MQTT clients. One client is subscribed to relevant topics using mosquitto on raspberryPi. The other client is publishing selected data to a public accessible broker. Receiving a new message will not only process all data in the way I process it but also trigger a publishing the received message to the public broker.

Yes, I can

if(topic.equals("sensor/xxx")) {
//publish to public broker here
}

But doing some like subscribing to "sensor/#", from my internal broker, and "forwarding" something like "sensor/+", and letting a library doing the job of determining if a certain message that is received with "sensors/#", will be republished to the public broker, limited to "sensors/+" is what I am looking for.

Is the logic inside HiveMQ mqtt-client library, which obviously filters in that exact way, when I subscribe to "sensors/#", accessible for the library user?

Michi
  • 487
  • 5
  • 20
  • What do you want to achieve? Do you want to validate if your are using wildcards properly? – Odysseus Dec 18 '20 at 08:07
  • I want to forward topics subscribed by a client I have full control of, of a broker I have full access to, to a broker in an environment I have only limited control but that has public access. I don't want to let pass "sensors/#' in general, but "sensor/publicData" should be forwarded. – Michi Dec 18 '20 at 08:19
  • So you want to realize some kind of topic filter? Let's say your client subscribes `sensors/#` on BrokerA and you want to forward `sensors/sensor1` but not `sensors/sensors2` e.g.? And what is meant by "forward" - republish this topic from your client to BrokerB? – Odysseus Dec 18 '20 at 08:29
  • Yes, thats what I want and I want to republish, and I want to make the decision on the client, and do things like: subscribe BrokerA: sensors/sensor1/data, republish BrokerB: publicData/aPublicSensorname/data – Michi Dec 18 '20 at 08:33

3 Answers3

2
import com.hivemq.client.mqtt.datatypes.MqttTopic;
import com.hivemq.client.mqtt.datatypes.MqttTopicFilter;
...

class Example {
    static boolean matches( String topicFilter, String topicReceived ) {
        MqttTopicFilter filter = MqttTopicFilter.of(topicFilter);
        MqttTopic topic = MqttTopic.of(topicReceived);
        return filter.matches(topic);
    }
}
Charlie Reitzel
  • 809
  • 8
  • 13
  • And this is the answer to the exact question. But the answer I marked as correct is the Answer to the question I should have asked :) – Michi Jan 14 '21 at 18:28
  • 1
    Ya, fair enough. Personally, I found this useful in the case where a single client subscribes to multiple filters. This call can be used to answer the question, "which subscription is _this_ message for?", and dispatch the message to the appropriate handler. As is often the case, the right questions and answers depend on your application requirements. It's not a perfect solution because it's easy for more than one subscription to match any given topic. So, some tie-breaker rule is still required, e.g. "first match wins" and evaluate in configured order. – Charlie Reitzel Jan 14 '21 at 19:18
1

One way to achieve what you want is to use a particular callback for the topics you want to forward.

Using HiveMQ library you can define a callback to consume the received message per subscribe or globally matching a given filter.

In your case you could use a per subscribe consumer for the topics which should be handled in a special way:

client.subscribeWith()
        .topicFilter("sensors/sensor1")
        .qos(<qos>)
        .callback(<callback for topics to be forwarded>)
        .send();

Followed by a global filter matching all topics which are not yet consumed:

client.publishes(MqttGlobalPublishFilter.REMAINING, <callback for other topics>))

(and the subscription to sensors/# of course)

This way only sensors/sensor1 will be consumed in your first callback and sensors/sensor2, sensors/sensor3 (and so on) are consumed by the other callback

Odysseus
  • 1,213
  • 4
  • 12
0

Part of the point of MQTT is to totally decouple the information producers from the consumers. This means that a client publishing a messages to a topic knows absolutely nothing about any clients that may be subscribed to the topic that the message is published to.

There may be any where from 0 to infinite subscribers and they may be subscribed to just the exactly matching topic or a wildcard that will match.

In the situation you describe in the comments, where you have a bridge between 2 brokers, you will need to explicitly list the topics you want to bridge, normally you can not change that list dynamically based on what a given client connected to the one of the brokers is subscribed to.

You might be able to write a plugin for HiveMQ that would do this, but it would have to run on the same broker that the client subscribes to which if I've understood correctly is the one you don't have control over.

hardillb
  • 54,545
  • 11
  • 67
  • 105
  • To describe my situation more exactly: I have a weather station, a solar panel on the roof and an inverter. The weather station provides all data including inside humidity and temp, which I consider sensitive data. The inverter provides current power produced, consumed, purchased. Current power produced is not sensitive data, the other values are. I want to use all values in my house, using mosquitto on RPi, but forward only environment data to my public weather page, using a public broker, that can't restrict access to certain topics. I want to use the built-in logic, if possible. – Michi Dec 18 '20 at 12:55