ORE Studio 0.0.4
Loading...
Searching...
No Matches
client.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2025 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_COMMS_NET_CLIENT_HPP
21#define ORES_COMMS_NET_CLIENT_HPP
22
23#include <mutex>
24#include <atomic>
25#include <thread>
26#include <memory>
27#include <iosfwd>
28#include <cstdint>
29#include <functional>
30#include <string_view>
31#include <boost/asio/awaitable.hpp>
32#include <boost/asio/ssl.hpp>
33#include <boost/asio/strand.hpp>
34#include <boost/asio/ip/tcp.hpp>
35#include <boost/asio/io_context.hpp>
36#include "ores.utility/log/make_logger.hpp"
37#include "ores.eventing/service/event_bus.hpp"
38#include "ores.comms/net/client_options.hpp"
39#include "ores.comms/net/connection.hpp"
40#include "ores.comms/net/pending_request_map.hpp"
41
43
53
54std::ostream& operator<<(std::ostream& s, connection_state v);
55
64using disconnect_callback_t = std::function<void()>;
65
75using reconnecting_callback_t = std::function<void()>;
76
86using reconnected_callback_t = std::function<void()>;
87
99using notification_callback_t = std::function<void(
100 const std::string& event_type,
101 std::chrono::system_clock::time_point timestamp)>;
102
108class client final {
109private:
110 inline static std::string_view logger_name = "ores.comms.net.client";
111
112 static auto& lg() {
113 using namespace ores::utility::log;
114 static auto instance = make_logger(logger_name);
115 return instance;
116 }
117
121 void setup_ssl_context();
122
128 boost::asio::awaitable<void> perform_handshake();
129
136 boost::asio::awaitable<void> run_heartbeat();
137
146 boost::asio::awaitable<void> run_message_loop();
147
154 boost::asio::awaitable<void> run_reconnect_loop();
155
161 boost::asio::awaitable<void> perform_connection();
162
169 std::chrono::milliseconds calculate_backoff(std::uint32_t attempt) const;
170
178 boost::asio::awaitable<void> write_frame(const messaging::frame& f);
179
183 std::uint32_t next_correlation_id();
184
185public:
194 explicit client(client_options config,
195 std::shared_ptr<eventing::service::event_bus> event_bus = nullptr);
196
204 explicit client(client_options config, boost::asio::any_io_executor executor,
205 std::shared_ptr<eventing::service::event_bus> event_bus = nullptr);
206
213 ~client();
214
222 boost::asio::awaitable<void> connect();
223
231 void connect_sync();
232
240 boost::asio::awaitable<void> connect_with_retry();
241
250
254 void disconnect();
255
261 bool is_connected() const;
262
267
277
287
297
307
317 boost::asio::awaitable<std::expected<messaging::frame, messaging::error_code>>
318 send_request(messaging::frame request_frame);
319
329 std::expected<messaging::frame, messaging::error_code>
330 send_request_sync(messaging::frame request_frame);
331
332private:
333 client_options config_;
334 std::unique_ptr<boost::asio::io_context> io_ctx_; // Owned io_context for sync operations
335 boost::asio::any_io_executor executor_;
336 boost::asio::ssl::context ssl_ctx_;
337 std::unique_ptr<connection> conn_;
338 std::uint32_t sequence_number_;
339 std::atomic<connection_state> state_;
340 mutable std::mutex state_mutex_; // Protects conn_, sequence_number_, and callbacks
341 disconnect_callback_t disconnect_callback_;
342 reconnecting_callback_t reconnecting_callback_;
343 reconnected_callback_t reconnected_callback_;
344 notification_callback_t notification_callback_;
345 std::shared_ptr<eventing::service::event_bus> event_bus_; // Optional event bus for connection events
346
347 // Infrastructure for unified message loop
348 std::unique_ptr<boost::asio::strand<boost::asio::any_io_executor>> write_strand_;
349 std::unique_ptr<pending_request_map> pending_requests_;
350 std::atomic<std::uint32_t> correlation_id_counter_{1};
351 std::atomic<bool> message_loop_running_{false};
352 std::atomic<bool> reconnect_loop_running_{false};
353 std::atomic<bool> heartbeat_loop_running_{false};
354 std::unique_ptr<std::thread> io_thread_; // Background thread for io_context
355 std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> work_guard_;
356
357 // Session compression type negotiated during handshake
358 messaging::compression_type session_compression_{messaging::compression_type::none};
359};
360
361}
362
363#endif
compression_type
Compression algorithm used for payload compression.
Definition message_types.hpp:91
Contains the networking elements of the comms library.
Definition client.hpp:42
connection_state
Connection state for the client.
Definition client.hpp:47
@ connected
Connected and ready for requests.
@ disconnected
Not connected to server.
@ connecting
Initial connection in progress.
@ reconnecting
Lost connection, attempting to reconnect.
std::function< void()> reconnected_callback_t
Callback invoked when client successfully reconnects.
Definition client.hpp:86
std::function< void(const std::string &event_type, std::chrono::system_clock::time_point timestamp)> notification_callback_t
Callback invoked when client receives a notification from server.
Definition client.hpp:101
std::function< void()> reconnecting_callback_t
Callback invoked when client starts reconnection attempts.
Definition client.hpp:75
std::function< void()> disconnect_callback_t
Callback invoked when client detects server disconnect.
Definition client.hpp:64
Implements logging for ORE Studio.
Definition lifecycle_manager.hpp:30
Complete frame with header and payload.
Definition frame.hpp:77
ORES protocol client.
Definition client.hpp:108
void set_notification_callback(notification_callback_t callback)
Set callback to be invoked when a notification is received.
Definition client.cpp:627
std::expected< messaging::frame, messaging::error_code > send_request_sync(messaging::frame request_frame)
Send a request frame and receive response frame (blocking version).
Definition client.cpp:827
void connect_with_retry_sync()
Connect to server with retry (blocking version).
Definition client.cpp:391
boost::asio::awaitable< void > connect_with_retry()
Connect to server with retry (async version).
Definition client.cpp:333
connection_state get_state() const
Get the current connection state.
Definition client.cpp:608
boost::asio::awaitable< std::expected< messaging::frame, messaging::error_code > > send_request(messaging::frame request_frame)
Send a request frame and receive response frame (async version).
Definition client.cpp:721
void set_reconnected_callback(reconnected_callback_t callback)
Set callback to be invoked when reconnection succeeds.
Definition client.cpp:622
void disconnect()
Disconnect from server.
Definition client.cpp:578
boost::asio::awaitable< void > connect()
Connect to server and perform handshake (async version).
Definition client.cpp:249
void connect_sync()
Connect to server and perform handshake (blocking version).
Definition client.cpp:269
void set_reconnecting_callback(reconnecting_callback_t callback)
Set callback to be invoked when reconnection starts.
Definition client.cpp:617
~client()
Destructor.
Definition client.cpp:99
bool is_connected() const
Check if client is connected.
Definition client.cpp:604
void set_disconnect_callback(disconnect_callback_t callback)
Set callback to be invoked when disconnect is detected.
Definition client.cpp:612
Configuration for the client.
Definition client_options.hpp:78