Commit 33d19cec63a85e6b0a226a3dcfab5eb1d345c0b4
1 parent
70896f68
I think this covers retained messages
Showing
7 changed files
with
99 additions
and
19 deletions
CMakeLists.txt
retainedmessage.cpp
0 → 100644
| 1 | +#include "retainedmessage.h" | |
| 2 | + | |
| 3 | +RetainedMessage::RetainedMessage(const std::string &topic, const std::string &payload, char qos) : | |
| 4 | + topic(topic), | |
| 5 | + payload(payload), | |
| 6 | + qos(qos) | |
| 7 | +{ | |
| 8 | + | |
| 9 | +} | |
| 10 | + | |
| 11 | +bool RetainedMessage::operator==(const RetainedMessage &rhs) const | |
| 12 | +{ | |
| 13 | + return this->topic == rhs.topic; | |
| 14 | +} | ... | ... |
retainedmessage.h
0 → 100644
| 1 | +#ifndef RETAINEDMESSAGE_H | |
| 2 | +#define RETAINEDMESSAGE_H | |
| 3 | + | |
| 4 | +#include <string> | |
| 5 | + | |
| 6 | +struct RetainedMessage | |
| 7 | +{ | |
| 8 | + std::string topic; | |
| 9 | + std::string payload; | |
| 10 | + char qos; | |
| 11 | + | |
| 12 | + RetainedMessage(const std::string &topic, const std::string &payload, char qos); | |
| 13 | + | |
| 14 | + bool operator==(const RetainedMessage &rhs) const; | |
| 15 | +}; | |
| 16 | + | |
| 17 | +namespace std { | |
| 18 | + | |
| 19 | + template <> | |
| 20 | + struct hash<RetainedMessage> | |
| 21 | + { | |
| 22 | + std::size_t operator()(const RetainedMessage& k) const | |
| 23 | + { | |
| 24 | + using std::size_t; | |
| 25 | + using std::hash; | |
| 26 | + using std::string; | |
| 27 | + | |
| 28 | + return hash<string>()(k.topic); | |
| 29 | + } | |
| 30 | + }; | |
| 31 | + | |
| 32 | +} | |
| 33 | + | |
| 34 | +#endif // RETAINEDMESSAGE_H | ... | ... |
subscriptionstore.cpp
| ... | ... | @@ -46,7 +46,7 @@ void SubscriptionStore::addSubscription(Client_p &client, const std::string &top |
| 46 | 46 | clients_by_id[client->getClientId()] = client; |
| 47 | 47 | lock_guard.unlock(); |
| 48 | 48 | |
| 49 | - giveClientRetainedMessage(client, topic); // TODO: wildcards | |
| 49 | + giveClientRetainedMessages(client, topic); | |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | void SubscriptionStore::removeClient(const Client_p &client) |
| ... | ... | @@ -122,22 +122,20 @@ void SubscriptionStore::queuePacketAtSubscribers(const std::string &topic, const |
| 122 | 122 | publishRecursively(subtopics.begin(), subtopics.end(), root, packet); |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | -void SubscriptionStore::giveClientRetainedMessage(Client_p &client, const std::string &topic) | |
| 125 | +void SubscriptionStore::giveClientRetainedMessages(Client_p &client, const std::string &subscribe_topic) | |
| 126 | 126 | { |
| 127 | 127 | RWLockGuard locker(&retainedMessagesRwlock); |
| 128 | 128 | locker.rdlock(); |
| 129 | 129 | |
| 130 | - auto retained_ptr = retainedMessages.find(topic); | |
| 131 | - | |
| 132 | - if (retained_ptr == retainedMessages.end()) | |
| 133 | - return; | |
| 134 | - | |
| 135 | - const RetainedPayload &m = retained_ptr->second; | |
| 130 | + for(const RetainedMessage &rm : retainedMessages) | |
| 131 | + { | |
| 132 | + Publish publish(rm.topic, rm.payload, rm.qos); | |
| 133 | + publish.retain = true; | |
| 134 | + const MqttPacket packet(publish); | |
| 136 | 135 | |
| 137 | - Publish publish(topic, m.payload, m.qos); | |
| 138 | - publish.retain = true; | |
| 139 | - const MqttPacket packet(publish); | |
| 140 | - client->writeMqttPacket(packet); | |
| 136 | + if (topicsMatch(subscribe_topic, rm.topic)) | |
| 137 | + client->writeMqttPacket(packet); | |
| 138 | + } | |
| 141 | 139 | } |
| 142 | 140 | |
| 143 | 141 | void SubscriptionStore::setRetainedMessage(const std::string &topic, const std::string &payload, char qos) |
| ... | ... | @@ -145,7 +143,9 @@ void SubscriptionStore::setRetainedMessage(const std::string &topic, const std:: |
| 145 | 143 | RWLockGuard locker(&retainedMessagesRwlock); |
| 146 | 144 | locker.wrlock(); |
| 147 | 145 | |
| 148 | - auto retained_ptr = retainedMessages.find(topic); | |
| 146 | + RetainedMessage rm(topic, payload, qos); | |
| 147 | + | |
| 148 | + auto retained_ptr = retainedMessages.find(rm); | |
| 149 | 149 | bool retained_found = retained_ptr != retainedMessages.end(); |
| 150 | 150 | |
| 151 | 151 | if (!retained_found && payload.empty()) |
| ... | ... | @@ -153,13 +153,11 @@ void SubscriptionStore::setRetainedMessage(const std::string &topic, const std:: |
| 153 | 153 | |
| 154 | 154 | if (retained_found && payload.empty()) |
| 155 | 155 | { |
| 156 | - retainedMessages.erase(topic); | |
| 156 | + retainedMessages.erase(rm); | |
| 157 | 157 | return; |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | - RetainedPayload &m = retainedMessages[topic]; | |
| 161 | - m.payload = payload; | |
| 162 | - m.qos = qos; | |
| 160 | + retainedMessages.insert(std::move(rm)); | |
| 163 | 161 | } |
| 164 | 162 | |
| 165 | 163 | ... | ... |
subscriptionstore.h
| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | |
| 12 | 12 | #include "client.h" |
| 13 | 13 | #include "utils.h" |
| 14 | +#include "retainedmessage.h" | |
| 14 | 15 | |
| 15 | 16 | struct RetainedPayload |
| 16 | 17 | { |
| ... | ... | @@ -39,7 +40,7 @@ class SubscriptionStore |
| 39 | 40 | const std::unordered_map<std::string, Client_p> &clients_by_id_const; |
| 40 | 41 | |
| 41 | 42 | pthread_rwlock_t retainedMessagesRwlock = PTHREAD_RWLOCK_INITIALIZER; |
| 42 | - std::unordered_map<std::string, RetainedPayload> retainedMessages; | |
| 43 | + std::unordered_set<RetainedMessage> retainedMessages; | |
| 43 | 44 | |
| 44 | 45 | bool publishNonRecursively(const MqttPacket &packet, const std::forward_list<std::string> &subscribers) const; |
| 45 | 46 | bool publishRecursively(std::list<std::string>::const_iterator cur_subtopic_it, std::list<std::string>::const_iterator end, |
| ... | ... | @@ -51,7 +52,7 @@ public: |
| 51 | 52 | void removeClient(const Client_p &client); |
| 52 | 53 | |
| 53 | 54 | void queuePacketAtSubscribers(const std::string &topic, const MqttPacket &packet, const Client_p &sender); |
| 54 | - void giveClientRetainedMessage(Client_p &client, const std::string &topic); | |
| 55 | + void giveClientRetainedMessages(Client_p &client, const std::string &subscribe_topic); | |
| 55 | 56 | |
| 56 | 57 | void setRetainedMessage(const std::string &topic, const std::string &payload, char qos); |
| 57 | 58 | }; | ... | ... |
utils.cpp
| ... | ... | @@ -18,3 +18,33 @@ std::list<std::__cxx11::string> split(const std::string &input, const char sep, |
| 18 | 18 | list.push_back(input.substr(start, std::string::npos)); |
| 19 | 19 | return list; |
| 20 | 20 | } |
| 21 | + | |
| 22 | + | |
| 23 | +bool topicsMatch(const std::string &subscribeTopic, const std::string &publishTopic) | |
| 24 | +{ | |
| 25 | + if (subscribeTopic.find("+") == std::string::npos && subscribeTopic.find("#") == std::string::npos) | |
| 26 | + return subscribeTopic == publishTopic; | |
| 27 | + | |
| 28 | + const std::list<std::string> subscribeParts = split(subscribeTopic, '/'); | |
| 29 | + const std::list<std::string> publishParts = split(publishTopic, '/'); | |
| 30 | + | |
| 31 | + auto subscribe_itr = subscribeParts.begin(); | |
| 32 | + auto publish_itr = publishParts.begin(); | |
| 33 | + | |
| 34 | + bool result = true; | |
| 35 | + while (subscribe_itr != subscribeParts.end() && publish_itr != publishParts.end()) | |
| 36 | + { | |
| 37 | + const std::string &subscribe_subtopic = *subscribe_itr++; | |
| 38 | + const std::string &publish_subtopic = *publish_itr++; | |
| 39 | + | |
| 40 | + if (subscribe_subtopic == "+") | |
| 41 | + continue; | |
| 42 | + if (subscribe_subtopic == "#") | |
| 43 | + return true; | |
| 44 | + if (subscribe_subtopic != publish_subtopic) | |
| 45 | + return false; | |
| 46 | + } | |
| 47 | + | |
| 48 | + result = subscribe_itr == subscribeParts.end() && publish_itr == publishParts.end(); | |
| 49 | + return result; | |
| 50 | +} | ... | ... |
utils.h
| ... | ... | @@ -21,4 +21,6 @@ template<typename T> int check(int rc) |
| 21 | 21 | |
| 22 | 22 | std::list<std::string> split(const std::string &input, const char sep, size_t max = std::numeric_limits<int>::max(), bool keep_empty_parts = true); |
| 23 | 23 | |
| 24 | +bool topicsMatch(const std::string &subscribeTopic, const std::string &publishTopic); | |
| 25 | + | |
| 24 | 26 | #endif // UTILS_H | ... | ... |