2026-04-17 01:16:38 -03:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <QObject>
|
|
|
|
|
#include <QMap>
|
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QStringList>
|
|
|
|
|
#include <QVariantMap>
|
|
|
|
|
#include "logos_api.h"
|
|
|
|
|
|
|
|
|
|
class QTimer;
|
|
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// Forward-declared, not included: logos_qt_host_core.h pulls in nlohmann/json,
|
|
|
|
|
// and MainUIBackend, UIPluginManager, PackageCoordinator and PluginLoader all
|
|
|
|
|
// include this header without touching the facade.
|
2026-08-22 10:45:05 -03:00
|
|
|
namespace logos { namespace qt { class QtLogosCore; } }
|
|
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// CoreModuleManager — the app's module-management surface over the SDK facade.
|
2026-04-17 01:16:38 -03:00
|
|
|
//
|
2026-04-24 11:00:06 -03:00
|
|
|
// Every call into liblogos (known/loaded module lists, load/unload, cascade
|
2026-08-22 10:45:06 -03:00
|
|
|
// unload, stats) funnels through this class; UIPluginManager, PackageManager
|
|
|
|
|
// and MainUIBackend never touch the C API directly.
|
2026-04-17 01:16:38 -03:00
|
|
|
//
|
2026-08-22 10:45:05 -03:00
|
|
|
// The char*/char** marshalling and the `delete[]`-not-`free()` ownership rule
|
2026-08-22 10:45:06 -03:00
|
|
|
// live once, in logos-qt-sdk's `logos::qt::QtLogosCore`
|
|
|
|
|
// (`logos_qt_host_core.h`) over logos-cpp-sdk's `logos::host::LogosCore`.
|
|
|
|
|
// Declaring that ABI a second time in the same image is an ODR hazard with no
|
|
|
|
|
// diagnostic.
|
2026-08-22 10:45:05 -03:00
|
|
|
//
|
2026-08-22 10:45:06 -03:00
|
|
|
// What stays here is what the facade has no basis to decide: the poll interval,
|
|
|
|
|
// which thread the timer lives on, when "the module set changed" is announced,
|
|
|
|
|
// and the QML-facing key names. The poller is a single 2s QTimer that reads
|
|
|
|
|
// per-module CPU/memory and emits coreModulesChanged() so the Modules tab
|
|
|
|
|
// re-reads via Q_PROPERTY.
|
2026-04-17 01:16:38 -03:00
|
|
|
class CoreModuleManager : public QObject {
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
2026-08-22 10:45:06 -03:00
|
|
|
// `core` is the process-wide facade, owned by main() and outliving this
|
|
|
|
|
// object. Must not be null.
|
2026-08-22 10:45:05 -03:00
|
|
|
explicit CoreModuleManager(LogosAPI* logosAPI,
|
|
|
|
|
logos::qt::QtLogosCore* core,
|
|
|
|
|
QObject* parent = nullptr);
|
2026-04-17 01:16:38 -03:00
|
|
|
~CoreModuleManager() override;
|
|
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// Thin wrappers over QtLogosCore. Callers never see a raw C string.
|
2026-04-24 11:00:06 -03:00
|
|
|
QStringList knownModules() const;
|
|
|
|
|
QStringList loadedModules() const;
|
2026-08-22 10:45:06 -03:00
|
|
|
// Loads with forward dependencies resolved. Returns true on success.
|
2026-04-24 11:00:06 -03:00
|
|
|
bool loadModule(const QString& name);
|
2026-08-22 10:45:06 -03:00
|
|
|
// Returns true on success. Does NOT cascade — see
|
|
|
|
|
// unloadModuleWithDependents.
|
2026-04-24 11:00:06 -03:00
|
|
|
bool unloadModule(const QString& name);
|
2026-08-22 10:45:06 -03:00
|
|
|
// Tears down `name` and every currently-loaded module that depends on it,
|
|
|
|
|
// leaves-first. False if any step failed — the cascade may still have made
|
|
|
|
|
// progress, so callers should refresh their UI state.
|
2026-04-24 11:00:06 -03:00
|
|
|
bool unloadModuleWithDependents(const QString& name);
|
2026-04-17 01:16:38 -03:00
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// Cached as of the last timer tick, so up to ~2s stale; empty for modules
|
|
|
|
|
// the poller hasn't seen yet.
|
2026-04-17 01:16:38 -03:00
|
|
|
QVariantMap moduleStats(const QString& name) const;
|
|
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// Re-scans every plugin directory, then emits coreModulesChanged(). Called
|
|
|
|
|
// by the Modules tab's Reload button and after install/uninstall reshapes
|
|
|
|
|
// the known set.
|
2026-04-17 01:16:38 -03:00
|
|
|
Q_INVOKABLE void refresh();
|
|
|
|
|
|
2026-08-22 10:45:06 -03:00
|
|
|
// Introspection, serialised to JSON for QML. On failure getMethods/
|
|
|
|
|
// getEvents return "[]" and callMethod returns error JSON; a disconnected
|
|
|
|
|
// module is a normal transient state, not an error.
|
2026-04-17 01:16:38 -03:00
|
|
|
Q_INVOKABLE QString getMethods(const QString& moduleName);
|
2026-06-04 17:18:04 -03:00
|
|
|
Q_INVOKABLE QString getEvents(const QString& moduleName);
|
2026-04-17 01:16:38 -03:00
|
|
|
Q_INVOKABLE QString callMethod(const QString& moduleName,
|
|
|
|
|
const QString& methodName,
|
|
|
|
|
const QString& argsJson);
|
|
|
|
|
|
|
|
|
|
signals:
|
2026-08-22 10:45:06 -03:00
|
|
|
// Emitted by refresh() and after every stats tick. MainUIBackend forwards
|
|
|
|
|
// it into its own same-named signal, which is what QML binds to.
|
2026-04-17 01:16:38 -03:00
|
|
|
void coreModulesChanged();
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void updateModuleStats();
|
|
|
|
|
|
|
|
|
|
private:
|
2026-08-22 10:45:05 -03:00
|
|
|
LogosAPI* m_logosAPI; // not owned
|
|
|
|
|
logos::qt::QtLogosCore* m_core; // not owned; owned by main()
|
|
|
|
|
QTimer* m_statsTimer; // owned (parent=this)
|
2026-04-17 01:16:38 -03:00
|
|
|
QMap<QString, QVariantMap> m_moduleStats;
|
|
|
|
|
};
|