diff --git a/components/common/cpp/include/ftl/configurable.hpp b/components/common/cpp/include/ftl/configurable.hpp index c1f903b61df4004e458c54f243fd0014c69ff96f..59090a58521a9559e0aa398e91a8fe38ef00a7eb 100644 --- a/components/common/cpp/include/ftl/configurable.hpp +++ b/components/common/cpp/include/ftl/configurable.hpp @@ -15,6 +15,15 @@ namespace ftl { +class Configurable; + +namespace config { +struct Event { + Configurable *entity; + std::string name; +}; +} + /** * The Configurable class should be inherited by any entity that is to be * configured using json objects. Additionally, any such object can then be @@ -39,6 +48,9 @@ class Configurable { */ void required(const char *f, const std::vector<std::tuple<std::string, std::string, std::string>> &r); + /** + * Return raw JSON entity for this Configurable. + */ nlohmann::json &getConfig() { return config_; } /** @@ -68,18 +80,26 @@ class Configurable { _trigger(name); } + /** + * Create or find existing configurable object of given type from the + * given property name. Additional constructor arguments can also be + * provided. Any kind of failure results in a nullptr being returned. + */ + template <typename T, typename... ARGS> + T *create(const std::string &name, ARGS ...args); + /** * 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&)>); + void on(const std::string &prop, std::function<void(const config::Event&)>); protected: nlohmann::json config_; private: - std::map<std::string, std::list<std::function<void(Configurable*, const std::string&)>>> observers_; + std::map<std::string, std::list<std::function<void(const config::Event&)>>> observers_; void _trigger(const std::string &name); @@ -124,4 +144,9 @@ std::optional<T> ftl::Configurable::get(const std::string &name) { } } +template <typename T, typename... ARGS> +T *ftl::Configurable::create(const std::string &name, ARGS ...args) { + return ftl::config::create<T>(this, name, args...); +} + #endif // _FTL_CONFIGURABLE_HPP_ diff --git a/components/common/cpp/src/configurable.cpp b/components/common/cpp/src/configurable.cpp index d770ae6e7003a21bc4a9d15d9c523cb0f0339f84..81f9092b8e316af4fb4dc13f104b8d3b0b77af30 100644 --- a/components/common/cpp/src/configurable.cpp +++ b/components/common/cpp/src/configurable.cpp @@ -30,7 +30,7 @@ void Configurable::_trigger(const string &name) { if (ix != observers_.end()) { for (auto &f : (*ix).second) { try { - f(this, name); + f({this, name}); } catch(...) { LOG(ERROR) << "Exception in event handler for '" << name << "'"; } @@ -38,7 +38,7 @@ void Configurable::_trigger(const string &name) { } } -void Configurable::on(const string &prop, function<void(Configurable*, const string&)> f) { +void Configurable::on(const string &prop, function<void(const ftl::config::Event&)> f) { auto ix = observers_.find(prop); if (ix == observers_.end()) { observers_[prop] = {f}; diff --git a/components/common/cpp/test/configurable_unit.cpp b/components/common/cpp/test/configurable_unit.cpp index 7855438a64114825ec54c54e8bb1a9848066de08..83148e9d41196e055c95a32ab3d93217af72baec 100644 --- a/components/common/cpp/test/configurable_unit.cpp +++ b/components/common/cpp/test/configurable_unit.cpp @@ -38,7 +38,7 @@ SCENARIO( "Configurable::on()" ) { Configurable cfg(json); bool trig = false; - cfg.on("test", [&trig](Configurable *c, const string &n) { + cfg.on("test", [&trig](const ftl::config::Event &e) { trig = true; }); @@ -53,10 +53,10 @@ SCENARIO( "Configurable::on()" ) { bool trig1 = false; bool trig2 = false; - cfg.on("test", [&trig1](Configurable *c, const string &n) { + cfg.on("test", [&trig1](const ftl::config::Event &e) { trig1 = true; }); - cfg.on("test", [&trig2](Configurable *c, const string &n) { + cfg.on("test", [&trig2](const ftl::config::Event &e) { trig2 = true; });