refactor: abstract connection/transport; and clearly separate qt remote obj and qt local into separate implementations

This commit is contained in:
Iuri Matias
2026-03-20 21:00:41 +00:00
committed by Logos Workspace
parent 4b66dac015
commit 1f14e5dbaa
13 changed files with 638 additions and 318 deletions
+23 -237
View File
@@ -4,9 +4,8 @@
#include "token_manager.h"
#include "logos_mode.h"
#include "logos_instance.h"
#include "plugin_registry.h"
#include <QRemoteObjectNode>
#include <QRemoteObjectReplica>
#include "logos_transport.h"
#include "logos_transport_factory.h"
#include <QRemoteObjectPendingCall>
#include <QRemoteObjectPendingCallWatcher>
#include <QPointer>
@@ -18,30 +17,20 @@
LogosAPIConsumer::LogosAPIConsumer(const QString& module_to_talk_to, const QString& origin_module, TokenManager* token_manager, QObject *parent)
: QObject(parent)
, m_node(nullptr)
, m_registryUrl(LogosInstance::id(module_to_talk_to))
, m_connected(false)
, m_token_manager(token_manager)
{
if (LogosModeConfig::isLocal()) {
qDebug() << "LogosAPIConsumer: Using Local mode - skipping QRemoteObjectNode";
m_connected = true;
} else {
m_node = new QRemoteObjectNode(this);
connectToRegistry();
}
m_transport = LogosTransportFactory::createConnection(m_registryUrl);
m_transport->connectToHost();
}
LogosAPIConsumer::~LogosAPIConsumer()
{
// Clean up event callbacks and connections
for (auto it = m_connections.begin(); it != m_connections.end(); ++it) {
QObject::disconnect(it.value());
}
m_eventCallbacks.clear();
m_connections.clear();
// QRemoteObjectNode will be deleted automatically as it's a child object
}
QObject* LogosAPIConsumer::requestObject(const QString& objectName, Timeout timeout)
@@ -53,45 +42,21 @@ QObject* LogosAPIConsumer::requestObject(const QString& objectName, Timeout time
return nullptr;
}
if (LogosModeConfig::isLocal()) {
QObject* plugin = PluginRegistry::getPlugin<QObject>(objectName);
if (!plugin) {
qWarning() << "LogosAPIConsumer: Plugin not found in registry:" << objectName;
return nullptr;
}
qDebug() << "LogosAPIConsumer: Successfully found plugin:" << objectName;
return plugin;
}
if (!m_connected) {
if (!m_transport->isConnected()) {
qWarning() << "LogosAPIConsumer: Not connected to registry. Cannot request object:" << objectName;
return nullptr;
}
qDebug() << "LogosAPIConsumer: Requesting object:" << objectName;
// Acquire the dynamic replica
QRemoteObjectReplica* replica = m_node->acquireDynamic(objectName);
if (!replica) {
qWarning() << "LogosAPIConsumer: Failed to acquire replica for object:" << objectName;
return nullptr;
QObject* object = m_transport->requestObject(objectName, timeout.ms);
if (object) {
qDebug() << "LogosAPIConsumer: Successfully acquired object:" << objectName;
}
// Wait for the replica to be initialized
if (!replica->waitForSource(timeout.ms)) {
qWarning() << "LogosAPIConsumer: Timeout waiting for object replica to be ready:" << objectName;
delete replica;
return nullptr;
}
qDebug() << "LogosAPIConsumer: Successfully acquired replica for object:" << objectName;
qDebug() << "LogosAPIConsumer: Replica acquired at" << QTime::currentTime().toString("hh:mm:ss.zzz");
return replica;
return object;
}
bool LogosAPIConsumer::isConnected() const
{
return m_connected;
return m_transport->isConnected();
}
QString LogosAPIConsumer::registryUrl() const
@@ -101,113 +66,24 @@ QString LogosAPIConsumer::registryUrl() const
bool LogosAPIConsumer::reconnect()
{
if (LogosModeConfig::isLocal()) {
m_connected = true;
return true;
}
qDebug() << "LogosAPIConsumer: Attempting to reconnect to registry:" << m_registryUrl;
// Disconnect first if already connected
if (m_connected) {
// Note: QRemoteObjectNode doesn't have a direct disconnect method
// We'll create a new node instead
m_node->deleteLater();
m_node = new QRemoteObjectNode(this);
m_connected = false;
}
return connectToRegistry();
return m_transport->reconnect();
}
bool LogosAPIConsumer::connectToRegistry()
{
if (!m_node) {
qWarning() << "LogosAPIConsumer: Remote object node is null";
return false;
}
if (m_registryUrl.isEmpty()) {
qWarning() << "LogosAPIConsumer: Registry URL is empty";
return false;
}
qDebug() << "LogosAPIConsumer: Connecting to registry:" << m_registryUrl;
qDebug() << "LogosAPIConsumer: Connecting to registry at" << QTime::currentTime().toString("hh:mm:ss.zzz");
// Connect to the registry node
QUrl url(m_registryUrl);
bool success = m_node->connectToNode(url);
if (success) {
m_connected = true;
qDebug() << "LogosAPIConsumer: Successfully connected to registry:" << m_registryUrl;
} else {
m_connected = false;
qWarning() << "LogosAPIConsumer: Failed to connect to registry:" << m_registryUrl;
}
qDebug() << "LogosAPIConsumer: Connected to registry at" << QTime::currentTime().toString("hh:mm:ss.zzz");
return m_connected;
}
QVariant LogosAPIConsumer::invokeRemoteMethod(const QString& authToken, const QString& objectName, const QString& methodName,
const QVariantList& args, Timeout timeout)
{
qDebug() << "LogosAPIConsumer: Calling invokeRemoteMethod:" << objectName << methodName << "args_count:" << args.size() << "timeout:" << timeout.ms;
// This method handles both ModuleProxy-wrapped modules (template_module, package_manager)
// and direct remote object calls for other modules
QObject* plugin = requestObject(objectName, timeout);
QObject* plugin = m_transport->requestObject(objectName, timeout.ms);
if (!plugin) {
qWarning() << "LogosAPIConsumer: Failed to acquire plugin/replica for object:" << objectName;
return QVariant();
}
ModuleProxy* moduleProxy = qobject_cast<ModuleProxy*>(plugin);
if (moduleProxy) {
QVariant result = moduleProxy->callRemoteMethod(authToken, methodName, args);
if (!LogosModeConfig::isLocal()) {
delete plugin;
}
return result;
}
if (LogosModeConfig::isLocal()) {
qWarning() << "LogosAPIConsumer: Local mode requires ModuleProxy-wrapped objects";
return QVariant();
}
// Remote mode: callRemoteMethod returns QRemoteObjectPendingCall, not QVariant
QRemoteObjectPendingCall pendingCall;
bool success = QMetaObject::invokeMethod(
plugin,
"callRemoteMethod",
Qt::DirectConnection,
Q_RETURN_ARG(QRemoteObjectPendingCall, pendingCall),
Q_ARG(QString, authToken),
Q_ARG(QString, methodName),
Q_ARG(QVariantList, args)
);
if (!success) {
qWarning() << "LogosAPIConsumer: Failed to invoke callRemoteMethod on replica for object:" << objectName;
delete plugin;
return QVariant();
}
// Wait for the result
pendingCall.waitForFinished(timeout.ms);
delete plugin;
if (!pendingCall.isFinished() || pendingCall.error() != QRemoteObjectPendingCall::NoError) {
qWarning() << "LogosAPIConsumer: Remote callRemoteMethod failed or timed out:" << pendingCall.error();
return QVariant();
}
return pendingCall.returnValue();
QVariant result = m_transport->callRemoteMethod(plugin, authToken, methodName, args, timeout.ms);
m_transport->releaseObject(plugin);
return result;
}
void LogosAPIConsumer::invokeRemoteMethodAsync(const QString& authToken, const QString& objectName, const QString& methodName,
@@ -289,12 +165,9 @@ void LogosAPIConsumer::onEvent(QObject* originObject, QObject* destinationObject
{
qDebug() << "LogosAPIConsumer: Registering event listener for event:" << eventName;
// Store the callback for this event name
m_eventCallbacks[eventName].append(callback);
// Check if we already have a connection for this origin object
if (!m_connections.contains(originObject)) {
// Create new connection only if it doesn't exist
auto connection = QObject::connect(originObject, SIGNAL(eventResponse(QString, QVariantList)),
this, SLOT(invokeCallback(QString, QVariantList)));
@@ -313,11 +186,6 @@ void LogosAPIConsumer::onEvent(QObject* originObject, QObject* destinationObject
void LogosAPIConsumer::invokeCallback(const QString& eventName, const QVariantList& data)
{
// qDebug() << "LogosAPIConsumer: invokeCallback called for event:" << eventName;
// Call all registered callbacks
// Note: This will call all callbacks for any event. In a more sophisticated implementation,
// you might want to store event names with callbacks to filter them.
for (const auto& callback : m_eventCallbacks[eventName]) {
try {
callback(eventName, data);
@@ -325,15 +193,12 @@ void LogosAPIConsumer::invokeCallback(const QString& eventName, const QVariantLi
qWarning() << "LogosAPIConsumer: Exception in callback for event:" << eventName;
}
}
// qDebug() << "LogosAPIConsumer: Called" << m_eventCallbacks[eventName].size() << "callbacks for event:" << eventName;
}
void LogosAPIConsumer::onEvent(QObject* originObject, QObject* destinationObject, const QString& eventName)
{
qDebug() << "LogosAPIConsumer: Registering event listener for event:" << eventName << "(connecting to destination slot)";
// connect to the eventResponse signal of the destinationObject's slot
QObject::connect(originObject, SIGNAL(eventResponse(QString, QVariantList)),
destinationObject, SLOT(onEventResponse(QString, QVariantList)), Qt::AutoConnection);
}
@@ -342,109 +207,30 @@ bool LogosAPIConsumer::informModuleToken(const QString& authToken, const QString
{
qDebug() << "LogosAPIConsumer: Informing module token for module:" << moduleName << "with token:" << token;
QObject* plugin = requestObject("capability_module", Timeout(20000));
QObject* plugin = m_transport->requestObject("capability_module", 20000);
if (!plugin) {
qWarning() << "LogosAPIConsumer: Failed to acquire plugin/replica for object: capability_module";
return false;
}
ModuleProxy* moduleProxy = qobject_cast<ModuleProxy*>(plugin);
if (moduleProxy) {
bool result = moduleProxy->informModuleToken(authToken, moduleName, token);
qDebug() << "LogosAPIConsumer: informModuleToken completed with result:" << result;
if (!LogosModeConfig::isLocal()) {
delete plugin;
}
return result;
}
if (LogosModeConfig::isLocal()) {
qWarning() << "LogosAPIConsumer: Local mode requires ModuleProxy-wrapped objects";
return false;
}
QRemoteObjectPendingCall pendingCall;
bool success = QMetaObject::invokeMethod(
plugin,
"informModuleToken",
Qt::DirectConnection,
Q_RETURN_ARG(QRemoteObjectPendingCall, pendingCall),
Q_ARG(QString, authToken),
Q_ARG(QString, moduleName),
Q_ARG(QString, token)
);
if (!success) {
qWarning() << "LogosAPIConsumer: Failed to invoke informModuleToken on replica";
delete plugin;
return false;
}
pendingCall.waitForFinished(20000);
delete plugin;
if (!pendingCall.isFinished() || pendingCall.error() != QRemoteObjectPendingCall::NoError) {
qWarning() << "LogosAPIConsumer: Remote informModuleToken failed or timed out:" << pendingCall.error();
return false;
}
QVariant result = pendingCall.returnValue();
bool result = m_transport->callInformModuleToken(plugin, authToken, moduleName, token, 20000);
qDebug() << "LogosAPIConsumer: informModuleToken completed with result:" << result;
return result.toBool();
m_transport->releaseObject(plugin);
return result;
}
bool LogosAPIConsumer::informModuleToken_module(const QString& authToken, const QString& originModule, const QString& moduleName, const QString& token)
{
qDebug() << "LogosAPIConsumer: Informing module token for module:" << moduleName << "with token:" << token;
QObject* plugin = requestObject(originModule, Timeout(20000));
QObject* plugin = m_transport->requestObject(originModule, 20000);
if (!plugin) {
qWarning() << "LogosAPIConsumer: Failed to acquire plugin/replica for object:" << originModule;
return false;
}
ModuleProxy* moduleProxy = qobject_cast<ModuleProxy*>(plugin);
if (moduleProxy) {
bool result = moduleProxy->informModuleToken(authToken, moduleName, token);
qDebug() << "LogosAPIConsumer: informModuleToken completed with result:" << result;
if (!LogosModeConfig::isLocal()) {
delete plugin;
}
return result;
}
if (LogosModeConfig::isLocal()) {
qWarning() << "LogosAPIConsumer: Local mode requires ModuleProxy-wrapped objects";
return false;
}
QRemoteObjectPendingCall pendingCall;
bool success = QMetaObject::invokeMethod(
plugin,
"informModuleToken",
Qt::DirectConnection,
Q_RETURN_ARG(QRemoteObjectPendingCall, pendingCall),
Q_ARG(QString, authToken),
Q_ARG(QString, moduleName),
Q_ARG(QString, token)
);
if (!success) {
qWarning() << "LogosAPIConsumer: Failed to invoke informModuleToken on replica";
delete plugin;
return false;
}
pendingCall.waitForFinished(20000);
delete plugin;
if (!pendingCall.isFinished() || pendingCall.error() != QRemoteObjectPendingCall::NoError) {
qWarning() << "LogosAPIConsumer: Remote informModuleToken failed or timed out:" << pendingCall.error();
return false;
}
QVariant result = pendingCall.returnValue();
bool result = m_transport->callInformModuleToken(plugin, authToken, moduleName, token, 20000);
qDebug() << "LogosAPIConsumer: informModuleToken completed with result:" << result;
return result.toBool();
m_transport->releaseObject(plugin);
return result;
}