hlcc 2.0.0-beta2+pre1
Loading...
Searching...
No Matches
requestor.hpp
Go to the documentation of this file.
1
9#ifndef HLCC_CPPUTIL_REQUESTOR_HPP
10#define HLCC_CPPUTIL_REQUESTOR_HPP
11
12
13#include <atomic>
14
15#include <mal/Cii.hpp>
16
17
18
19namespace hlcc::cpputil {
20
21
31template <typename INTERFACE_TYPE>
32class Requestor {
33public:
38 explicit Requestor(log4cplus::Logger& logger)
39 : m_mutex {},
40 m_logger{logger},
41 m_uri{},
42 m_client{}
43 {
44 }
45
53 explicit Requestor(log4cplus::Logger& logger, const elt::mal::Uri& uri,
54 const std::optional<elt::mal::Mal::Properties> mal_properties = {})
55 : Requestor(logger) {
56 SetConnectionInfo(uri, mal_properties);
57 }
58
65 void SetConnectionInfo(const elt::mal::Uri& uri,
66 const std::optional<elt::mal::Mal::Properties> mal_properties = {}) {
67
68 std::lock_guard lck {m_mutex};
69
70 if (uri != m_uri) {
71 // Close previous instance. Probably would be done automatically after being dereferenced.
72 if (m_client) {
73 LOG4CPLUS_DEBUG(m_logger, "SetConnectionInfo will close old client");
74 m_client->close();
75 }
76
77 try {
78 // Create the MAL client.
79 // Note that (at least with ZMQ MAL), client construction immediately triggers an async connection attempt.
80 m_client = elt::mal::CiiFactory::getInstance().getClient<INTERFACE_TYPE>(
81 uri, elt::mal::rr::qos::QoS::DEFAULT,
82 mal_properties ? *mal_properties : elt::mal::Mal::Properties());
83 m_uri = uri;
84 LOG4CPLUS_DEBUG(m_logger, "Created rr client for " << uri);
85
86 // Register connection listener that logs all later connections and disconnections.
87 // This registration itself is async, which means that if immediately afterwards we call Connect
88 // or connect implicitly by using the interface, then the new connection may not be logged yet.
89 // We copy-capture the uri instead of using m_uri because these two may diverge when switching to a new URI.
90 m_client->registerConnectionListener([this, uri](bool connected) {
91 m_connected.store(connected);
92 LOG4CPLUS_DEBUG(m_logger, "Connected with " << uri << ": " << connected);
93 });
94 } catch (const std::exception& ex) {
95 // This happens, for example, when Nomad does not resolve the address and gives us a URI such as "zpb.rr:///trksim/TrackCmds".
96 // We just log the error and leave m_client empty or closed. A following call to Connect will fail.
97 LOG4CPLUS_WARN(m_logger, "Failed to create rr client for " << uri << ": " << ex.what());
98 }
99 }
100 }
101
108 std::shared_ptr<INTERFACE_TYPE>& GetInterface() {
109 std::lock_guard lck {m_mutex};
110 if (!m_client) {
111 LOG4CPLUS_DEBUG(m_logger, "Requestor::GetInterface() called without having an interface client. The user must call SetConnectionInfo first.");
112 // still we return the empty pointer.
113 }
114 return m_client;
115 }
116
128 bool Connect(std::chrono::seconds conn_timeout) {
129 std::lock_guard lck {m_mutex};
130 if (m_client) {
131 // TODO should we skip this if m_connected == true?
132 // Currently we also connect redundantly, just to be able to probe it independently of the timing of the connection callback.
133
134 elt::mal::future<void> conn_future = m_client->asyncConnect();
135 ::boost::chrono::seconds conn_timeout_cii{conn_timeout.count()};
136 LOG4CPLUS_TRACE(m_logger, "Requestor::Connect() called asyncConnect() and will wait max " << conn_timeout_cii.count() << " s.");
137 auto future_status = conn_future.wait_for(conn_timeout_cii);
138 bool success = future_status == (boost::future_status::ready); // ready, timeout, deferred
139 LOG4CPLUS_TRACE(m_logger, "Requestor::Connect() returned from waiting for connection, success=" << success);
140 return success;
141 }
142 else {
143 LOG4CPLUS_DEBUG(m_logger, "Requestor::Connect() failed because of missing MAL client.");
144 return false;
145 }
146 }
147
148 Requestor(const Requestor&) = delete;
149 Requestor& operator=(const Requestor&) = delete;
150
151private:
152 mutable std::recursive_mutex m_mutex;
153 log4cplus::Logger& m_logger;
154 elt::mal::Uri m_uri;
155 std::shared_ptr<INTERFACE_TYPE> m_client; // Share pointer to MAL Client
156
160 std::atomic<bool> m_connected{false};
161};
162
163
164
165} // namespace hlcc::cpputil
166
167#endif // RAD_MAL_REQUESTOR_HPP_
Definition: requestor.hpp:32
Requestor(const Requestor &)=delete
Requestor(log4cplus::Logger &logger, const elt::mal::Uri &uri, const std::optional< elt::mal::Mal::Properties > mal_properties={})
Definition: requestor.hpp:53
Requestor(log4cplus::Logger &logger)
Definition: requestor.hpp:38
Requestor & operator=(const Requestor &)=delete
bool Connect(std::chrono::seconds conn_timeout)
Definition: requestor.hpp:128
std::shared_ptr< INTERFACE_TYPE > & GetInterface()
Definition: requestor.hpp:108
void SetConnectionInfo(const elt::mal::Uri &uri, const std::optional< elt::mal::Mal::Properties > mal_properties={})
Definition: requestor.hpp:65
Definition: requestor.hpp:19