aboutsummaryrefslogtreecommitdiffstats
path: root/src/module/system/GlobalModuleContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/module/system/GlobalModuleContext.cpp')
-rw-r--r--src/module/system/GlobalModuleContext.cpp341
1 files changed, 341 insertions, 0 deletions
diff --git a/src/module/system/GlobalModuleContext.cpp b/src/module/system/GlobalModuleContext.cpp
new file mode 100644
index 00000000..6296250d
--- /dev/null
+++ b/src/module/system/GlobalModuleContext.cpp
@@ -0,0 +1,341 @@
+/**
+ * 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 <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "core/thread/Task.h"
+#include "module/system/Event.h"
+#include "module/system/Module.h"
+
+namespace GpgFrontend::Module {
+
+class GlobalModuleContext::Impl {
+ public:
+ Impl(TaskRunnerPtr task_runner)
+ : default_task_runner_(task_runner),
+ random_gen_(
+ (boost::posix_time::microsec_clock::universal_time() -
+ boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1)))
+ .total_milliseconds()) {
+ // Initialize acquired channels with default values.
+ acquired_channel_.insert(GPGFRONTEND_DEFAULT_CHANNEL);
+ acquired_channel_.insert(GPGFRONTEND_NON_ASCII_CHANNEL);
+ }
+
+ int GetChannel(ModulePtr plugin) {
+ // Search for the plugin in the register table.
+ auto plugin_info_opt =
+ search_plugin_register_table(plugin->GetPluginIdentifier());
+ if (!plugin_info_opt.has_value()) {
+ SPDLOG_ERROR(
+ "cannot find plugin id {} at register table, fallbacking to "
+ "default "
+ "channel",
+ plugin->GetPluginIdentifier());
+ return GetDefaultChannel(plugin);
+ }
+
+ auto plugin_info = plugin_info_opt.value();
+ return plugin_info->channel;
+ }
+
+ int GetDefaultChannel(ModulePtr) { return GPGFRONTEND_DEFAULT_CHANNEL; }
+
+ std::optional<TaskRunnerPtr> GetTaskRunner(ModulePtr plugin) {
+ auto opt = search_plugin_register_table(plugin->GetPluginIdentifier());
+ if (!opt.has_value()) {
+ return std::nullopt;
+ }
+ return opt.value()->task_runner;
+ }
+
+ std::optional<TaskRunnerPtr> GetTaskRunner(ModuleIdentifier plugin_id) {
+ // Search for the plugin in the register table.
+ auto plugin_info_opt = search_plugin_register_table(plugin_id);
+ if (!plugin_info_opt.has_value()) {
+ SPDLOG_ERROR("cannot find plugin id {} at register table", plugin_id);
+ return std::nullopt;
+ }
+ return plugin_info_opt.value()->task_runner;
+ }
+
+ std::optional<TaskRunnerPtr> GetGlobalTaskRunner() {
+ return default_task_runner_;
+ }
+
+ bool RegisterPlugin(ModulePtr plugin) {
+ SPDLOG_DEBUG("attempting to register plugin: {}",
+ plugin->GetPluginIdentifier());
+ // Check if the plugin is null or already registered.
+ if (plugin == nullptr ||
+ plugin_register_table_.find(plugin->GetPluginIdentifier()) !=
+ plugin_register_table_.end()) {
+ SPDLOG_ERROR("plugin is null or have already registered this plugin");
+ return false;
+ }
+
+ if (!plugin->Register()) {
+ SPDLOG_ERROR("register plugin {} failed", plugin->GetPluginIdentifier());
+ return false;
+ }
+
+ PluginRegisterInfo register_info;
+ register_info.plugin = plugin;
+ register_info.channel = acquire_new_unique_channel();
+ register_info.task_runner = std::make_shared<Thread::TaskRunner>();
+
+ // Register the plugin with its identifier.
+ plugin_register_table_[plugin->GetPluginIdentifier()] =
+ std::make_shared<PluginRegisterInfo>(std::move(register_info));
+
+ SPDLOG_DEBUG("successfully registered plugin: {}",
+ plugin->GetPluginIdentifier());
+ return true;
+ }
+
+ bool ActivePlugin(ModuleIdentifier plugin_id) {
+ SPDLOG_DEBUG("attempting to activate plugin: {}", plugin_id);
+
+ // Search for the plugin in the register table.
+ auto plugin_info_opt = search_plugin_register_table(plugin_id);
+ if (!plugin_info_opt.has_value()) {
+ SPDLOG_ERROR("cannot find plugin id {} at register table", plugin_id);
+ return false;
+ }
+
+ auto plugin_info = plugin_info_opt.value();
+ // Activate the plugin if it is not already active.
+ if (plugin_info->activate && plugin_info->plugin->Active()) {
+ plugin_info->activate = true;
+ }
+
+ SPDLOG_DEBUG("plugin activation status: {}", plugin_info->activate);
+ return plugin_info->activate;
+ }
+
+ bool ListenEvent(ModuleIdentifier plugin_id, EventIdentifier event) {
+ SPDLOG_DEBUG("plugin: {} is attempting to listen to event {}", plugin_id,
+ event);
+ // Check if the event exists, if not, create it.
+ auto it = plugin_events_table_.find(event);
+ if (it == plugin_events_table_.end()) {
+ plugin_events_table_[event] = std::unordered_set<ModuleIdentifier>();
+ it = plugin_events_table_.find(event);
+ SPDLOG_INFO("new event {} of plugin system created", event);
+ }
+
+ auto& listeners_set = it->second;
+ // Add the listener (plugin) to the event.
+ auto listener_it =
+ std::find(listeners_set.begin(), listeners_set.end(), plugin_id);
+ if (listener_it == listeners_set.end()) {
+ listeners_set.insert(plugin_id);
+ }
+ return true;
+ }
+
+ bool DeactivatePlugin(ModuleIdentifier plugin_id) {
+ // Search for the plugin in the register table.
+ auto plugin_info_opt = search_plugin_register_table(plugin_id);
+ if (!plugin_info_opt.has_value()) {
+ SPDLOG_ERROR("cannot find plugin id {} at register table", plugin_id);
+ return false;
+ }
+
+ auto plugin_info = plugin_info_opt.value();
+ // Activate the plugin if it is not already deactive.
+ if (!plugin_info->activate && plugin_info->plugin->Deactive()) {
+ plugin_info->activate = false;
+ }
+
+ return !plugin_info->activate;
+ }
+
+ bool TriggerEvent(EventRefrernce event) {
+ SPDLOG_DEBUG("attempting to trigger event: {}", event->GetIdentifier());
+
+ // Find the set of listeners associated with the given event in the table
+ auto it = plugin_events_table_.find(event->GetIdentifier());
+ if (it == plugin_events_table_.end()) {
+ // Log a warning if the event is not registered and nobody is listening
+ SPDLOG_WARN(
+ "event {} is not listening by anyone and not registered as well",
+ event->GetIdentifier());
+ return false;
+ }
+
+ // Retrieve the set of listeners for this event
+ auto& listeners_set = it->second;
+
+ // Check if the set of listeners is empty
+ if (listeners_set.empty()) {
+ // Log a warning if nobody is listening to this event
+ SPDLOG_WARN("event {} is not listening by anyone",
+ event->GetIdentifier());
+ return false;
+ }
+
+ // Log the number of listeners for this event
+ SPDLOG_DEBUG("event {}'s current listeners size: {}",
+ event->GetIdentifier(), listeners_set.size());
+
+ // Iterate through each listener and execute the corresponding plugin
+ for (auto& listener_plugin_id : listeners_set) {
+ // Search for the plugin's information in the registration table
+ auto plugin_info_opt = search_plugin_register_table(listener_plugin_id);
+
+ // Log an error if the plugin is not found in the registration table
+ if (!plugin_info_opt.has_value()) {
+ SPDLOG_ERROR("cannot find plugin id {} at register table",
+ listener_plugin_id);
+ }
+
+ // Retrieve the plugin's information
+ auto plugin_info = plugin_info_opt.value();
+
+ // Check if the plugin is activated
+ if (!plugin_info->activate) continue;
+
+ // Execute the plugin and check if it fails
+ if (plugin_info->plugin->Exec(event)) {
+ // Log an error if the plugin execution fails
+ SPDLOG_ERROR("plugin {} executed failed", listener_plugin_id);
+ }
+ }
+
+ // Return true to indicate successful execution of all plugins
+ return true;
+ }
+
+ private:
+ struct PluginRegisterInfo {
+ int channel;
+ TaskRunnerPtr task_runner;
+ ModulePtr plugin;
+ bool activate;
+ };
+
+ using PluginRegisterInfoPtr = std::shared_ptr<PluginRegisterInfo>;
+
+ std::unordered_map<ModuleIdentifier, PluginRegisterInfoPtr>
+ plugin_register_table_;
+ std::map<EventIdentifier, std::unordered_set<ModuleIdentifier>>
+ plugin_events_table_;
+
+ std::set<int> acquired_channel_;
+ boost::random::mt19937 random_gen_;
+ TaskRunnerPtr default_task_runner_;
+
+ int acquire_new_unique_channel() {
+ boost::random::uniform_int_distribution<> dist(1, 65535);
+
+ int random_channel = dist(random_gen_);
+ // Ensure the acquired channel is unique.
+ while (acquired_channel_.find(random_channel) != acquired_channel_.end()) {
+ random_channel = dist(random_gen_);
+ }
+
+ // Add the acquired channel to the set.
+ acquired_channel_.insert(random_channel);
+ return random_channel;
+ }
+
+ // Function to search for a plugin in the register table.
+ std::optional<PluginRegisterInfoPtr> search_plugin_register_table(
+ ModuleIdentifier identifier) {
+ auto it = plugin_register_table_.find(identifier);
+ if (it == plugin_register_table_.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+ }
+
+ std::list<ModuleIdentifier>& search_plugin_events_table(ModuleIdentifier);
+};
+
+// Constructor for GlobalPluginContext, takes a TaskRunnerPtr as an argument.
+GlobalModuleContext::GlobalModuleContext(TaskRunnerPtr task_runner)
+ : p_(std::make_unique<Impl>(task_runner)) {}
+
+GlobalModuleContext::~GlobalModuleContext() = default;
+
+// Function to get the task runner associated with a plugin.
+std::optional<TaskRunnerPtr> GlobalModuleContext::GetTaskRunner(
+ ModulePtr plugin) {
+ return p_->GetTaskRunner(plugin);
+}
+
+// Function to get the task runner associated with a plugin.
+std::optional<TaskRunnerPtr> GlobalModuleContext::GetTaskRunner(
+ ModuleIdentifier plugin_id) {
+ return p_->GetTaskRunner(plugin_id);
+}
+
+// Function to get the global task runner.
+std::optional<TaskRunnerPtr> GlobalModuleContext::GetGlobalTaskRunner() {
+ return p_->GetGlobalTaskRunner();
+}
+
+bool GlobalModuleContext::RegisterPlugin(ModulePtr plugin) {
+ return p_->RegisterPlugin(plugin);
+}
+
+bool GlobalModuleContext::ActivePlugin(ModuleIdentifier plugin_id) {
+ return p_->ActivePlugin(plugin_id);
+}
+
+bool GlobalModuleContext::ListenEvent(ModuleIdentifier plugin_id,
+ EventIdentifier event) {
+ return p_->ListenEvent(plugin_id, event);
+}
+
+bool GlobalModuleContext::DeactivatePlugin(ModuleIdentifier plugin_id) {
+ return p_->DeactivatePlugin(plugin_id);
+}
+
+bool GlobalModuleContext::TriggerEvent(EventRefrernce event) {
+ return p_->TriggerEvent(event);
+}
+
+int GlobalModuleContext::GetChannel(ModulePtr plugin) {
+ return p_->GetChannel(plugin);
+}
+
+int GlobalModuleContext::GetDefaultChannel(ModulePtr _) {
+ return p_->GetDefaultChannel(_);
+}
+
+} // namespace GpgFrontend::Module