From eafc8baf5195634b2f337d2991f4e95d35942e1a Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 27 Mar 2026 15:54:11 -0400 Subject: [PATCH] simplify: plugin_loader is no longer needed --- src/CMakeLists.txt | 2 - src/logos_core/plugin_loader.cpp | 216 ------------------------------ src/logos_core/plugin_loader.h | 27 ---- src/logos_core/plugin_manager.cpp | 205 ++++++++++++++++++++++++++-- 4 files changed, 193 insertions(+), 257 deletions(-) delete mode 100644 src/logos_core/plugin_loader.cpp delete mode 100644 src/logos_core/plugin_loader.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 539928b..8a4fc0b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,8 +96,6 @@ set(LOGOS_CORE_SOURCES logos_core/plugin_registry.h logos_core/dependency_resolver.cpp logos_core/dependency_resolver.h - logos_core/plugin_loader.cpp - logos_core/plugin_loader.h logos_core/plugin_manager.cpp logos_core/plugin_manager.h logos_core/qt/qt_app_context.cpp diff --git a/src/logos_core/plugin_loader.cpp b/src/logos_core/plugin_loader.cpp deleted file mode 100644 index 99cc2ad..0000000 --- a/src/logos_core/plugin_loader.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "plugin_loader.h" -#include "plugin_registry.h" -#include "dependency_resolver.h" -#include "qt/qt_process_manager.h" -#include -#include -#include -#include -#include -#include "logos_api.h" -#include "logos_api_client.h" -#include "token_manager.h" - -PluginLoader::PluginLoader(PluginRegistry& registry) - : m_registry(registry) -{ -} - -QString PluginLoader::resolveLogosHostPath() { - QString logosHostPath; - - QByteArray envPathBytes = qgetenv("LOGOS_HOST_PATH"); - if (!envPathBytes.isEmpty()) { - logosHostPath = QString::fromUtf8(envPathBytes); - } - - if (logosHostPath.isEmpty()) { - logosHostPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/logos_host"); - } - - if (!QFile::exists(logosHostPath)) { - QStringList dirs = m_registry.pluginsDirs(); - if (!dirs.isEmpty()) { - QDir pluginsDirCandidate(dirs.first()); - QString candidate = QDir::cleanPath(pluginsDirCandidate.absoluteFilePath("../bin/logos_host")); - if (QFile::exists(candidate)) { - logosHostPath = candidate; - } - } - } - - if (!QFile::exists(logosHostPath)) { - qCritical() << "logos_host not found at:" << logosHostPath - << "- set LOGOS_HOST_PATH or place it next to the executable"; - return QString(); - } - - return logosHostPath; -} - -void PluginLoader::notifyCapabilityModule(const QString& name, const QString& token) { - if (!m_registry.isLoaded("capability_module")) - return; - - TokenManager& tokenManager = TokenManager::instance(); - QString capabilityModuleToken = tokenManager.getToken("capability_module"); - - static LogosAPI* s_coreApi = nullptr; - if (!s_coreApi) - s_coreApi = new LogosAPI("core"); - - LogosAPIClient* client = s_coreApi->getClient("capability_module"); - if (!client->informModuleToken(capabilityModuleToken, name, token)) { - qWarning() << "Failed to register token with capability module for:" << name; - } -} - -bool PluginLoader::loadPlugin(const QString& name) { - if (!m_registry.isKnown(name)) { - qWarning() << "Cannot load unknown plugin:" << name; - return false; - } - - if (m_registry.isLoaded(name)) { - qWarning() << "Plugin already loaded:" << name; - return false; - } - - QString pluginPath = m_registry.pluginPath(name); - - QString logosHostPath = resolveLogosHostPath(); - if (logosHostPath.isEmpty()) - return false; - - std::vector arguments = { - "--name", name.toStdString(), - "--path", pluginPath.toStdString() - }; - - PluginRegistry* registry = &m_registry; - - QtProcessManager::ProcessCallbacks callbacks; - - callbacks.onFinished = [registry](const std::string& pluginName, int exitCode, bool crashed) { - Q_UNUSED(exitCode); - QString qName = QString::fromStdString(pluginName); - if (crashed) { - qCritical() << "Plugin process crashed:" << qName; - exit(1); - } - registry->markUnloaded(qName); - }; - - callbacks.onError = [](const std::string& pluginName, bool crashed) { - if (crashed) { - qCritical() << "Plugin process crashed:" << QString::fromStdString(pluginName); - exit(1); - } - }; - - callbacks.onOutput = [](const std::string& pluginName, const std::string& line, bool isStderr) { - QString qName = QString::fromStdString(pluginName); - QString qLine = QString::fromStdString(line); - if (isStderr) { - qCritical() << "[" << qName << "]" << qLine; - } else if (qLine.contains("Warning:") || qLine.contains("WARNING:")) { - qWarning() << "[" << qName << "]" << qLine; - } else if (qLine.contains("Critical:") || qLine.contains("FAILED:") || qLine.contains("ERROR:")) { - qCritical() << "[" << qName << "]" << qLine; - } - }; - - if (!QtProcessManager::startProcess(name.toStdString(), logosHostPath.toStdString(), arguments, callbacks)) { - return false; - } - - QUuid authToken = QUuid::createUuid(); - QString authTokenString = authToken.toString(QUuid::WithoutBraces); - - if (!QtProcessManager::sendToken(name.toStdString(), authTokenString.toStdString())) { - return false; - } - - m_registry.markLoaded(name); - - TokenManager& tokenManager = TokenManager::instance(); - tokenManager.saveToken(name, authTokenString); - - notifyCapabilityModule(name, authTokenString); - - qInfo() << "Plugin loaded:" << name; - - return true; -} - -bool PluginLoader::loadPluginWithDependencies(const QString& name) { - QStringList requested; - requested.append(name); - - QStringList resolved = DependencyResolver::resolve( - requested, - [this](const QString& n) { return m_registry.isKnown(n); }, - [this](const QString& n) { return m_registry.pluginDependencies(n); } - ); - - if (resolved.isEmpty() || !resolved.contains(name)) { - qWarning() << "Cannot resolve dependencies for:" << name; - return false; - } - - bool allSucceeded = true; - for (const QString& moduleName : resolved) { - if (m_registry.isLoaded(moduleName)) - continue; - if (!loadPlugin(moduleName)) { - qWarning() << "Failed to load plugin:" << moduleName; - allSucceeded = false; - } - } - - return allSucceeded; -} - -bool PluginLoader::initializeCapabilityModule() { - if (!m_registry.isKnown("capability_module")) - return false; - - if (!loadPlugin("capability_module")) { - qWarning() << "Failed to load capability module"; - return false; - } - - return true; -} - -bool PluginLoader::unloadPlugin(const QString& name) { - if (!m_registry.isLoaded(name)) { - qWarning() << "Cannot unload plugin (not loaded):" << name; - return false; - } - - if (!QtProcessManager::hasProcess(name.toStdString())) { - qWarning() << "No process found for plugin:" << name; - return false; - } - - QtProcessManager::terminateProcess(name.toStdString()); - m_registry.markUnloaded(name); - - qInfo() << "Plugin unloaded:" << name; - return true; -} - -void PluginLoader::terminateAll() { - QtProcessManager::terminateAll(); - m_registry.clearLoaded(); -} - -QHash PluginLoader::getPluginProcessIds() { - auto stdMap = QtProcessManager::getAllProcessIds(); - QHash result; - for (const auto& [name, pid] : stdMap) { - result.insert(QString::fromStdString(name), pid); - } - return result; -} diff --git a/src/logos_core/plugin_loader.h b/src/logos_core/plugin_loader.h deleted file mode 100644 index 9f3967e..0000000 --- a/src/logos_core/plugin_loader.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PLUGIN_LOADER_H -#define PLUGIN_LOADER_H - -#include -#include - -class PluginRegistry; - -class PluginLoader { -public: - explicit PluginLoader(PluginRegistry& registry); - - bool loadPlugin(const QString& name); - bool loadPluginWithDependencies(const QString& name); - bool initializeCapabilityModule(); - bool unloadPlugin(const QString& name); - void terminateAll(); - QHash getPluginProcessIds(); - -private: - QString resolveLogosHostPath(); - void notifyCapabilityModule(const QString& name, const QString& token); - - PluginRegistry& m_registry; -}; - -#endif // PLUGIN_LOADER_H diff --git a/src/logos_core/plugin_manager.cpp b/src/logos_core/plugin_manager.cpp index 43bf2d5..c0a2216 100644 --- a/src/logos_core/plugin_manager.cpp +++ b/src/logos_core/plugin_manager.cpp @@ -1,10 +1,17 @@ #include "plugin_manager.h" #include "plugin_registry.h" -#include "plugin_loader.h" #include "dependency_resolver.h" +#include "qt/qt_process_manager.h" #include +#include +#include +#include +#include #include #include +#include "logos_api.h" +#include "logos_api_client.h" +#include "token_manager.h" namespace { PluginRegistry& registryInstance() { @@ -12,11 +19,6 @@ namespace { return instance; } - PluginLoader& loaderInstance() { - static PluginLoader instance(registryInstance()); - return instance; - } - char** toNullTerminatedArray(const QStringList& list) { int count = list.size(); if (count == 0) { @@ -34,6 +36,55 @@ namespace { result[count] = nullptr; return result; } + + QString resolveLogosHostPath() { + QString logosHostPath; + + QByteArray envPathBytes = qgetenv("LOGOS_HOST_PATH"); + if (!envPathBytes.isEmpty()) { + logosHostPath = QString::fromUtf8(envPathBytes); + } + + if (logosHostPath.isEmpty()) { + logosHostPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/logos_host"); + } + + if (!QFile::exists(logosHostPath)) { + QStringList dirs = registryInstance().pluginsDirs(); + if (!dirs.isEmpty()) { + QDir pluginsDirCandidate(dirs.first()); + QString candidate = QDir::cleanPath(pluginsDirCandidate.absoluteFilePath("../bin/logos_host")); + if (QFile::exists(candidate)) { + logosHostPath = candidate; + } + } + } + + if (!QFile::exists(logosHostPath)) { + qCritical() << "logos_host not found at:" << logosHostPath + << "- set LOGOS_HOST_PATH or place it next to the executable"; + return QString(); + } + + return logosHostPath; + } + + void notifyCapabilityModule(const QString& name, const QString& token) { + if (!registryInstance().isLoaded("capability_module")) + return; + + TokenManager& tokenManager = TokenManager::instance(); + QString capabilityModuleToken = tokenManager.getToken("capability_module"); + + static LogosAPI* s_coreApi = nullptr; + if (!s_coreApi) + s_coreApi = new LogosAPI("core"); + + LogosAPIClient* client = s_coreApi->getClient("capability_module"); + if (!client->informModuleToken(capabilityModuleToken, name, token)) { + qWarning() << "Failed to register token with capability module for:" << name; + } + } } namespace PluginManager { @@ -76,23 +127,148 @@ namespace PluginManager { } bool loadPlugin(const char* pluginName) { - return loaderInstance().loadPlugin(QString::fromUtf8(pluginName)); + QString name = QString::fromUtf8(pluginName); + + if (!registryInstance().isKnown(name)) { + qWarning() << "Cannot load unknown plugin:" << name; + return false; + } + + if (registryInstance().isLoaded(name)) { + qWarning() << "Plugin already loaded:" << name; + return false; + } + + QString pluginPath = registryInstance().pluginPath(name); + + QString logosHostPath = resolveLogosHostPath(); + if (logosHostPath.isEmpty()) + return false; + + std::vector arguments = { + "--name", name.toStdString(), + "--path", pluginPath.toStdString() + }; + + QtProcessManager::ProcessCallbacks callbacks; + + callbacks.onFinished = [](const std::string& pName, int exitCode, bool crashed) { + Q_UNUSED(exitCode); + QString qName = QString::fromStdString(pName); + if (crashed) { + qCritical() << "Plugin process crashed:" << qName; + exit(1); + } + registryInstance().markUnloaded(qName); + }; + + callbacks.onError = [](const std::string& pName, bool crashed) { + if (crashed) { + qCritical() << "Plugin process crashed:" << QString::fromStdString(pName); + exit(1); + } + }; + + callbacks.onOutput = [](const std::string& pName, const std::string& line, bool isStderr) { + QString qName = QString::fromStdString(pName); + QString qLine = QString::fromStdString(line); + if (isStderr) { + qCritical() << "[" << qName << "]" << qLine; + } else if (qLine.contains("Warning:") || qLine.contains("WARNING:")) { + qWarning() << "[" << qName << "]" << qLine; + } else if (qLine.contains("Critical:") || qLine.contains("FAILED:") || qLine.contains("ERROR:")) { + qCritical() << "[" << qName << "]" << qLine; + } + }; + + if (!QtProcessManager::startProcess(name.toStdString(), logosHostPath.toStdString(), arguments, callbacks)) { + return false; + } + + QUuid authToken = QUuid::createUuid(); + QString authTokenString = authToken.toString(QUuid::WithoutBraces); + + if (!QtProcessManager::sendToken(name.toStdString(), authTokenString.toStdString())) { + return false; + } + + registryInstance().markLoaded(name); + + TokenManager& tokenManager = TokenManager::instance(); + tokenManager.saveToken(name, authTokenString); + + notifyCapabilityModule(name, authTokenString); + + qInfo() << "Plugin loaded:" << name; + + return true; } bool loadPluginWithDependencies(const char* pluginName) { - return loaderInstance().loadPluginWithDependencies(QString::fromUtf8(pluginName)); + QString name = QString::fromUtf8(pluginName); + + QStringList requested; + requested.append(name); + + QStringList resolved = DependencyResolver::resolve( + requested, + [](const QString& n) { return registryInstance().isKnown(n); }, + [](const QString& n) { return registryInstance().pluginDependencies(n); } + ); + + if (resolved.isEmpty() || !resolved.contains(name)) { + qWarning() << "Cannot resolve dependencies for:" << name; + return false; + } + + bool allSucceeded = true; + for (const QString& moduleName : resolved) { + if (registryInstance().isLoaded(moduleName)) + continue; + if (!loadPlugin(moduleName.toUtf8().constData())) { + qWarning() << "Failed to load plugin:" << moduleName; + allSucceeded = false; + } + } + + return allSucceeded; } bool initializeCapabilityModule() { - return loaderInstance().initializeCapabilityModule(); + if (!registryInstance().isKnown("capability_module")) + return false; + + if (!loadPlugin("capability_module")) { + qWarning() << "Failed to load capability module"; + return false; + } + + return true; } bool unloadPlugin(const char* pluginName) { - return loaderInstance().unloadPlugin(QString::fromUtf8(pluginName)); + QString name = QString::fromUtf8(pluginName); + + if (!registryInstance().isLoaded(name)) { + qWarning() << "Cannot unload plugin (not loaded):" << name; + return false; + } + + if (!QtProcessManager::hasProcess(name.toStdString())) { + qWarning() << "No process found for plugin:" << name; + return false; + } + + QtProcessManager::terminateProcess(name.toStdString()); + registryInstance().markUnloaded(name); + + qInfo() << "Plugin unloaded:" << name; + return true; } void terminateAll() { - loaderInstance().terminateAll(); + QtProcessManager::terminateAll(); + registryInstance().clearLoaded(); } char** getLoadedPluginsCStr() { @@ -112,7 +288,12 @@ namespace PluginManager { } QHash getPluginProcessIds() { - return loaderInstance().getPluginProcessIds(); + auto stdMap = QtProcessManager::getAllProcessIds(); + QHash result; + for (const auto& [name, pid] : stdMap) { + result.insert(QString::fromStdString(name), pid); + } + return result; } QStringList resolveDependencies(const QStringList& requestedModules) {