Commit 787db53b authored by Alessio Netti's avatar Alessio Netti
Browse files

MQTT Topics and Names checks

- Name uniqueness checks have been extended to sensor names and sensor
groups (managed by two separate sets)
parent 06155b53
...@@ -109,7 +109,7 @@ bool AnalyticsManager::load(const string& path, const string& globalFile, const ...@@ -109,7 +109,7 @@ bool AnalyticsManager::load(const string& path, const string& globalFile, const
if(dynLib.configurator->getAnalyzers().size() == 0) { if(dynLib.configurator->getAnalyzers().size() == 0) {
LOG(warning) << "Plugin \"" << dynLib.id << "\" created no analyzers!"; LOG(warning) << "Plugin \"" << dynLib.id << "\" created no analyzers!";
} else if(!checkTopics(dynLib)) { } else if(!checkTopics(dynLib)) {
LOG(error) << "Problematic MQTT-Topics, please check your config files!"; LOG(error) << "Problematic MQTT topics or sensor names, please check your config files!";
return false; return false;
} }
//save dl-struct //save dl-struct
...@@ -172,11 +172,13 @@ bool AnalyticsManager::reload(boost::asio::io_service& io, const string& plugin) ...@@ -172,11 +172,13 @@ bool AnalyticsManager::reload(boost::asio::io_service& io, const string& plugin)
void AnalyticsManager::removeTopics(an_dl_t p) { void AnalyticsManager::removeTopics(an_dl_t p) {
MQTTChecker& mqttCheck = MQTTChecker::getInstance(); MQTTChecker& mqttCheck = MQTTChecker::getInstance();
for(const auto& a : p.configurator->getAnalyzers()) { for(const auto& a : p.configurator->getAnalyzers()) {
mqttCheck.removeName(a->getName()); mqttCheck.removeGroup(a->getName());
if (a->getStreaming()) if (a->getStreaming())
for (const auto &u : a->getUnits()) for (const auto &u : a->getUnits())
for (const auto &o: u->getBaseOutputs()) for (const auto &o: u->getBaseOutputs()) {
mqttCheck.removeTopic(o->getMqtt()); mqttCheck.removeTopic(o->getMqtt());
mqttCheck.removeName(o->getName());
}
} }
} }
...@@ -184,12 +186,12 @@ bool AnalyticsManager::checkTopics(an_dl_t p) { ...@@ -184,12 +186,12 @@ bool AnalyticsManager::checkTopics(an_dl_t p) {
MQTTChecker& mqttCheck = MQTTChecker::getInstance(); MQTTChecker& mqttCheck = MQTTChecker::getInstance();
bool validTopics=true; bool validTopics=true;
for(const auto& a : p.configurator->getAnalyzers()) { for(const auto& a : p.configurator->getAnalyzers()) {
if (!mqttCheck.checkName(a->getName())) if (!mqttCheck.checkGroup(a->getName()))
validTopics = false; validTopics = false;
if (a->getStreaming()) if (a->getStreaming())
for (const auto &u : a->getUnits()) for (const auto &u : a->getUnits())
for (const auto &o: u->getBaseOutputs()) for (const auto &o: u->getBaseOutputs())
if (!mqttCheck.checkTopic(o->getMqtt())) if (!mqttCheck.checkTopic(o->getMqtt()) || !mqttCheck.checkName(o->getName()))
validTopics = false; validTopics = false;
} }
return validTopics; return validTopics;
......
...@@ -78,30 +78,60 @@ public: ...@@ -78,30 +78,60 @@ public:
return true; return true;
} }
/**
* @brief Removes a name from the internal set of sensor names
*
* This method should be used to remove obsolete sensor names, e.g. when reloading plugins.
* This is useful only in the case that MQTT topics differ from the actual sensor names.
*
* @param name The name (string) to be removed
*/
//TODO: get rid of these two methods once MQTT topics and sensor names are unified
void removeName(const std::string& name) {
_names.erase(name);
}
/**
* @brief Performs a check on a certain name
*
* The check is passed if the name for the group, analyzer or entity is not used already.
*
* @param name An arbitrary name (string) to check
* @return True if the name is valid, False otherwise
*/
bool checkName(const std::string& name) {
auto returnIt = _names.insert(name);
if (!returnIt.second) {
LOG(error) << "Name \"" << name << "\" used twice!";
return false;
}
return true;
}
/** /**
* @brief Removes a name from the internal set of entities * @brief Removes a name from the internal set of entities
* *
* This method should be used to remove obsolete sensor groups, entities or analyzers once they * This method should be used to remove obsolete sensor groups, entities or analyzers once they
* are destroyed, e.g. on plugin reload actions. * are destroyed, e.g. on plugin reload actions.
* *
* @param topic The name (string) to be removed * @param name The name (string) to be removed
*/ */
void removeName(const std::string& name) { void removeGroup(const std::string& name) {
_groups.erase(name); _groups.erase(name);
} }
/** /**
* @brief Performs a check on a certain name * @brief Performs a check on a certain group name
* *
* The check is passed if the name for the group, analyzer or entity is not used already. * The check is passed if the name for the group, analyzer or entity is not used already.
* *
* @param topic An arbitrary name (string) to check * @param name An arbitrary name (string) to check
* @return True if the name is valid, False otherwise * @return True if the name is valid, False otherwise
*/ */
bool checkName(const std::string& name) { bool checkGroup(const std::string& name) {
auto returnIt = _groups.insert(name); auto returnIt = _groups.insert(name);
if (!returnIt.second) { if (!returnIt.second) {
LOG(error) << "Name \"" << name << "\" used twice!"; LOG(error) << "Group name \"" << name << "\" used twice!";
return false; return false;
} }
return true; return true;
...@@ -128,6 +158,8 @@ private: ...@@ -128,6 +158,8 @@ private:
std::set<std::string> _topics; std::set<std::string> _topics;
// Set used to keep track of groups, analyzers and other entities // Set used to keep track of groups, analyzers and other entities
std::set<std::string> _groups; std::set<std::string> _groups;
// Set used to keep track of sensor names (if different from the respective topics)
std::set<std::string> _names;
// Logger object to notify MQTT check outcome // Logger object to notify MQTT check outcome
logger_t lg; logger_t lg;
......
...@@ -297,13 +297,16 @@ bool Configuration::readPlugins() { ...@@ -297,13 +297,16 @@ bool Configuration::readPlugins() {
//check if an MQTT-suffix was assigned twice //check if an MQTT-suffix was assigned twice
bool validTopics=true; bool validTopics=true;
for(const auto& g : dynLib.configurator->getSensorGroups()) for(const auto& g : dynLib.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) if (!mqttCheck.checkGroup(g->getGroupName()))
if(!mqttCheck.checkTopic(s->getMqtt())) validTopics = false;
validTopics=false; for (const auto &s : g->getSensors())
if (!mqttCheck.checkTopic(s->getMqtt()) || !mqttCheck.checkName(s->getName()))
validTopics = false;
}
if(!validTopics) { if(!validTopics) {
LOG(error) << "Problematic MQTT-Topics, please check your config files!"; LOG(error) << "Problematic MQTT topics or sensor names, please check your config files!";
return false; return false;
} }
......
...@@ -369,7 +369,7 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser ...@@ -369,7 +369,7 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser
if (p.configurator->reReadConfig()) { if (p.configurator->reReadConfig()) {
// Perform checks on MQTT topics // Perform checks on MQTT topics
if(!_httpsServer.checkTopics(p)) { if(!_httpsServer.checkTopics(p)) {
response = "Plugin " + pathStrs[0] + ": problematic MQTT-Topics, please check your config files!"; response = "Plugin " + pathStrs[0] + ": problematic MQTT topics or sensor names, please check your config files!";
connection->set_status(server::connection::internal_server_error); connection->set_status(server::connection::internal_server_error);
_httpsServer.removeTopics(p); _httpsServer.removeTopics(p);
p.configurator->clearConfig(); p.configurator->clearConfig();
...@@ -460,18 +460,25 @@ bool HttpsServer::check_authkey(const std::string& authkey, permission requiredP ...@@ -460,18 +460,25 @@ bool HttpsServer::check_authkey(const std::string& authkey, permission requiredP
void HttpsServer::removeTopics(dl_t p) { void HttpsServer::removeTopics(dl_t p) {
MQTTChecker& mqttCheck = MQTTChecker::getInstance(); MQTTChecker& mqttCheck = MQTTChecker::getInstance();
for(const auto& g : p.configurator->getSensorGroups()) for(const auto& g : p.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) mqttCheck.removeGroup(g->getGroupName());
mqttCheck.removeTopic(s->getMqtt()); for (const auto &s : g->getSensors()) {
mqttCheck.removeTopic(s->getMqtt());
mqttCheck.removeName(s->getName());
}
}
} }
bool HttpsServer::checkTopics(dl_t p) { bool HttpsServer::checkTopics(dl_t p) {
MQTTChecker& mqttCheck = MQTTChecker::getInstance(); MQTTChecker& mqttCheck = MQTTChecker::getInstance();
bool validTopics=true; bool validTopics=true;
for(const auto& g : p.configurator->getSensorGroups()) for(const auto& g : p.configurator->getSensorGroups()) {
for(const auto& s : g->getSensors()) if (!mqttCheck.checkGroup(g->getGroupName()))
if(!mqttCheck.checkTopic(s->getMqtt())) validTopics = false;
for (const auto &s : g->getSensors())
if (!mqttCheck.checkTopic(s->getMqtt()) || !mqttCheck.checkName(s->getName()))
validTopics = false; validTopics = false;
}
return validTopics; return validTopics;
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment