// // Created by Netti, Alessio on 10.12.18. // #include "AnalyticsManager.h" void AnalyticsManager::clear() { for(const auto& p : _plugins) p.destroy(p.configurator); _plugins.clear(); _status = CLEAR; } bool AnalyticsManager::load(const string& path, const string& globalFile, const pluginSettings_t& pluginSettings) { //The load code is pretty much the same as in Configuration.cpp to load pusher plugins _configPath = path; _pluginSettings = pluginSettings; boost::property_tree::iptree cfg; if (_configPath != "" && _configPath[_configPath.length()-1] != '/') _configPath.append("/"); try { boost::property_tree::read_info(_configPath + globalFile, cfg); } catch (boost::property_tree::info_parser_error& e) { LOG(error) << "Error when reading analyzer plugins from global.conf: " << e.what(); return false; } BOOST_FOREACH(boost::property_tree::iptree::value_type &plugin, cfg.get_child("analyzerPlugins")) { if (boost::iequals(plugin.first, "analyzerPlugin")) { if (!plugin.second.empty()) { LOG(info) << "Loading analyzer plugin \"" << plugin.second.data() << "\"..."; std::string pluginConfig; //path to config file for plugin std::string pluginLib = "libdcdbanalyzer_" + plugin.second.data(); #if __APPLE__ pluginLib+= ".dylib"; #else pluginLib+= ".so"; #endif BOOST_FOREACH(boost::property_tree::iptree::value_type &val, plugin.second) { if (boost::iequals(val.first, "path")) { std::string iPath = val.second.data(); // If path not specified we will look up in the default lib-directories (usr/lib and friends) if (iPath != "") { if (iPath[iPath.length()-1] != '/') iPath.append("/"); pluginLib = iPath + pluginLib; } } else if (boost::iequals(val.first, "config")) { pluginConfig = val.second.data(); // If config-path not specified we will look for pluginName.conf in the global.conf directory if (pluginConfig == "") pluginConfig = _configPath + plugin.second.data() + ".conf"; } else { LOG(warning) << " Value \"" << val.first << "\" not recognized. Omitting"; } } // Open dl-code based on http://tldp.org/HOWTO/C++-dlopen/thesolution.html if (FILE *file = fopen(pluginConfig.c_str(), "r")) { fclose(file); an_dl_t dynLib; dynLib.id = plugin.second.data(); dynLib.DL = NULL; dynLib.configurator = NULL; // If plugin.conf exists, open libdcdbanalyzer_pluginName.so and read config LOG(info) << pluginConfig << " found"; dynLib.DL = dlopen(pluginLib.c_str(), RTLD_NOW); if(!dynLib.DL) { LOG(error) << "Cannot load " << dynLib.id << "-library: " << dlerror(); return false; } dlerror(); // Set dynLib an_dl_t struct, load create and destroy symbols dynLib.create = (an_create_t*) dlsym(dynLib.DL, "create"); const char* dlsym_error = dlerror(); if (dlsym_error) { LOG(error) << "Cannot load symbol create for " << dynLib.id << ": " << dlsym_error; return false; } dynLib.destroy = (an_destroy_t*) dlsym(dynLib.DL, "destroy"); dlsym_error = dlerror(); if (dlsym_error) { LOG(error) << "Cannot load symbol destroy for " << dynLib.id << ": " << dlsym_error; return false; } dynLib.configurator = dynLib.create(); dynLib.configurator->setGlobalSettings(_pluginSettings); // Read the analyzer plugin configuration if (!(dynLib.configurator->readConfig(pluginConfig))) { LOG(error) << "Plugin \"" << dynLib.id << "\" could not read configuration!"; return false; } // Returning an empty vector may indicate problems with the config file if(dynLib.configurator->getAnalyzers().size() == 0) { LOG(warning) << "Plugin \"" << dynLib.id << "\" created no analyzers!"; } //save dl-struct _plugins.push_back(dynLib); LOG(info) << "Plugin \"" << dynLib.id << "\" loaded!"; } else { LOG(info) << pluginConfig << " not found. Omitting"; } } } } _status = LOADED; return true; } bool AnalyticsManager::mqttCheck(pluginVector_t& pushers) { if(_status != LOADED) { LOG(error) << "Cannot perform MQTT check, AnalyticsManager is not loaded!"; return false; } std::set _mqttTopics; // Initializing set with topics from pusher sensors for(const auto& p : pushers) for(const auto& g : p.configurator->getSensorGroups()) for(const auto& s : g->getSensors()) _mqttTopics.insert(s->getMqtt()); // Check if an MQTT-suffix was assigned twice and if it is correctly formatted for(const auto& p : _plugins) for(const auto& a : p.configurator->getAnalyzers()) for(const auto& u : a->getUnits()) for(const auto& o: u->getBaseOutputs()) { std::string str(o->getMqtt()); str.erase(std::remove(str.begin(), str.end(), '/'), str.end()); if (str.length() != 28) { LOG(error) << "MQTT-Topic \"" << o->getMqtt() << "\" contains " << str.length() << " hex characters, not 28 as required!"; return false; } auto returnIt = _mqttTopics.insert(str); if (!returnIt.second) { LOG(error) << "MQTT-Topic \"" << o->getMqtt() << "\" used twice!"; return false; } } _mqttTopics.clear(); return true; } bool AnalyticsManager::init(boost::asio::io_service& io, const string& plugin) { if(_status != LOADED) { LOG(error) << "Cannot init, AnalyticsManager is not loaded!"; return false; } for (const auto &p : _plugins) //Actions always affect either one or all plugins, and always all analyzers within said plugin if(plugin=="" || plugin==p.id) { LOG(info) << "Init \"" << p.id << "\" data analytics plugin"; for (const auto &a : p.configurator->getAnalyzers()) a->init(io); } return true; } bool AnalyticsManager::reload(boost::asio::io_service& io, const string& plugin) { if(_status != LOADED) { LOG(error) << "Cannot reload, AnalyticsManager is not loaded!"; return false; } for (const auto &p : _plugins) if(plugin=="" || plugin==p.id) { LOG(info) << "Reload \"" << p.id << "\" data analytics plugin"; if( !p.configurator->reReadConfig() ) return false; for (const auto &a : p.configurator->getAnalyzers()) a->init(io); } return true; } bool AnalyticsManager::start(const string& plugin) { if(_status != LOADED) { LOG(error) << "Cannot start, AnalyticsManager is not loaded!"; return false; } for (const auto &p : _plugins) if(plugin=="" || plugin==p.id) { LOG(info) << "Start \"" << p.id << "\" data analytics plugin"; for (const auto &a : p.configurator->getAnalyzers()) a->start(); } return true; } bool AnalyticsManager::stop(const string& plugin) { if(_status != LOADED) { LOG(error) << "Cannot stop, AnalyticsManager is not loaded!"; return false; } for (const auto &p : _plugins) if(plugin=="" || plugin==p.id) { LOG(info) << "Stop \"" << p.id << "\" data analytics plugin"; for (const auto &a : p.configurator->getAnalyzers()) a->stop(); } return true; } string AnalyticsManager::forwardREST(const string& command) { if(_status != LOADED) { LOG(error) << "Cannot forward REST command, AnalyticsManager is not loaded!"; return ""; } //TODO: implement REST interface integration return ""; }