userver: userver/server/websocket/server.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
server.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/server/websocket/server.hpp
4/// @brief @copybrief server::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). It is **not** safe to call Recv() and Send() from different coroutines
80 /// at once if TLS is used. Consider using Send()+TryRecv() from the same coroutine instaead.
81 virtual void Recv(Message& message) = 0;
82
83 /// @brief Behaves in the same way as Recv(), but in case of first bytes of
84 /// message are not yet ready to receive gives the control up to a client.
85 /// @returns false in case of messages absence, otherwise true and behaves
86 /// like Recv()
87 virtual bool TryRecv(Message& message) = 0;
88
89 /// @brief Send a message to websocket.
90 /// @param message message to send
91 /// @throws engine::io::IoException in case of socket errors
92 /// @note Send() is not thread-safe by itself (you may not call Send() from
93 /// multiple coroutines at once). It is **not** safe to call Recv() and Send() from different coroutines
94 /// at once if TLS is used. Consider using Send()+TryRecv() from the same coroutine instaead.
95 virtual void Send(const Message& message) = 0;
96 virtual void SendText(std::string_view message) = 0;
97
98 template <typename ContiguousContainer>
99 void SendBinary(const ContiguousContainer& message) {
100 static_assert(
101 sizeof(typename ContiguousContainer::value_type) == 1, "SendBinary() should send either std::bytes or chars"
102 );
103 DoSendBinary(utils::span(
104 reinterpret_cast<const std::byte*>(message.data()),
105 reinterpret_cast<const std::byte*>(message.data() + message.size())
106 ));
107 }
108
109 virtual void Close(CloseStatus status_code) = 0;
110
111 virtual const engine::io::Sockaddr& RemoteAddr() const = 0;
112
113 virtual void AddFinalTags(tracing::Span& span) const = 0;
114 virtual void AddStatistics(Statistics& stats) const = 0;
115
116protected:
117 virtual void DoSendBinary(utils::span<const std::byte> message) = 0;
118};
119
120std::shared_ptr<WebSocketConnection>
121MakeWebSocket(std::unique_ptr<engine::io::RwBase>&& socket, engine::io::Sockaddr&& peer_name, const Config& config);
122
123} // namespace server::websocket
124
125USERVER_NAMESPACE_END