diff --git a/cpp/logos_api.cpp b/cpp/logos_api.cpp index 7f43acd..a9baa57 100644 --- a/cpp/logos_api.cpp +++ b/cpp/logos_api.cpp @@ -62,6 +62,27 @@ LogosAPIClient* LogosAPI::getClient(const std::string& target_module) const return getClient(QString::fromStdString(target_module)); } +LogosAPIClient* LogosAPI::getClient(const QString& target_module, + const LogosTransportConfig& transport) const +{ + // Separate cache from the default-transport path. Caching by + // (target, protocol) keeps `getClient(x, tcp_ssl)` and + // `getClient(x, local)` from aliasing onto the same object, which + // would double-open connections / confuse reuse. + const QString key = target_module + "#" + + QString::number(static_cast(transport.protocol)) + ":" + + QString::fromStdString(transport.host) + ":" + + QString::number(transport.port); + if (m_clientsByTransport.contains(key)) + return m_clientsByTransport.value(key); + + LogosAPIClient* client = new LogosAPIClient( + target_module, m_module_name, m_token_manager, transport, + const_cast(this)); + m_clientsByTransport.insert(key, client); + return client; +} + TokenManager* LogosAPI::getTokenManager() const { return m_token_manager; diff --git a/cpp/logos_api.h b/cpp/logos_api.h index 04c4125..78e2d40 100644 --- a/cpp/logos_api.h +++ b/cpp/logos_api.h @@ -82,6 +82,24 @@ public: */ LogosAPIClient* getClient(const std::string& target_module) const; + /** + * @brief Get a client that uses an *explicit* transport instead of + * the process-global default. + * + * Use this when the caller needs to dial one module over a + * particular protocol without side-effecting the rest of the + * process. Canonical case: a CLI that talks only to `core_service` + * over tcp_ssl — using `LogosTransportConfigGlobal::setDefault` for + * that would also flip the same process's `LogosAPIProvider` into + * trying to bind a tcp_ssl server, which the CLI has no cert for. + * + * Cached per (target_module, transport) pair so repeat calls with + * the same config return the same client; a request with a + * different transport to the same target creates a separate client. + */ + LogosAPIClient* getClient(const QString& target_module, + const LogosTransportConfig& transport) const; + /** * @brief Get the token manager instance * @return TokenManager* Pointer to the token manager @@ -98,7 +116,8 @@ public: private: QString m_module_name; LogosAPIProvider* m_provider; - mutable QHash m_clients; // Cache of clients per target module + mutable QHash m_clients; // Cache of default-transport clients per target module + mutable QHash m_clientsByTransport; // Cache for explicit-transport clients, keyed by target+transport TokenManager* m_token_manager; }; diff --git a/cpp/logos_api_client.cpp b/cpp/logos_api_client.cpp index f67873f..1641d7a 100644 --- a/cpp/logos_api_client.cpp +++ b/cpp/logos_api_client.cpp @@ -13,6 +13,18 @@ LogosAPIClient::LogosAPIClient(const QString& module_to_talk_to, const QString& { } +LogosAPIClient::LogosAPIClient(const QString& module_to_talk_to, + const QString& origin_module, + TokenManager* token_manager, + const LogosTransportConfig& transport, + QObject *parent) + : QObject(parent) + , m_consumer(new LogosAPIConsumer(module_to_talk_to, origin_module, token_manager, transport, this)) + , m_token_manager(token_manager) + , m_origin_module(origin_module) +{ +} + LogosAPIClient::~LogosAPIClient() { } diff --git a/cpp/logos_api_client.h b/cpp/logos_api_client.h index c453cab..fc192f8 100644 --- a/cpp/logos_api_client.h +++ b/cpp/logos_api_client.h @@ -10,6 +10,7 @@ #include #include "logos_mode.h" +#include "logos_transport_config.h" class LogosAPIConsumer; class LogosObject; @@ -27,6 +28,18 @@ class LogosAPIClient : public QObject public: explicit LogosAPIClient(const QString& module_to_talk_to, const QString& origin_module, TokenManager* token_manager, QObject *parent = nullptr); + /** + * Explicit-transport overload. The client (and the consumer it + * owns) will use `transport` for its connection, bypassing + * `LogosTransportConfigGlobal::getDefault`. See + * `LogosAPIConsumer`'s explicit-transport constructor for the + * full rationale. + */ + LogosAPIClient(const QString& module_to_talk_to, + const QString& origin_module, + TokenManager* token_manager, + const LogosTransportConfig& transport, + QObject *parent = nullptr); ~LogosAPIClient(); /** diff --git a/cpp/logos_api_consumer.cpp b/cpp/logos_api_consumer.cpp index fcb23ab..49560e6 100644 --- a/cpp/logos_api_consumer.cpp +++ b/cpp/logos_api_consumer.cpp @@ -23,6 +23,23 @@ LogosAPIConsumer::LogosAPIConsumer(const QString& module_to_talk_to, const QStri m_transport->connectToHost(); } +LogosAPIConsumer::LogosAPIConsumer(const QString& module_to_talk_to, + const QString& origin_module, + TokenManager* token_manager, + const LogosTransportConfig& transport, + QObject *parent) + : QObject(parent) + , m_registryUrl(LogosInstance::id(module_to_talk_to)) + , m_token_manager(token_manager) +{ + // Explicit-config path. Bypasses `LogosTransportConfigGlobal::getDefault` + // so the caller's choice of transport for THIS consumer doesn't bleed + // into the rest of the process (in particular, any `LogosAPIProvider` + // in the same LogosAPI still creates its host from the global default). + m_transport = LogosTransportFactory::createConnection(transport, m_registryUrl); + m_transport->connectToHost(); +} + LogosAPIConsumer::~LogosAPIConsumer() { } diff --git a/cpp/logos_api_consumer.h b/cpp/logos_api_consumer.h index 33a972a..1f6761e 100644 --- a/cpp/logos_api_consumer.h +++ b/cpp/logos_api_consumer.h @@ -11,6 +11,7 @@ #include #include "logos_mode.h" +#include "logos_transport_config.h" class LogosTransportConnection; class LogosObject; @@ -31,6 +32,20 @@ class LogosAPIConsumer : public QObject public: explicit LogosAPIConsumer(const QString& module_to_talk_to, const QString& origin_module, TokenManager* token_manager, QObject *parent = nullptr); + /** + * Explicit-transport overload. Use this when the caller needs a + * specific transport for this consumer and does *not* want the + * process-global default (which also drives provider bind-URLs). + * Typical case: a pure client that only reaches one remote module + * over a particular protocol — e.g. the logoscore CLI dialing + * `core_service` over tcp_ssl without side-effecting the client's + * own LogosAPI provider into also trying to bind TLS. + */ + LogosAPIConsumer(const QString& module_to_talk_to, + const QString& origin_module, + TokenManager* token_manager, + const LogosTransportConfig& transport, + QObject *parent = nullptr); ~LogosAPIConsumer(); /**