mirror of
https://github.com/logos-co/logos-plugin-qt.git
synced 2026-08-31 02:41:08 +00:00
This repo was the Qt plugin BUILD backend — pure Nix functions plus a CMake
module, with no C++ target at all. But the two things a Qt host actually needs
at runtime lived in logos-qt-sdk, where they are neither a language wrapper over
the protocol C API nor codegen:
LogosAPI / LogosAPIProvider owns a LogosTransportHost per transport,
constructs ModuleProxy / ModuleHandshakeProxy,
publishes the handshake surface, seeds trust
anchors, injects the token validator
LogosProviderBase the base every generated provider derives
PluginInterface the Qt plugin loading contract
the cdylib->Qt glue generator the emitter that wraps a language-neutral
cdylib in a Qt plugin
They move here, so "swap the plugin technology" is a one-repo change.
ADDITIVE: the sources are COPIED and logos-qt-sdk is untouched. Removing them
there now would turn nine downstream masters red at once; that comes later,
after consumers are repointed.
qt_provider_object (and logos_qt_arg_decode, which its QMetaObject dispatch
needs) is carried deliberately even though it is legacy: logos_api_provider
falls back to wrapping a plain QObject in it, and the modules that rely on that
have not been migrated yet. It goes once they are.
The generator links Qt Core and logos-lidl only — never logos-cpp-sdk. It needed
exactly one helper from that SDK's shared frontend, lidlToPascalCase (~12
lines), which is inlined instead, the same way logos-view-module does it. It
also REFUSES `--backend <anything but cdylib>` rather than ignoring the flag:
callers are migrating from a tool where --backend was required and dispatched
on, so silently treating `--backend qt` as cdylib would emit confidently wrong
artifacts with a zero exit.
`rawLib`, `lib` and `cmake-module` deliberately do not reference the new
derivations, so a consumer that only wants the Nix build functions never
realises a Qt/protocol build. Proven, not assumed: with both new inputs
overridden to a bogus flake, cmake-module and rawLib still evaluate while
logos-qt-host fails — so the override bites and the cheap outputs really never
touch it.
Behaviour preservation is the whole claim of a relocation, so it is measured:
the emitted glue is BYTE-IDENTICAL to logos-qt-generator --backend cdylib over
every one of the 20 .lidl contracts in the workspace, in both single and
concurrency:multi mode (40 pairs, exit codes included), and single vs multi do
differ from each other, so both code paths were really exercised. The built
liblogos_qt_host.a is byte-identical to liblogos_qt_sdk.a, exporting the same
390 symbols.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
124 lines
5.1 KiB
C++
124 lines
5.1 KiB
C++
#ifndef LOGOS_API_PROVIDER_H
|
|
#define LOGOS_API_PROVIDER_H
|
|
|
|
#include "logos_transport_config.h"
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include <QVariant>
|
|
#include <QVariantList>
|
|
#include <QMap>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
class LogosTransportHost;
|
|
class LogosObject;
|
|
class ModuleProxy;
|
|
class ModuleHandshakeProxy;
|
|
class LogosProviderObject;
|
|
class QtProviderObject;
|
|
|
|
/**
|
|
* @brief LogosAPIProvider handles registering objects for access by consumers
|
|
*
|
|
* Supports two registration paths:
|
|
* 1. registerObject(name, QObject*) — wraps in QtProviderObject, then ModuleProxy
|
|
* 2. registerObject(name, LogosProviderObject*) — wraps directly in ModuleProxy
|
|
* Both paths converge at ModuleProxy -> transport.
|
|
*/
|
|
class LogosAPIProvider : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
/**
|
|
* @param module_name The module this provider belongs to.
|
|
* @param transports Optional per-instance transport override. When empty,
|
|
* the provider uses the process-global default. This
|
|
* is what lets a daemon expose `core_service` on
|
|
* TCP/TLS while keeping module-to-module traffic on
|
|
* the local-socket default.
|
|
*/
|
|
explicit LogosAPIProvider(const QString& module_name,
|
|
LogosTransportSet transports = {},
|
|
QObject *parent = nullptr);
|
|
// Back-compat overload
|
|
LogosAPIProvider(const QString& module_name, QObject *parent)
|
|
: LogosAPIProvider(module_name, LogosTransportSet{}, parent) {}
|
|
~LogosAPIProvider();
|
|
|
|
/**
|
|
* @brief Register a legacy QObject-based plugin.
|
|
* Wraps in QtProviderObject, then ModuleProxy.
|
|
*/
|
|
bool registerObject(const QString& name, QObject* object);
|
|
|
|
/**
|
|
* @brief Register a legacy QObject-based plugin — const char* overload (resolves ambiguity)
|
|
*/
|
|
bool registerObject(const char* name, QObject* object)
|
|
{ return registerObject(QString(name), object); }
|
|
|
|
/**
|
|
* @brief Register a legacy QObject-based plugin (std::string overload).
|
|
*/
|
|
bool registerObject(const std::string& name, QObject* object);
|
|
|
|
/**
|
|
* @brief Register a new-API LogosProviderObject plugin.
|
|
* Wraps directly in ModuleProxy.
|
|
*/
|
|
bool registerObject(const QString& name, LogosProviderObject* provider);
|
|
|
|
QString registryUrl() const;
|
|
bool saveToken(const QString& from_module_name, const QString& token);
|
|
|
|
// Install an extra token authorizer, forwarded to the ModuleProxy. Consulted
|
|
// in addition to the built-in issued-token scan, with the call's transport
|
|
// ("local" | "tcp" | "tcp_ssl") so local_only tokens can be enforced. The
|
|
// daemon backs this with TokenStore::lookupByToken so operator-issued named
|
|
// tokens authorize. Safe to call before or after registerObject(); a
|
|
// validator set before registration is applied when the proxy is created.
|
|
using TokenValidator = std::function<bool(const QString& token,
|
|
const QString& transportProtocol)>;
|
|
void setTokenValidator(TokenValidator validator);
|
|
|
|
public slots:
|
|
void onEventResponse(LogosObject* object, const QString& eventName, const QVariantList& data);
|
|
|
|
private:
|
|
bool publishProvider(const QString& name, LogosProviderObject* provider);
|
|
// Publishes the token-only handshake surface (logos::handshakeObjectName)
|
|
// before the module's initializer runs, so capability_module can deliver a
|
|
// token to a module that is still starting up. Best-effort: a transport that
|
|
// declines it simply leaves capability_module falling back to the business
|
|
// object, which is the pre-existing behaviour.
|
|
void publishHandshake(const QString& name, LogosProviderObject* provider);
|
|
// Installs the host-issued token as this module's "core"/"capability_module"
|
|
// trust anchor before the handshake surface is published. Without it the
|
|
// surface is reachable but refuses every push for the whole pre-init window
|
|
// it exists to cover, because the initializer that normally seeds those
|
|
// entries has not run yet. Never overwrites an existing entry, and is a no-op
|
|
// on a host that does not publish an `authToken` property.
|
|
void seedHandshakeTrustAnchor();
|
|
|
|
// One host per configured transport. Single-entry vector for back-compat.
|
|
std::vector<std::unique_ptr<LogosTransportHost>> m_transports;
|
|
QString m_registryUrl;
|
|
QMap<QString, QString> m_tokens;
|
|
ModuleProxy* m_moduleProxy;
|
|
ModuleHandshakeProxy* m_handshakeProxy = nullptr;
|
|
QString m_registeredHandshakeName;
|
|
QtProviderObject* m_qtProviderObject;
|
|
QString m_registeredObjectName;
|
|
// Appended (never inserted mid-list): keeps every pre-existing member's
|
|
// offset identical between builds, so a LogosAPIProvider is layout-safe even
|
|
// if a future co-located consumer ever accessed one across a version
|
|
// boundary. Held until the proxy exists (registerObject may come after the
|
|
// setter).
|
|
TokenValidator m_pendingValidator;
|
|
};
|
|
|
|
#endif // LOGOS_API_PROVIDER_H
|