support non-local remote transports (#57)

* support non-local remote transports

* fix LogosResult

* allow getting client over specific transport

* fix ssl

* investiage ssl error

* pr comments

* allow transport set configuration on any module

* pr comments

* add docs

* pr comments

* propagate only non-qt dependencies

* restore ABI compatibility
This commit is contained in:
Dario Lipicar
2026-05-07 12:27:14 -03:00
committed by GitHub
parent ecd369d48b
commit 25c88f4d48
57 changed files with 4960 additions and 114 deletions
+77 -10
View File
@@ -1,15 +1,45 @@
#include "logos_api_client.h"
#include "logos_api.h"
#include "logos_api_consumer.h"
#include "logos_object.h"
#include "token_manager.h"
#include <QMetaObject>
#include <QPointer>
#include <string>
LogosAPIClient::LogosAPIClient(const QString& module_to_talk_to, const QString& origin_module, TokenManager* token_manager, QObject *parent)
LogosAPIClient::LogosAPIClient(const QString& module_to_talk_to,
const QString& origin_module,
TokenManager* token_manager,
const LogosTransportConfig& target_transport,
const LogosTransportConfig& capability_transport,
QObject *parent)
: QObject(parent)
, m_consumer(new LogosAPIConsumer(module_to_talk_to, origin_module, token_manager, this))
, m_consumer(new LogosAPIConsumer(module_to_talk_to, origin_module,
token_manager, target_transport, this))
, m_token_manager(token_manager)
, m_origin_module(origin_module)
// Pre-build the capability_module consumer once. We skip it for
// the capability_module client itself — the auto-`requestModule`
// path is gated by `objectName != "capability_module"` so we'd
// never use it, and constructing one would be a redundant
// self-connection. Init-list order matches the declaration order
// in the header — `m_capability_consumer` is appended at the end
// for ABI stability (see header comment).
, m_capability_consumer(module_to_talk_to == QStringLiteral("capability_module")
? nullptr
: new LogosAPIConsumer(QStringLiteral("capability_module"),
origin_module, token_manager,
capability_transport, this))
{
}
LogosAPIClient::LogosAPIClient(const QString& module_to_talk_to,
const QString& origin_module,
TokenManager* token_manager,
QObject *parent)
: LogosAPIClient(module_to_talk_to, origin_module, token_manager,
LogosTransportConfigGlobal::getDefault(),
LogosTransportConfigGlobal::getDefault(), parent)
{
}
@@ -44,11 +74,12 @@ QVariant LogosAPIClient::invokeRemoteMethod(const QString& objectName, const QSt
QString token = getToken(objectName);
if (token.isEmpty() && objectName != "capability_module") {
if (token.isEmpty() && objectName != "capability_module" && m_capability_consumer) {
qDebug() << "LogosAPIClient: calling requestModule for" << objectName;
LogosAPIConsumer* packageManagerConsumer = new LogosAPIConsumer("capability_module", m_origin_module, m_token_manager, this);
QString capabilityToken = getToken("capability_module");
QVariant result = packageManagerConsumer->invokeRemoteMethod(capabilityToken, "capability_module", "requestModule", QVariantList() << m_origin_module << objectName, timeout);
QVariant result = m_capability_consumer->invokeRemoteMethod(
capabilityToken, "capability_module", "requestModule",
QVariantList() << m_origin_module << objectName, timeout);
qDebug() << "LogosAPIClient: requestModule result for" << objectName << ":" << result.toString();
token = result.toString();
}
@@ -96,11 +127,47 @@ void LogosAPIClient::invokeRemoteMethodAsync(const QString& objectName, const QS
QString token = getToken(objectName);
if (token.isEmpty() && objectName != "capability_module") {
LogosAPIConsumer* packageManagerConsumer = new LogosAPIConsumer("capability_module", m_origin_module, m_token_manager, this);
QString capabilityToken = getToken("capability_module");
QVariant result = packageManagerConsumer->invokeRemoteMethod(capabilityToken, "capability_module", "requestModule", QVariantList() << m_origin_module << objectName, timeout);
token = result.toString();
if (token.isEmpty() && objectName != "capability_module" && m_capability_consumer) {
// Async-chain: dispatch the requestModule call asynchronously,
// and only fire the real method's invokeRemoteMethodAsync from
// its callback. The previous version called `requestModule`
// synchronously here, which made the "async" entry point
// block its caller for the full requestModule round-trip
// (a real perf hit when capability_module has any latency).
//
// Lifetime: the inner callback captures m_consumer through a
// QPointer guard. If the LogosAPIClient (and thus its
// QObject-parented m_consumer) is destroyed while the
// requestModule round-trip is still in flight, the QPointer
// goes null and the inner dispatch is suppressed instead of
// dereferencing dangling memory.
const QString capabilityToken = getToken("capability_module");
const QString origin = m_origin_module;
QPointer<LogosAPIConsumer> consumer = m_consumer;
auto outerCallback = std::move(callback);
m_capability_consumer->invokeRemoteMethodAsync(
capabilityToken,
QStringLiteral("capability_module"),
QStringLiteral("requestModule"),
QVariantList() << origin << objectName,
[consumer, objectName, methodName, args, timeout,
outerCallback = std::move(outerCallback)]
(const QVariant& tokenResult) mutable {
if (!consumer) {
// Client was destroyed mid-flight. Honour the
// contract by firing the outer callback with an
// invalid QVariant so callers don't deadlock
// waiting for a result that'll never come.
if (outerCallback) outerCallback(QVariant{});
return;
}
consumer->invokeRemoteMethodAsync(
tokenResult.toString(),
objectName, methodName, args,
std::move(outerCallback), timeout);
},
timeout);
return;
}
m_consumer->invokeRemoteMethodAsync(token, objectName, methodName, args, std::move(callback), timeout);