move plugin launcher as a separate concern

This commit is contained in:
Iuri Matias
2026-03-27 16:08:21 -04:00
parent eafc8baf51
commit dd455eef3e
4 changed files with 153 additions and 94 deletions
+2
View File
@@ -98,6 +98,8 @@ set(LOGOS_CORE_SOURCES
logos_core/dependency_resolver.h
logos_core/plugin_manager.cpp
logos_core/plugin_manager.h
logos_core/plugin_launcher.cpp
logos_core/plugin_launcher.h
logos_core/qt/qt_app_context.cpp
logos_core/qt/qt_app_context.h
logos_core/qt/qt_process_manager.cpp
+116
View File
@@ -0,0 +1,116 @@
#include "plugin_launcher.h"
#include "qt/qt_process_manager.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QCoreApplication>
namespace {
QString resolveLogosHostPath(const QStringList& pluginsDirs) {
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)) {
if (!pluginsDirs.isEmpty()) {
QDir pluginsDirCandidate(pluginsDirs.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;
}
}
namespace PluginLauncher {
bool launch(const QString& name, const QString& pluginPath,
const QStringList& pluginsDirs, OnTerminatedFn onTerminated) {
QString logosHostPath = resolveLogosHostPath(pluginsDirs);
if (logosHostPath.isEmpty())
return false;
std::vector<std::string> arguments = {
"--name", name.toStdString(),
"--path", pluginPath.toStdString()
};
QtProcessManager::ProcessCallbacks callbacks;
callbacks.onFinished = [onTerminated](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);
}
if (onTerminated)
onTerminated(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;
}
};
return QtProcessManager::startProcess(name.toStdString(), logosHostPath.toStdString(), arguments, callbacks);
}
bool sendToken(const QString& name, const QString& token) {
return QtProcessManager::sendToken(name.toStdString(), token.toStdString());
}
void terminate(const QString& name) {
QtProcessManager::terminateProcess(name.toStdString());
}
void terminateAll() {
QtProcessManager::terminateAll();
}
bool hasProcess(const QString& name) {
return QtProcessManager::hasProcess(name.toStdString());
}
QHash<QString, qint64> getAllProcessIds() {
auto stdMap = QtProcessManager::getAllProcessIds();
QHash<QString, qint64> result;
for (const auto& [name, pid] : stdMap) {
result.insert(QString::fromStdString(name), pid);
}
return result;
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef PLUGIN_LAUNCHER_H
#define PLUGIN_LAUNCHER_H
#include <QString>
#include <QStringList>
#include <QHash>
#include <functional>
namespace PluginLauncher {
using OnTerminatedFn = std::function<void(const QString& name)>;
bool launch(const QString& name, const QString& pluginPath,
const QStringList& pluginsDirs, OnTerminatedFn onTerminated);
bool sendToken(const QString& name, const QString& token);
void terminate(const QString& name);
void terminateAll();
bool hasProcess(const QString& name);
QHash<QString, qint64> getAllProcessIds();
}
#endif // PLUGIN_LAUNCHER_H
+14 -94
View File
@@ -1,12 +1,9 @@
#include "plugin_manager.h"
#include "plugin_registry.h"
#include "dependency_resolver.h"
#include "qt/qt_process_manager.h"
#include "plugin_launcher.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QUuid>
#include <QCoreApplication>
#include <cassert>
#include <cstring>
#include "logos_api.h"
@@ -37,38 +34,6 @@ namespace {
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;
@@ -141,63 +106,23 @@ namespace PluginManager {
QString pluginPath = registryInstance().pluginPath(name);
QString logosHostPath = resolveLogosHostPath();
if (logosHostPath.isEmpty())
auto onTerminated = [](const QString& n) {
registryInstance().markUnloaded(n);
};
if (!PluginLauncher::launch(name, pluginPath, registryInstance().pluginsDirs(), onTerminated))
return false;
std::vector<std::string> arguments = {
"--name", name.toStdString(),
"--path", pluginPath.toStdString()
};
QString authToken = QUuid::createUuid().toString(QUuid::WithoutBraces);
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)) {
if (!PluginLauncher::sendToken(name, authToken))
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);
TokenManager::instance().saveToken(name, authToken);
notifyCapabilityModule(name, authTokenString);
notifyCapabilityModule(name, authToken);
qInfo() << "Plugin loaded:" << name;
@@ -254,12 +179,12 @@ namespace PluginManager {
return false;
}
if (!QtProcessManager::hasProcess(name.toStdString())) {
if (!PluginLauncher::hasProcess(name)) {
qWarning() << "No process found for plugin:" << name;
return false;
}
QtProcessManager::terminateProcess(name.toStdString());
PluginLauncher::terminate(name);
registryInstance().markUnloaded(name);
qInfo() << "Plugin unloaded:" << name;
@@ -267,7 +192,7 @@ namespace PluginManager {
}
void terminateAll() {
QtProcessManager::terminateAll();
PluginLauncher::terminateAll();
registryInstance().clearLoaded();
}
@@ -288,12 +213,7 @@ namespace PluginManager {
}
QHash<QString, qint64> getPluginProcessIds() {
auto stdMap = QtProcessManager::getAllProcessIds();
QHash<QString, qint64> result;
for (const auto& [name, pid] : stdMap) {
result.insert(QString::fromStdString(name), pid);
}
return result;
return PluginLauncher::getAllProcessIds();
}
QStringList resolveDependencies(const QStringList& requestedModules) {