From f67e319ab9c7e39ef794a7dd925b697a93ae4256 Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nwpope@utu.fi> Date: Mon, 3 Jun 2019 07:42:56 +0300 Subject: [PATCH] Add events to configuable, untested --- components/common/cpp/CMakeLists.txt | 1 + .../common/cpp/include/ftl/configurable.hpp | 64 ++++++++++++++++++- components/common/cpp/src/configurable.cpp | 24 +++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 components/common/cpp/src/configurable.cpp diff --git a/components/common/cpp/CMakeLists.txt b/components/common/cpp/CMakeLists.txt index 2b99f94b2..f85d96d2c 100644 --- a/components/common/cpp/CMakeLists.txt +++ b/components/common/cpp/CMakeLists.txt @@ -1,6 +1,7 @@ set(COMMONSRC src/config.cpp src/configuration.cpp + src/configurable.cpp src/opencv_to_pcl.cpp ) diff --git a/components/common/cpp/include/ftl/configurable.hpp b/components/common/cpp/include/ftl/configurable.hpp index 71c8a5564..d14585dc8 100644 --- a/components/common/cpp/include/ftl/configurable.hpp +++ b/components/common/cpp/include/ftl/configurable.hpp @@ -6,18 +6,35 @@ #include <nlohmann/json.hpp> #include <string> #include <tuple> +#include <map> +#include <list> +#include <functional> #define REQUIRED(...) required(__func__, __VA_ARGS__) namespace ftl { +/** + * The Configurable class should be inherited by any entity that is to be + * configured using json objects. Additionally, any such object can then be + * reconfigured through changes to that underlying json object with event + * callbacks being triggered when specific changes occur. + * + * Configurables may also optionally have a URI that enables static methods + * of getting and setting configuration options. These static methods are used + * by network RPCs to enable remote reconfiguration. + */ class Configurable { public: Configurable() {} explicit Configurable(nlohmann::json &config) : config_(config) { - + if (config["uri"].is_string()) __changeURI(config["uri"].get<std::string>(), this); } + /** + * Force the JSON object to have specific properties with a specific type. + * If not, emit errors and terminate the application. + */ void required(const char *f, const std::vector<std::tuple<std::string, std::string, std::string>> &r) { bool diderror = false; for (auto i : r) { @@ -33,10 +50,55 @@ class Configurable { nlohmann::json &getConfig() { return config_; } + /** + * Get a configuration property from the json object. Returns an optional + * result which will be empty if the property does not exist or is not of + * the requested type. + */ + template <typename T> + std::optional<T> get(const std::string &name) { + try { + return config_[name].get<T>(); + } catch (...) { + return {}; + } + } + + /** + * Change a configuration property and trigger any listening event handlers + * for that property. Also triggers the global listeners. + */ + template <typename T> + void set(const std::string &name, T value) { + config_[name] = value; + _trigger(name); + } + + /** + * Add callback for whenever a specified property changes value. + * @param prop Name of property to watch + * @param callback A function object that will be called on change. + */ + void on(const std::string &prop, std::function<void(Configurable*, const std::string&)>); + protected: nlohmann::json config_; + + private: + std::map<std::string, std::list<std::function<void(Configurable*, const std::string&)>>> observers_; + + void _trigger(const std::string &name); + + static void __changeURI(const std::string &uri, Configurable *cfg); }; +/*template <> +void Configurable::set<const std::string&>(const std::string &name, const std::string &value) { + config_[name] = value; + if (name == "uri") __changeURI(value, this); + _trigger(name); +}*/ + } #endif // _FTL_CONFIGURABLE_HPP_ diff --git a/components/common/cpp/src/configurable.cpp b/components/common/cpp/src/configurable.cpp new file mode 100644 index 000000000..cea4d74e6 --- /dev/null +++ b/components/common/cpp/src/configurable.cpp @@ -0,0 +1,24 @@ +#include <ftl/configurable.hpp> + +using ftl::Configurable; +using std::string; +using std::map; +using std::list; +using std::function; + +void Configurable::_trigger(const string &name) { + auto ix = observers_.find(name); + if (ix != observers_.end()) { + for (auto &f : (*ix).second) { + try { + f(this, name); + } catch(...) { + LOG(ERROR) << "Exception in event handler for '" << name << "'"; + } + } + } +} + +void Configurable::__changeURI(const string &uri, Configurable *cfg) { + +} \ No newline at end of file -- GitLab