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 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 instead.
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 instead.
95 virtual void Send(const Message& message) = 0;
96 virtual void SendText(std::string_view message) = 0;
97
98 /// @brief Send a ping message to websocket.
99 /// @throws engine::io::IoException in case of socket errors
100 virtual void SendPing() = 0;
101
102 /// @brief Get the number of not answered sequential pings;
103 /// calls to SendPing() increment this value, Recv and TryRecv
104 /// reset this value if some 'pong' is received.
105 /// @returns the number of not answered sequential pings
106 virtual std::size_t NotAnsweredSequentialPingsCount() = 0;
107
108 template <typename ContiguousContainer>
109 void SendBinary(const ContiguousContainer& message) {
110 static_assert(
111 sizeof(typename ContiguousContainer::value_type) == 1,
112 "SendBinary() should send either std::bytes or chars"
113 );
114 DoSendBinary(utils::span(
115 reinterpret_cast<const std::byte*>(message.data()),
116 reinterpret_cast<const std::byte*>(message.data() + message.size())
117 ));
118 }
119
120 virtual void Close(CloseStatus status_code) = 0;
121
122 virtual const engine::io::Sockaddr& RemoteAddr() const = 0;
123
124 virtual void AddFinalTags(tracing::Span& span) const = 0;
125 virtual void AddStatistics(Statistics& stats) const = 0;
126
127protected:
128 virtual void DoSendBinary(utils::span<const std::byte> message) = 0;
129};
130
131std::shared_ptr<WebSocketConnection> MakeWebSocket(
132 std::unique_ptr<engine::io::RwBase>&& socket,
133 engine::io::Sockaddr&& peer_name,
134 const Config& config
135);
136
137} // namespace server::websocket
138
139USERVER_NAMESPACE_END