diff options
Diffstat (limited to 'src/core/module')
-rw-r--r-- | src/core/module/Event.cpp | 139 | ||||
-rw-r--r-- | src/core/module/Event.h | 95 | ||||
-rw-r--r-- | src/core/module/GlobalModuleContext.cpp | 377 | ||||
-rw-r--r-- | src/core/module/GlobalModuleContext.h | 88 | ||||
-rw-r--r-- | src/core/module/GlobalRegisterTable.cpp | 167 | ||||
-rw-r--r-- | src/core/module/GlobalRegisterTable.h | 66 | ||||
-rw-r--r-- | src/core/module/GpgFrontendModuleSystem.h | 34 | ||||
-rw-r--r-- | src/core/module/Module.cpp | 106 | ||||
-rw-r--r-- | src/core/module/Module.h | 80 | ||||
-rw-r--r-- | src/core/module/ModuleManager.cpp | 184 | ||||
-rw-r--r-- | src/core/module/ModuleManager.h | 179 |
11 files changed, 1515 insertions, 0 deletions
diff --git a/src/core/module/Event.cpp b/src/core/module/Event.cpp new file mode 100644 index 00000000..fab26453 --- /dev/null +++ b/src/core/module/Event.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "Event.h" + +namespace GpgFrontend::Module { + +class Event::Impl { + public: + Impl(QString event_id, std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : event_identifier_(std::move(event_id)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()) { + for (const auto& param : params) { + AddParameter(param); + } + GF_CORE_LOG_DEBUG("create event {}", event_identifier_); + } + + auto operator[](const QString& key) const -> std::optional<ParameterValue> { + auto it_data = data_.find(key); + if (it_data != data_.end()) { + return it_data->second; + } + return std::nullopt; + } + + auto operator==(const Event& other) const -> bool { + return event_identifier_ == other.p_->event_identifier_; + } + + auto operator!=(const Event& other) const -> bool { + return !(*this == other); + } + + auto operator<(const Event& other) const -> bool { + return this->event_identifier_ < other.p_->event_identifier_; + } + + explicit operator QString() const { return event_identifier_; } + + auto GetIdentifier() -> EventIdentifier { return event_identifier_; } + + void AddParameter(const QString& key, const ParameterValue& value) { + data_[key] = value; + } + + void AddParameter(const ParameterInitializer& param) { + AddParameter(param.key, param.value); + } + + void ExecuteCallback(ListenerIdentifier listener_id, + const DataObjectPtr& data_object) { + GF_CORE_LOG_DEBUG("try to execute callback for event {} with listener {}", + event_identifier_, listener_id); + if (callback_) { + GF_CORE_LOG_DEBUG("executing callback for event {} with listener {}", + event_identifier_, listener_id); + if (!QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, event_identifier = event_identifier_, + listener_id, data_object]() { + callback(event_identifier, listener_id, data_object); + })) { + GF_CORE_LOG_ERROR( + "failed to invoke callback for event {} with listener {}", + event_identifier_, listener_id); + } + } + } + + private: + EventIdentifier event_identifier_; + std::map<QString, ParameterValue> data_; + EventCallback callback_; + QThread* callback_thread_ = nullptr; ///< +}; + +Event::Event(const QString& event_id, + std::initializer_list<ParameterInitializer> params, + EventCallback callback) + : p_(SecureCreateUniqueObject<Impl>(event_id, params, + std::move(callback))) {} + +Event::~Event() = default; + +auto Event::Event::operator==(const Event& other) const -> bool { + return this->p_ == other.p_; +} + +auto Event::Event::operator!=(const Event& other) const -> bool { + return this->p_ != other.p_; +} + +auto Event::Event::operator<(const Event& other) const -> bool { + return this->p_ < other.p_; +} + +Event::Event::operator QString() const { return static_cast<QString>(*p_); } + +auto Event::Event::GetIdentifier() -> EventIdentifier { + return p_->GetIdentifier(); +} + +void Event::AddParameter(const QString& key, const ParameterValue& value) { + p_->AddParameter(key, value); +} + +void Event::ExecuteCallback(ListenerIdentifier l_id, DataObjectPtr d_o) { + p_->ExecuteCallback(std::move(l_id), d_o); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Event.h b/src/core/module/Event.h new file mode 100644 index 00000000..92268216 --- /dev/null +++ b/src/core/module/Event.h @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <any> +#include <functional> +#include <optional> + +#include "core/GpgFrontendCore.h" +#include "core/model/DataObject.h" + +namespace GpgFrontend::Module { + +class Event; + +using EventRefrernce = std::shared_ptr<Event>; +using EventIdentifier = QString; +using Evnets = std::vector<Event>; + +class GPGFRONTEND_CORE_EXPORT Event { + public: + using ParameterValue = std::any; + using EventIdentifier = QString; + using ListenerIdentifier = QString; + using EventCallback = + std::function<void(EventIdentifier, ListenerIdentifier, DataObjectPtr)>; + struct ParameterInitializer { + QString key; + ParameterValue value; + }; + + explicit Event(const QString&, + std::initializer_list<ParameterInitializer> = {}, + EventCallback = nullptr); + + ~Event(); + + auto operator[](const QString& key) const -> std::optional<ParameterValue>; + + auto operator==(const Event& other) const -> bool; + + auto operator!=(const Event& other) const -> bool; + + auto operator<(const Event& other) const -> bool; + + auto operator<=(const Event& other) const -> bool; + + explicit operator QString() const; + + auto GetIdentifier() -> EventIdentifier; + + void AddParameter(const QString& key, const ParameterValue& value); + + void ExecuteCallback(ListenerIdentifier, DataObjectPtr); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename... Args> +auto MakeEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb) -> EventRefrernce { + std::initializer_list<Event::ParameterInitializer> params = { + Event::ParameterInitializer{std::forward<Args>(args)}...}; + return GpgFrontend::SecureCreateSharedObject<Event>(event_id, params, e_cb); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalModuleContext.cpp b/src/core/module/GlobalModuleContext.cpp new file mode 100644 index 00000000..9bc4f06b --- /dev/null +++ b/src/core/module/GlobalModuleContext.cpp @@ -0,0 +1,377 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GlobalModuleContext.h" + +#include <set> +#include <unordered_map> +#include <unordered_set> + +#include "core/module/Event.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "model/DataObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext::Impl { + public: + explicit Impl() { + // Initialize acquired channels with default values. + acquired_channel_.insert(kGpgFrontendDefaultChannel); + acquired_channel_.insert(kGpgFrontendNonAsciiChannel); + } + + auto GetChannel(ModuleRawPtr module) -> int { + // Search for the module in the register table. + auto module_info_opt = + search_module_register_table(module->GetModuleIdentifier()); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR( + "cannot find module id {} at register table, fallbacking to " + "default " + "channel", + module->GetModuleIdentifier()); + return GetDefaultChannel(module); + } + + auto module_info = module_info_opt.value(); + return module_info->channel; + } + + static auto GetDefaultChannel(ModuleRawPtr) -> int { + return kGpgFrontendDefaultChannel; + } + + auto GetTaskRunner(ModuleRawPtr /*module*/) -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetTaskRunner(ModuleIdentifier /*module_id*/) + -> std::optional<TaskRunnerPtr> { + return Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + } + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr> { + return default_task_runner_; + } + + auto RegisterModule(const ModulePtr& module) -> bool { + GF_CORE_LOG_DEBUG("attempting to register module: {}", + module->GetModuleIdentifier()); + // Check if the module is null or already registered. + if (module == nullptr || + module_register_table_.find(module->GetModuleIdentifier()) != + module_register_table_.end()) { + GF_CORE_LOG_ERROR( + "module is null or have already registered this module"); + return false; + } + + if (!module->Register()) { + GF_CORE_LOG_ERROR("register module {} failed", + module->GetModuleIdentifier()); + return false; + } + + auto register_info = + GpgFrontend::SecureCreateSharedObject<ModuleRegisterInfo>(); + register_info->module = module; + register_info->channel = acquire_new_unique_channel(); + + // move module to its task runner' thread + register_info->module->setParent(nullptr); + register_info->module->moveToThread( + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->GetThread()); + + // Register the module with its identifier. + module_register_table_[module->GetModuleIdentifier()] = register_info; + + GF_CORE_LOG_DEBUG("successfully registered module: {}", + module->GetModuleIdentifier()); + return true; + } + + auto ActiveModule(ModuleIdentifier module_id) -> bool { + GF_CORE_LOG_DEBUG("attempting to activate module: {}", module_id); + + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + + // try to get module from module info + auto module = module_info->module; + if (module == nullptr) { + GF_CORE_LOG_ERROR( + "module id {} at register table is releated to a null module", + module_id); + return false; + } + + // Activate the module if it is not already active. + if (!module_info->activate) { + module->Active(); + module_info->activate = true; + } + + GF_CORE_LOG_DEBUG("module activation status: {}", module_info->activate); + return module_info->activate; + } + + auto ListenEvent(ModuleIdentifier module_id, EventIdentifier event) -> bool { + GF_CORE_LOG_DEBUG("module: {} is attempting to listen to event {}", + module_id, event); + // Check if the event exists, if not, create it. + auto met_it = module_events_table_.find(event); + if (met_it == module_events_table_.end()) { + module_events_table_[event] = std::unordered_set<ModuleIdentifier>(); + met_it = module_events_table_.find(event); + GF_CORE_LOG_DEBUG("new event {} of module system created", event); + } + + auto& listeners_set = met_it->second; + // Add the listener (module) to the event. + auto listener_it = listeners_set.find(module_id); + if (listener_it == listeners_set.end()) { + listeners_set.insert(module_id); + } + return true; + } + + auto DeactivateModule(ModuleIdentifier module_id) -> bool { + // Search for the module in the register table. + auto module_info_opt = search_module_register_table(module_id); + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + module_id); + return false; + } + + auto module_info = module_info_opt.value(); + // Activate the module if it is not already deactive. + if (!module_info->activate && module_info->module->Deactive()) { + module_info->activate = false; + } + + return !module_info->activate; + } + + auto TriggerEvent(const EventRefrernce& event) -> bool { + auto event_id = event->GetIdentifier(); + GF_CORE_LOG_DEBUG("attempting to trigger event: {}", event_id); + + // Find the set of listeners associated with the given event in the table + auto met_it = module_events_table_.find(event_id); + if (met_it == module_events_table_.end()) { + // Log a warning if the event is not registered and nobody is listening + GF_CORE_LOG_WARN( + "event {} is not listening by anyone and not registered as well", + event_id); + return false; + } + + // Retrieve the set of listeners for this event + auto& listeners_set = met_it->second; + + // Check if the set of listeners is empty + if (listeners_set.empty()) { + // Log a warning if nobody is listening to this event + GF_CORE_LOG_WARN("event {} is not listening by anyone", + event->GetIdentifier()); + return false; + } + + // Log the number of listeners for this event + GF_CORE_LOG_DEBUG("event {}'s current listeners size: {}", + event->GetIdentifier(), listeners_set.size()); + + // Iterate through each listener and execute the corresponding module + for (const auto& listener_module_id : listeners_set) { + // Search for the module's information in the registration table + auto module_info_opt = search_module_register_table(listener_module_id); + + // Log an error if the module is not found in the registration table + if (!module_info_opt.has_value()) { + GF_CORE_LOG_ERROR("cannot find module id {} at register table", + listener_module_id); + continue; + } + + // Retrieve the module's information + auto module_info = module_info_opt.value(); + auto module = module_info->module; + + GF_CORE_LOG_DEBUG( + "module {} is listening to event {}, activate state: {}", + module_info->module->GetModuleIdentifier(), event->GetIdentifier(), + module_info->activate); + + // Check if the module is activated + if (!module_info->activate) continue; + + Thread::Task::TaskRunnable const exec_runnerable = + [module, event](DataObjectPtr) -> int { return module->Exec(event); }; + + Thread::Task::TaskCallback const exec_callback = + [listener_module_id, event_id](int code, DataObjectPtr) { + if (code < 0) { + // Log an error if the module execution fails + GF_CORE_LOG_ERROR( + "module {} execution failed of event {}: exec return code {}", + listener_module_id, event_id, code); + } + }; + + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->PostTask(new Thread::Task(exec_runnerable, + QString("event/%1/module/exec/%2") + .arg(event_id) + .arg(listener_module_id), + nullptr, exec_callback)); + } + + // Return true to indicate successful execution of all modules + return true; + } + + auto IsModuleActivated(const ModuleIdentifier& m_id) const -> bool { + auto m = search_module_register_table(m_id); + return m.has_value() && m->get()->activate; + } + + private: + struct ModuleRegisterInfo { + int channel; + ModulePtr module; + bool activate; + }; + + using ModuleRegisterInfoPtr = std::shared_ptr<ModuleRegisterInfo>; + + std::unordered_map<ModuleIdentifier, ModuleRegisterInfoPtr> + module_register_table_; + std::map<EventIdentifier, std::unordered_set<ModuleIdentifier>> + module_events_table_; + + std::set<int> acquired_channel_; + TaskRunnerPtr default_task_runner_; + + auto acquire_new_unique_channel() -> int { + int random_channel = QRandomGenerator::global()->bounded(65535); + // Ensure the acquired channel is unique. + while (acquired_channel_.find(random_channel) != acquired_channel_.end()) { + random_channel = QRandomGenerator::global()->bounded(65535); + } + + // Add the acquired channel to the set. + acquired_channel_.insert(random_channel); + return random_channel; + } + + // Function to search for a module in the register table. + auto search_module_register_table(const ModuleIdentifier& identifier) const + -> std::optional<ModuleRegisterInfoPtr> { + auto mrt_it = module_register_table_.find(identifier); + if (mrt_it == module_register_table_.end()) { + return std::nullopt; + } + return mrt_it->second; + } +}; + +// Constructor for GlobalModuleContext, takes a TaskRunnerPtr as an argument. +GlobalModuleContext::GlobalModuleContext() + : p_(SecureCreateUniqueObject<Impl>()) {} + +GlobalModuleContext::~GlobalModuleContext() = default; + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleRawPtr module) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(module); +} + +// Function to get the task runner associated with a module. +auto GlobalModuleContext::GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(module_id)); +} + +// Function to get the global task runner. +auto GlobalModuleContext::GetGlobalTaskRunner() + -> std::optional<TaskRunnerPtr> { + return p_->GetGlobalTaskRunner(); +} + +auto GlobalModuleContext::RegisterModule(ModulePtr module) -> bool { + return p_->RegisterModule(std::move(module)); +} + +auto GlobalModuleContext::ActiveModule(ModuleIdentifier module_id) -> bool { + return p_->ActiveModule(std::move(module_id)); +} + +auto GlobalModuleContext::ListenEvent(ModuleIdentifier module_id, + EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(module_id), std::move(event)); +} + +auto GlobalModuleContext::DeactivateModule(ModuleIdentifier module_id) -> bool { + return p_->DeactivateModule(std::move(module_id)); +} + +auto GlobalModuleContext::TriggerEvent(EventRefrernce event) -> bool { + return p_->TriggerEvent(std::move(event)); +} + +auto GlobalModuleContext::GetChannel(ModuleRawPtr module) -> int { + return p_->GetChannel(module); +} + +auto GlobalModuleContext::GetDefaultChannel(ModuleRawPtr channel) -> int { + return GlobalModuleContext::Impl::GetDefaultChannel(channel); +} + +auto GlobalModuleContext::IsModuleActivated(ModuleIdentifier m_id) -> bool { + return p_->IsModuleActivated(std::move(m_id)); +} + +} // namespace GpgFrontend::Module diff --git a/src/core/module/GlobalModuleContext.h b/src/core/module/GlobalModuleContext.h new file mode 100644 index 00000000..1c971bb5 --- /dev/null +++ b/src/core/module/GlobalModuleContext.h @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <optional> + +#include "core/module/Event.h" +#include "core/thread/TaskRunner.h" +#include "function/SecureMemoryAllocator.h" +#include "module/GlobalRegisterTable.h" + +namespace GpgFrontend::Module { + +class GlobalModuleContext; +class GlobalRegisterTable; + +class Module; +class ModuleManager; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleRawPtr = Module*; + +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using GRTPtr = std::shared_ptr<GlobalRegisterTable>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT GlobalModuleContext : public QObject { + Q_OBJECT + public: + explicit GlobalModuleContext(); + + ~GlobalModuleContext() override; + + auto GetChannel(ModuleRawPtr) -> int; + + static auto GetDefaultChannel(ModuleRawPtr) -> int; + + auto GetTaskRunner(ModuleRawPtr) -> std::optional<TaskRunnerPtr>; + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto GetGlobalTaskRunner() -> std::optional<TaskRunnerPtr>; + + auto RegisterModule(ModulePtr) -> bool; + + auto ActiveModule(ModuleIdentifier) -> bool; + + auto DeactivateModule(ModuleIdentifier) -> bool; + + auto ListenEvent(ModuleIdentifier, EventIdentifier) -> bool; + + auto TriggerEvent(EventRefrernce) -> bool; + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.cpp b/src/core/module/GlobalRegisterTable.cpp new file mode 100644 index 00000000..c16eba37 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.cpp @@ -0,0 +1,167 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GlobalRegisterTable.h" + +#include <any> +#include <optional> +#include <shared_mutex> +#include <sstream> +#include <unordered_map> +#include <vector> + +#include "function/SecureMemoryAllocator.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class GlobalRegisterTable::Impl { + public: + struct RTNode { + std::optional<std::any> value = std::nullopt; + std::unordered_map<QString, SecureUniquePtr<RTNode>> children; + int version = 0; + const std::type_info* type = nullptr; + }; + + explicit Impl(GlobalRegisterTable* parent) : parent_(parent) {} + + auto PublishKV(const Namespace& n, const Key& k, std::any v) -> bool { + QStringList const segments = k.split('.'); + int version = 0; + + { + std::unique_lock lock(lock_); + auto& root_rt_node = + global_register_table_.emplace(n, SecureCreateUniqueObject<RTNode>()) + .first->second; + + RTNode* current = root_rt_node.get(); + for (const QString& segment : segments) { + current = current->children + .emplace(segment, SecureCreateUniqueObject<RTNode>()) + .first->second.get(); + } + + current->value = v; + current->type = &v.type(); + version = ++current->version; + } + + emit parent_->SignalPublish(n, k, version, v); + return true; + } + + auto LookupKV(const Namespace& n, const Key& k) -> std::optional<std::any> { + QStringList const segments = k.split('.'); + + std::optional<std::any> rtn = std::nullopt; + { + std::shared_lock const lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return std::nullopt; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return std::nullopt; + current = it->second.get(); + } + rtn = current->value; + } + return rtn; + } + + auto ListChildKeys(const Namespace& n, const Key& k) -> std::vector<Key> { + QStringList const segments = k.split('.'); + + std::vector<Key> rtn; + { + std::shared_lock lock(lock_); + auto it = global_register_table_.find(n); + if (it == global_register_table_.end()) return {}; + + RTNode* current = it->second.get(); + for (const QString& segment : segments) { + auto it = current->children.find(segment); + if (it == current->children.end()) return {}; + current = it->second.get(); + } + + for (auto& it : current->children) { + rtn.emplace_back(it.first); + } + } + return rtn; + } + + auto ListenPublish(QObject* o, const Namespace& n, const Key& k, LPCallback c) + -> bool { + if (o == nullptr) return false; + return QObject::connect(parent_, &GlobalRegisterTable::SignalPublish, o, + [n, k, c](const Namespace& pn, const Key& pk, + int ver, std::any value) { + if (pn == n && pk == k) { + c(pn, pk, ver, std::move(value)); + } + }) == nullptr; + } + + private: + using Table = std::map<Namespace, SecureUniquePtr<RTNode>>; + std::shared_mutex lock_; + GlobalRegisterTable* parent_; + + Table global_register_table_; +}; + +GlobalRegisterTable::GlobalRegisterTable() + : p_(SecureCreateUniqueObject<Impl>(this)) {} + +GlobalRegisterTable::~GlobalRegisterTable() = default; + +auto GlobalRegisterTable::PublishKV(Namespace n, Key k, std::any v) -> bool { + return p_->PublishKV(n, k, v); +} + +auto GlobalRegisterTable::LookupKV(Namespace n, Key v) + -> std::optional<std::any> { + return p_->LookupKV(n, v); +} + +auto GlobalRegisterTable::ListenPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto GlobalRegisterTable::ListChildKeys(Namespace n, Key k) + -> std::vector<Key> { + return p_->ListChildKeys(n, k); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GlobalRegisterTable.h b/src/core/module/GlobalRegisterTable.h new file mode 100644 index 00000000..db68c888 --- /dev/null +++ b/src/core/module/GlobalRegisterTable.h @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <any> +#include <functional> +#include <optional> + +#include "function/SecureMemoryAllocator.h" + +namespace GpgFrontend::Module { + +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GlobalRegisterTable : public QObject { + Q_OBJECT + public: + GlobalRegisterTable(); + + ~GlobalRegisterTable() override; + + auto PublishKV(Namespace, Key, std::any) -> bool; + + auto LookupKV(Namespace, Key) -> std::optional<std::any>; + + auto ListenPublish(QObject *, Namespace, Key, LPCallback) -> bool; + + auto ListChildKeys(Namespace n, Key k) -> std::vector<Key>; + + signals: + void SignalPublish(Namespace, Key, int, std::any); + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/GpgFrontendModuleSystem.h b/src/core/module/GpgFrontendModuleSystem.h new file mode 100644 index 00000000..903aec69 --- /dev/null +++ b/src/core/module/GpgFrontendModuleSystem.h @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <core/GpgFrontendCore.h> +#include <core/module/Event.h> +#include <core/module/Module.h> +#include <core/module/ModuleManager.h>
\ No newline at end of file diff --git a/src/core/module/Module.cpp b/src/core/module/Module.cpp new file mode 100644 index 00000000..9076dc2c --- /dev/null +++ b/src/core/module/Module.cpp @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "Module.h" + +#include "core/module/GlobalModuleContext.h" + +namespace GpgFrontend::Module { + +class Module::Impl { + public: + friend class GlobalModuleContext; + + using ExecCallback = std::function<void(int)>; + + Impl(ModuleRawPtr m_ptr, ModuleIdentifier id, ModuleVersion version, + ModuleMetaData meta_data) + : m_ptr_(m_ptr), + identifier_(std::move(id)), + version_(std::move(version)), + meta_data_(std::move(meta_data)) {} + + auto GetChannel() -> int { return get_gpc()->GetChannel(m_ptr_); } + + auto GetDefaultChannel() -> int { + return GlobalModuleContext::GetDefaultChannel(m_ptr_); + } + + auto GetTaskRunner() -> std::optional<TaskRunnerPtr> { + return get_gpc()->GetTaskRunner(m_ptr_); + } + + auto ListenEvent(EventIdentifier event) -> bool { + return get_gpc()->ListenEvent(GetModuleIdentifier(), std::move(event)); + } + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier { + return identifier_; + } + + void SetGPC(GlobalModuleContext* gpc) { gpc_ = gpc; } + + private: + GlobalModuleContext* gpc_{}; + Module* m_ptr_; + const ModuleIdentifier identifier_; + const ModuleVersion version_; + const ModuleMetaData meta_data_; + + auto get_gpc() -> GlobalModuleContext* { + if (gpc_ == nullptr) { + throw std::runtime_error("module is not registered by module manager"); + } + return gpc_; + } +}; + +Module::Module(ModuleIdentifier id, ModuleVersion version, + const ModuleMetaData& meta_data) + : p_(SecureCreateUniqueObject<Impl>(this, id, version, meta_data)) {} + +Module::~Module() = default; + +auto Module::getChannel() -> int { return p_->GetChannel(); } + +auto Module::getDefaultChannel() -> int { return p_->GetDefaultChannel(); } + +auto Module::getTaskRunner() -> TaskRunnerPtr { + return p_->GetTaskRunner().value_or(nullptr); +} + +auto Module::listenEvent(EventIdentifier event) -> bool { + return p_->ListenEvent(std::move(event)); +} + +auto Module::GetModuleIdentifier() const -> ModuleIdentifier { + return p_->GetModuleIdentifier(); +} + +void Module::SetGPC(GlobalModuleContext* gpc) { p_->SetGPC(gpc); } +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/Module.h b/src/core/module/Module.h new file mode 100644 index 00000000..2a5b54e7 --- /dev/null +++ b/src/core/module/Module.h @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/module/Event.h" +#include "core/thread/TaskRunner.h" + +namespace GpgFrontend::Module { + +class Module; +class GlobalModuleContext; +class ModuleManager; + +using ModuleIdentifier = QString; +using ModuleVersion = QString; +using ModuleMetaData = std::map<QString, QString>; +using ModulePtr = std::shared_ptr<Module>; + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class GPGFRONTEND_CORE_EXPORT Module : public QObject { + Q_OBJECT + public: + Module(ModuleIdentifier, ModuleVersion, const ModuleMetaData&); + + ~Module(); + + virtual auto Register() -> bool = 0; + + virtual auto Active() -> bool = 0; + + virtual auto Exec(EventRefrernce) -> int = 0; + + virtual auto Deactive() -> bool = 0; + + [[nodiscard]] auto GetModuleIdentifier() const -> ModuleIdentifier; + + void SetGPC(GlobalModuleContext*); + + protected: + auto getChannel() -> int; + + auto getDefaultChannel() -> int; + + auto getTaskRunner() -> TaskRunnerPtr; + + auto listenEvent(EventIdentifier) -> bool; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp new file mode 100644 index 00000000..83e7c1ff --- /dev/null +++ b/src/core/module/ModuleManager.cpp @@ -0,0 +1,184 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "ModuleManager.h" + +#include <memory> + +#include "GpgConstants.h" +#include "core/module/GlobalModuleContext.h" +#include "core/module/GlobalRegisterTable.h" +#include "core/module/Module.h" +#include "core/thread/Task.h" +#include "function/SecureMemoryAllocator.h" +#include "function/basic/GpgFunctionObject.h" +#include "thread/TaskRunnerGetter.h" +#include "utils/MemoryUtils.h" + +namespace GpgFrontend::Module { + +class ModuleManager::Impl { + public: + Impl() + : gmc_(GpgFrontend::SecureCreateUniqueObject<GlobalModuleContext>()), + grt_(GpgFrontend::SecureCreateUniqueObject<GlobalRegisterTable>()) {} + + ~Impl() = default; + + void RegisterModule(const ModulePtr& module) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](GpgFrontend::DataObjectPtr) -> int { + module->SetGPC(gmc_.get()); + gmc_->RegisterModule(module); + return 0; + }, + __func__, nullptr)); + } + + void TriggerEvent(const EventRefrernce& event) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->TriggerEvent(event); + return 0; + }, + __func__, nullptr)); + } + + void ActiveModule(const ModuleIdentifier& identifier) { + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + ->PostTask(new Thread::Task( + [=](const GpgFrontend::DataObjectPtr&) -> int { + gmc_->ActiveModule(identifier); + return 0; + }, + __func__, nullptr)); + } + + auto GetTaskRunner(ModuleIdentifier module_id) + -> std::optional<TaskRunnerPtr> { + return gmc_->GetTaskRunner(std::move(module_id)); + } + + auto UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return grt_->PublishKV(n, k, v); + } + + auto RetrieveRTValue(Namespace n, Key k) -> std::optional<std::any> { + return grt_->LookupKV(n, k); + } + + auto ListenPublish(QObject* o, Namespace n, Key k, LPCallback c) -> bool { + return grt_->ListenPublish(o, n, k, c); + } + + auto ListRTChildKeys(const QString& n, const QString& k) -> std::vector<Key> { + return grt_->ListChildKeys(n, k); + } + + auto IsModuleActivated(ModuleIdentifier id) -> bool { + return gmc_->IsModuleActivated(id); + } + + private: + static ModuleMangerPtr global_module_manager; + SecureUniquePtr<GlobalModuleContext> gmc_; + SecureUniquePtr<GlobalRegisterTable> grt_; +}; + +auto IsModuleAcivate(ModuleIdentifier id) -> bool { + return ModuleManager::GetInstance().IsModuleActivated(id); +} + +auto UpsertRTValue(const QString& namespace_, const QString& key, + const std::any& value) -> bool { + return ModuleManager::GetInstance().UpsertRTValue(namespace_, key, + std::any(value)); +} + +auto ListenRTPublishEvent(QObject* o, Namespace n, Key k, LPCallback c) + -> bool { + return ModuleManager::GetInstance().ListenRTPublish(o, n, k, c); +} + +auto ListRTChildKeys(const QString& namespace_, const QString& key) + -> std::vector<Key> { + return ModuleManager::GetInstance().ListRTChildKeys(namespace_, key); +} + +ModuleManager::ModuleManager(int channel) + : SingletonFunctionObject<ModuleManager>(channel), + p_(SecureCreateUniqueObject<Impl>()) {} + +ModuleManager::~ModuleManager() = default; + +void ModuleManager::RegisterModule(ModulePtr module) { + return p_->RegisterModule(module); +} + +void ModuleManager::TriggerEvent(EventRefrernce event) { + return p_->TriggerEvent(event); +} + +void ModuleManager::ActiveModule(ModuleIdentifier id) { + return p_->ActiveModule(id); +} + +auto ModuleManager::GetTaskRunner(ModuleIdentifier id) + -> std::optional<TaskRunnerPtr> { + return p_->GetTaskRunner(std::move(id)); +} + +auto ModuleManager::UpsertRTValue(Namespace n, Key k, std::any v) -> bool { + return p_->UpsertRTValue(n, k, v); +} + +auto ModuleManager::RetrieveRTValue(Namespace n, Key k) + -> std::optional<std::any> { + return p_->RetrieveRTValue(n, k); +} + +auto ModuleManager::ListenRTPublish(QObject* o, Namespace n, Key k, + LPCallback c) -> bool { + return p_->ListenPublish(o, n, k, c); +} + +auto ModuleManager::ListRTChildKeys(const QString& n, const QString& k) + -> std::vector<Key> { + return p_->ListRTChildKeys(n, k); +} + +auto ModuleManager::IsModuleActivated(ModuleIdentifier id) -> bool { + return p_->IsModuleActivated(id); +} + +} // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h new file mode 100644 index 00000000..93b89e95 --- /dev/null +++ b/src/core/module/ModuleManager.h @@ -0,0 +1,179 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <mutex> +#include <vector> + +#include "core/function/SecureMemoryAllocator.h" +#include "core/function/basic/GpgFunctionObject.h" +#include "core/module/Event.h" +#include "core/utils/MemoryUtils.h" + +namespace GpgFrontend::Thread { +class TaskRunner; +} + +namespace GpgFrontend::Module { + +using TaskRunnerPtr = std::shared_ptr<Thread::TaskRunner>; + +class Event; +class Module; +class GlobalModuleContext; +class ModuleManager; + +using EventRefrernce = std::shared_ptr<Event>; +using ModuleIdentifier = QString; +using ModulePtr = std::shared_ptr<Module>; +using ModuleMangerPtr = std::shared_ptr<ModuleManager>; +using GMCPtr = std::shared_ptr<GlobalModuleContext>; +using Namespace = QString; +using Key = QString; +using LPCallback = std::function<void(Namespace, Key, int, std::any)>; + +class GPGFRONTEND_CORE_EXPORT ModuleManager + : public SingletonFunctionObject<ModuleManager> { + public: + explicit ModuleManager(int channel); + + virtual ~ModuleManager() override; + + void RegisterModule(ModulePtr); + + auto IsModuleActivated(ModuleIdentifier) -> bool; + + void TriggerEvent(EventRefrernce); + + void ActiveModule(ModuleIdentifier); + + void DeactiveModule(ModuleIdentifier); + + auto GetTaskRunner(ModuleIdentifier) -> std::optional<TaskRunnerPtr>; + + auto UpsertRTValue(Namespace, Key, std::any) -> bool; + + auto RetrieveRTValue(Namespace, Key) -> std::optional<std::any>; + + auto ListenRTPublish(QObject*, Namespace, Key, LPCallback) -> bool; + + auto ListRTChildKeys(const QString&, const QString&) -> std::vector<Key>; + + private: + class Impl; + SecureUniquePtr<Impl> p_; +}; + +template <typename T, typename... Args> +void RegisterModule(Args&&... args) { + ModuleManager::GetInstance().RegisterModule( + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...)); +} + +template <typename T, typename... Args> +void RegisterAndActivateModule(Args&&... args) { + auto& manager = ModuleManager::GetInstance(); + auto module = + GpgFrontend::SecureCreateSharedObject<T>(std::forward<Args>(args)...); + manager.RegisterModule(module); + manager.ActiveModule(module->GetModuleIdentifier()); +} + +template <typename... Args> +void TriggerEvent(const EventIdentifier& event_id, Args&&... args, + Event::EventCallback e_cb = nullptr) { + ModuleManager::GetInstance().TriggerEvent( + std::move(MakeEvent(event_id, std::forward<Args>(args)..., e_cb))); +} + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT IsModuleAcivate(ModuleIdentifier) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @param value + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT UpsertRTValue(const QString& namespace_, + const QString& key, + const std::any& value) -> bool; + +/** + * @brief + * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT ListenRTPublishEvent(QObject*, Namespace, Key, + LPCallback) -> bool; + +/** + * @brief + * + * @param namespace_ + * @param key + * @return std::vector<Key> + */ +auto GPGFRONTEND_CORE_EXPORT ListRTChildKeys(const QString& namespace_, + const QString& key) + -> std::vector<Key>; + +template <typename T> +auto RetrieveRTValueTyped(const QString& namespace_, const QString& key) + -> std::optional<T> { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return std::nullopt; +} + +template <typename T> +auto RetrieveRTValueTypedOrDefault(const QString& namespace_, + const QString& key, const T& defaultValue) + -> T { + auto any_value = + ModuleManager::GetInstance().RetrieveRTValue(namespace_, key); + if (any_value && any_value->type() == typeid(T)) { + return std::any_cast<T>(*any_value); + } + return defaultValue; +} + +} // namespace GpgFrontend::Module
\ No newline at end of file |