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
64 public:
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 Send a message to websocket.
85 /// @param message message to send
86 /// @throws engine::io::IoException in case of socket errors
87 /// @note Send() is not thread-safe by itself (you may not call Send() from
88 /// multiple coroutines at once), but it is safe to call Recv() and Send()
89 /// from different coroutines at once thus implementing full-duplex socket
90 /// connection.
91 virtual void Send(const Message& message) = 0;
92 virtual void SendText(std::string_view message) = 0;
93
94 template <typename ContiguousContainer>
95 void SendBinary(const ContiguousContainer& message) {
96 static_assert(sizeof(typename ContiguousContainer::value_type) == 1,
97 "SendBinary() should send either std::bytes or chars");
98 DoSendBinary(utils::span(
99 reinterpret_cast<const std::byte*>(message.data()),
100 reinterpret_cast<const std::byte*>(message.data() + message.size())));
101 }
102
103 virtual void Close(CloseStatus status_code) = 0;
104
105 virtual const engine::io::Sockaddr& RemoteAddr() const = 0;
106
107 virtual void AddFinalTags(tracing::Span& span) const = 0;
108 virtual void AddStatistics(Statistics& stats) const = 0;
109
110 protected:
111 virtual void DoSendBinary(utils::span<const std::byte> message) = 0;
112};
113
114std::shared_ptr<WebSocketConnection> MakeWebSocket(
115 std::unique_ptr<engine::io::RwBase>&& socket,
116 engine::io::Sockaddr&& peer_name, const Config& config);
117
118} // namespace server::websocket
119
120USERVER_NAMESPACE_END