Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
WsConnectionImpl.hpp
1#pragma once
2
3#include "util/WithTimeout.hpp"
4#include "util/requests/Types.hpp"
5#include "util/requests/WsConnection.hpp"
6
7#include <boost/asio/associated_executor.hpp>
8#include <boost/asio/bind_cancellation_slot.hpp>
9#include <boost/asio/buffer.hpp>
10#include <boost/asio/cancellation_signal.hpp>
11#include <boost/asio/cancellation_type.hpp>
12#include <boost/asio/spawn.hpp>
13#include <boost/asio/steady_timer.hpp>
14#include <boost/beast/core/buffers_to_string.hpp>
15#include <boost/beast/core/error.hpp>
16#include <boost/beast/core/flat_buffer.hpp>
17#include <boost/beast/core/tcp_stream.hpp>
18#include <boost/beast/ssl/ssl_stream.hpp>
19#include <boost/beast/websocket/rfc6455.hpp>
20#include <boost/beast/websocket/stream.hpp>
21#include <boost/beast/websocket/stream_base.hpp>
22#include <boost/system/errc.hpp>
23
24#include <atomic>
25#include <chrono>
26#include <expected>
27#include <memory>
28#include <optional>
29#include <string>
30#include <utility>
31
32namespace util::requests::impl {
33
34template <typename StreamType>
35class WsConnectionImpl : public WsConnection {
36 StreamType ws_;
37
38public:
39 explicit WsConnectionImpl(StreamType ws) : ws_(std::move(ws))
40 {
41 }
42
43 std::expected<std::string, RequestError>
45 boost::asio::yield_context yield,
46 std::optional<std::chrono::steady_clock::duration> timeout = std::nullopt
47 ) override
48 {
49 boost::beast::error_code errorCode;
50 boost::beast::flat_buffer buffer;
51
52 auto operation = [&](auto&& token) { ws_.async_read(buffer, token); };
53 if (timeout) {
54 errorCode = util::withTimeout(operation, yield[errorCode], *timeout);
55 } else {
56 operation(yield[errorCode]);
57 }
58
59 if (errorCode)
60 return std::unexpected{RequestError{"Read error", errorCode}};
61
62 return boost::beast::buffers_to_string(std::move(buffer).data());
63 }
64
65 std::optional<RequestError>
67 std::string const& message,
68 boost::asio::yield_context yield,
69 std::optional<std::chrono::steady_clock::duration> timeout = std::nullopt
70 ) override
71 {
72 boost::beast::error_code errorCode;
73 auto operation = [&](auto&& token) {
74 ws_.async_write(boost::asio::buffer(message), token);
75 };
76 if (timeout) {
77 errorCode = util::withTimeout(operation, yield, *timeout);
78 } else {
79 operation(yield[errorCode]);
80 }
81
82 if (errorCode)
83 return RequestError{"Write error", errorCode};
84
85 return std::nullopt;
86 }
87
88 std::optional<RequestError>
90 boost::asio::yield_context yield,
91 std::chrono::steady_clock::duration const timeout = kDEFAULT_TIMEOUT
92 ) override
93 {
94 // Set the timeout for closing the connection
95 boost::beast::websocket::stream_base::timeout wsTimeout{};
96 ws_.get_option(wsTimeout);
97 wsTimeout.handshake_timeout = timeout;
98 ws_.set_option(wsTimeout);
99
100 boost::beast::error_code errorCode;
101 ws_.async_close(boost::beast::websocket::close_code::normal, yield[errorCode]);
102 if (errorCode)
103 return RequestError{"Close error", errorCode};
104 return std::nullopt;
105 }
106};
107
108using PlainWsConnection =
109 WsConnectionImpl<boost::beast::websocket::stream<boost::beast::tcp_stream>>;
110using SslWsConnection = WsConnectionImpl<
111 boost::beast::websocket::stream<boost::asio::ssl::stream<boost::beast::tcp_stream>>>;
112
113} // namespace util::requests::impl
Error type for HTTP requests.
Definition Types.hpp:15
Interface for WebSocket connections. It is used to hide SSL and plain connections behind the same int...
Definition WsConnection.hpp:30
static constexpr std::chrono::seconds kDEFAULT_TIMEOUT
Definition WsConnection.hpp:75
std::optional< RequestError > close(boost::asio::yield_context yield, std::chrono::steady_clock::duration const timeout=kDEFAULT_TIMEOUT) override
Close the WebSocket.
Definition WsConnectionImpl.hpp:89
std::optional< RequestError > write(std::string const &message, boost::asio::yield_context yield, std::optional< std::chrono::steady_clock::duration > timeout=std::nullopt) override
Write a message to the WebSocket.
Definition WsConnectionImpl.hpp:66
std::expected< std::string, RequestError > read(boost::asio::yield_context yield, std::optional< std::chrono::steady_clock::duration > timeout=std::nullopt) override
Read a message from the WebSocket.
Definition WsConnectionImpl.hpp:44
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:56
boost::system::error_code withTimeout(Operation &&operation, boost::asio::yield_context yield, std::chrono::steady_clock::duration timeout)
Perform a coroutine operation with a timeout.
Definition WithTimeout.hpp:30