aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/module
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/module')
-rw-r--r--src/core/module/Event.cpp139
-rw-r--r--src/core/module/Event.h95
-rw-r--r--src/core/module/GlobalModuleContext.cpp377
-rw-r--r--src/core/module/GlobalModuleContext.h88
-rw-r--r--src/core/module/GlobalRegisterTable.cpp167
-rw-r--r--src/core/module/GlobalRegisterTable.h66
-rw-r--r--src/core/module/GpgFrontendModuleSystem.h34
-rw-r--r--src/core/module/Module.cpp106
-rw-r--r--src/core/module/Module.h80
-rw-r--r--src/core/module/ModuleManager.cpp184
-rw-r--r--src/core/module/ModuleManager.h179
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