// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include #include #include #include #if defined(DEBUG_SETTINGS_DB) and DEBUG_SETTINGS_DB == 1 #include #define log_debug(...) LOG_DEBUG(__VA_ARGS__); #else #define log_debug(...) #endif namespace settings { Settings::~Settings() { deinit(); } void Settings::init(const service::ServiceProxy &interface) { this->interface = SettingsProxy(interface); this->interface.init([this](const EntryPath &p, const std::string &v) { this->handleVariableChanged(p, v); }); if (not interface.isValid()) { throw std::invalid_argument("need the interface!"); } } void Settings::deinit() { if (interface.isValid()) { interface.deinit(); for (const auto &callbacks : cbValues) { log_debug("[Settings::unregisterValueChange] %s", callbacks.first.to_string().c_str()); interface.unregisterValueChange(callbacks.first); } } cbValues.clear(); } void Settings::handleVariableChanged(const EntryPath &path, const std::string &value) { log_debug("handleVariableChanged: (key=%s)", path.to_string().c_str()); if (auto callbacks = cbValues.find(path); std::end(cbValues) != callbacks) { // we cant get by const ref here - as user can remove this callback from cbValues map which would cause use // after free auto [cb, cbWithName] = callbacks->second; if (nullptr != cb) { cb(value); } if (nullptr != cbWithName) { cbWithName(path.variable, value); } } } void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb, SettingsScope scope) { auto path = EntryPath{.service = interface.ownerName(), .variable = variableName, .scope = scope}; if (auto callbacks = cbValues.find(path); std::end(cbValues) != callbacks && nullptr != callbacks->second.first) { log_debug("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str()); } cbValues[path].first = std::move(cb); interface.registerValueChange(std::move(path)); } void Settings::registerValueChange(const std::string &variableName, ValueChangedCallbackWithName cb, SettingsScope scope) { auto path = EntryPath{.service = interface.ownerName(), .variable = variableName, .scope = scope}; if (auto callbacks = cbValues.find(path); cbValues.end() != callbacks && nullptr != callbacks->second.second) { log_debug("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str()); } cbValues[path].second = std::move(cb); interface.registerValueChange(std::move(path)); } void Settings::unregisterValueChange(const std::string &variableName, SettingsScope scope) { auto path = EntryPath{.service = interface.ownerName(), .variable = variableName, .scope = scope}; if (auto callbacks = cbValues.find(path); cbValues.end() != callbacks) { log_debug("[Settings::unregisterValueChange] %s", path.to_string().c_str()); cbValues.erase(callbacks); } interface.unregisterValueChange(std::move(path)); } void Settings::setValue(const std::string &variableName, const std::string &variableValue, SettingsScope scope) { auto path = EntryPath{.service = interface.ownerName(), .variable = variableName, .scope = scope}; interface.setValue(path, variableValue); getCache()->setValue(path, variableValue); } std::string Settings::getValue(const std::string &variableName, SettingsScope scope) { return getCache()->getValue({.service = interface.ownerName(), .variable = variableName, .scope = scope}); } SettingsCache *Settings::getCache() { return SettingsCache::getInstance(); } Settings::Settings(const service::ServiceProxy &interface) { init(interface); } } // namespace settings