userver: userver/server/websocket/server.hpp Source File
Loading...
Searching...
No Matches
server.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/websocket/server.hpp
4/// @brief @copybrief websocket::WebSocketConnection
5
6#include <memory>
7#include <optional>
8
9#include <userver/engine/io/socket.hpp>
10#include <userver/server/http/http_request.hpp>
11#include <userver/tracing/span.hpp>
12#include <userver/utils/span.hpp>
13#include <userver/yaml_config/fwd.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace server::websocket {
18
19using CloseStatusInt = int16_t;
20
21/// @brief Close statuses
23 kNone = 0,
24
25 kNormal = 1000,
26 kGoingAway = 1001,
27 kProtocolError = 1002,
28 kUnsupportedData = 1003,
29 kFrameTooLarge = 1004,
30 kNoStatusRcvd = 1005,
31 kAbnormalClosure = 1006,
32 kBadMessageData = 1007,
33 kPolicyViolation = 1008,
34 kTooBigData = 1009,
35 kExtensionMismatch = 1010,
36 kServerError = 1011
37};
38
39/// @brief WebSocket message
40struct Message {
41 std::string data; ///< payload
42 std::optional<CloseStatus> close_status = {}; ///< close status
43 bool is_text = false; ///< is it text or binary?
44};
45
46class WebSocketConnectionImpl;
47
48struct Config final {
49 unsigned max_remote_payload = 65536;
50 unsigned fragment_size = 65536; // 0 - do not fragment
51};
52
53Config Parse(const yaml_config::YamlConfig&, formats::parse::To<Config>);
54
55struct Statistics final {
56 std::atomic<int64_t> msg_sent{0};
57 std::atomic<int64_t> msg_recv{0};
58 std::atomic<int64_t> bytes_sent{0};
59 std::atomic<int64_t> bytes_recv{0};
60};
61
62/// @brief Main class for Websocket connection
64public:
65 WebSocketConnection();
66
67 WebSocketConnection(WebSocketConnection&&) = delete;
68 WebSocketConnection(const WebSocketConnection&) = delete;
69
70 WebSocketConnection& operator=(WebSocketConnection&&) = delete;
71 WebSocketConnection& operator=(const WebSocketConnection&) = delete;
72
73 virtual ~WebSocketConnection();
74
75 /// @brief Read a message from websocket, handling pings under the hood.
76 /// @param message input message
77 /// @throws engine::io::IoException in case of socket errors
78 /// @note Recv() is not thread-safe by itself (you may not call Recv() from
79 /// multiple coroutines at once), but it is safe to call Recv() and Send()
80 /// from different coroutines at once thus implementing full-duplex socket
81 /// connection.
82 virtual void Recv(Message& message) = 0;
83
84 /// @brief Behaves in the same way as Recv(), but in case of first bytes of
85 /// message are not yet ready to receive gives the control up to a client.
86 /// @returns false in case of messages absence, otherwise true and behaves
87 /// like Recv()
88 virtual bool TryRecv(Message& message) = 0;
89
90 /// @brief Send a message to websocket.
91 /// @param message message to send
92 /// @throws engine::io::IoException in case of socket errors
93 /// @note Send() is not thread-safe by itself (you may not call Send() from
94 /// multiple coroutines at once), but it is safe to call Recv() and Send()
95 /// from different coroutines at once thus implementing full-duplex socket
96 /// connection.
97 virtual void Send(const Message& message) = 0;
98 virtual void SendText(std::string_view message) = 0;
99
100 template <typename ContiguousContainer>
101 void SendBinary(const ContiguousContainer& message) {
102 static_assert(
103 sizeof(typename ContiguousContainer::value_type) == 1, "SendBinary() should send either std::bytes or chars"
104 );
105 DoSendBinary(utils::span(
106 reinterpret_cast<const std::byte*>(message.data()),
107 reinterpret_cast<const std::byte*>(message.data() + message.size())
108 ));
109 }
110
111 virtual void Close(CloseStatus status_code) = 0;
112
113 virtual const engine::io::Sockaddr& RemoteAddr() const = 0;
114
115 virtual void AddFinalTags(tracing::Span& span) const = 0;
116 virtual void AddStatistics(Statistics& stats) const = 0;
117
118protected:
119 virtual void DoSendBinary(utils::span<const std::byte> message) = 0;
120};
121
122std::shared_ptr<WebSocketConnection>
123MakeWebSocket(std::unique_ptr<engine::io::RwBase>&& socket, engine::io::Sockaddr&& peer_name, const Config& config);
124
125} // namespace server::websocket
126
127USERVER_NAMESPACE_END