web_socket/lib.rs
1#![doc(html_logo_url = "https://cdn.worldvectorlogo.com/logos/websocket.svg")]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4
5mod frame;
6mod ws;
7#[doc(hidden)]
8pub use frame::Frame;
9pub use ws::WebSocket;
10
11/// Two roles that can be played by a WebSocket connection: `Server` and `Client`.
12#[derive(Debug)]
13pub enum Role {
14 /// Represent websocket server instance.
15 Server,
16 /// Represent websocket client instance.
17 Client,
18}
19
20/// It represent the type of data that is being sent over the WebSocket connection.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum MessageType {
23 /// `Text` data is represented as a sequence of Unicode characters encoded using UTF-8 encoding.
24 Text = 1,
25 /// `Binary` data can be any sequence of bytes and is typically used for sending non-textual data, such as images, audio files etc...
26 Binary = 2,
27}
28
29impl MessageType {
30 /// Returns `true` if message type is text
31 #[inline]
32 pub fn is_text(&self) -> bool {
33 matches!(self, MessageType::Text)
34 }
35
36 /// Returns `true` if message type is binary
37 #[inline]
38 pub fn is_binary(&self) -> bool {
39 matches!(self, MessageType::Binary)
40 }
41}
42
43/// Represents a fragment of a WebSocket message.
44#[derive(Debug, Clone)]
45pub enum Stream {
46 /// Indicates tCopyhe start of a new message fragment of the given [MessageType].
47 Start(MessageType),
48 /// Indicates the continuation of the current message fragment.
49 Next(MessageType),
50 /// Indicates the end of the current message fragment.
51 End(MessageType),
52}
53
54impl Stream {
55 /// Get [MessageType] from [Stream]
56 #[inline]
57 pub fn ty(&self) -> MessageType {
58 match *self {
59 Stream::Start(ty) => ty,
60 Stream::Next(ty) => ty,
61 Stream::End(ty) => ty,
62 }
63 }
64}
65
66/// Data that is either complete or fragmented.
67#[derive(Debug, Clone)]
68pub enum DataType {
69 /// The message is split into fragments, each of which is sent as a separate
70 /// WebSocket message with the [Fragment] variant.
71 Stream(Stream),
72 /// A complete WebSocket message in a single transmission.
73 Complete(MessageType),
74}
75
76#[derive(Debug)]
77/// Represent a websocket event
78pub enum Event {
79 /// Websocket data frame.
80 Data {
81 /// Represents WebSocket [DataType], Either complete or fragmented
82 ty: DataType,
83 /// Payload, represented as bytes.
84 data: Box<[u8]>,
85 },
86
87 /// A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive.
88 ///
89 /// And SHOULD respond with Pong frame as soon as is practical.
90 Ping(Box<[u8]>),
91
92 /// A Pong frame sent in response to a Ping frame must have identical
93 /// "Application data" as found in the message body of the Ping frame being replied to.
94 ///
95 /// If an endpoint receives a Ping frame and has not yet sent Pong frame(s) in response to previous Ping frame(s), the endpoint MAY
96 /// elect to send a Pong frame for only the most recently processed Ping frame.
97 ///
98 /// A Pong frame MAY be sent unsolicited. This serves as a unidirectional heartbeat. A response to an unsolicited Pong frame is not expected.
99 Pong(Box<[u8]>),
100
101 /// represents the websocket error message.
102 Error(&'static str),
103
104 /// represents a successful close event of the WebSocket connection.
105 Close {
106 /// represents the status [CloseCode] of the close event.
107 code: u16,
108 /// represents the reason for the close event
109 reason: Box<str>,
110 },
111}
112
113/// When closing an established connection an endpoint MAY indicate a reason for closure.
114#[derive(Debug, Clone, Copy)]
115pub enum CloseCode {
116 /// The purpose for which the connection was established has been fulfilled
117 Normal = 1000,
118 /// Server going down or a browser having navigated away from a page
119 Away = 1001,
120 /// An endpoint is terminating the connection due to a protocol error.
121 ProtocolError = 1002,
122 /// It has received a type of data it cannot accept
123 Unsupported = 1003,
124
125 // reserved 1004
126 /// MUST NOT be set as a status code in a Close control frame by an endpoint.
127 ///
128 /// No status code was actually present.
129 NoStatusRcvd = 1005,
130 /// MUST NOT be set as a status code in a Close control frame by an endpoint.
131 ///
132 /// Connection was closed abnormally.
133 Abnormal = 1006,
134 /// Application has received data within a message that was not consistent with the type of the message.
135 InvalidPayload = 1007,
136 /// This is a generic status code that can be returned when there is no other more suitable status code.
137 PolicyViolation = 1008,
138 /// Message that is too big for it to process.
139 MessageTooBig = 1009,
140 /// It has expected the server to negotiate one or more extension.
141 MandatoryExt = 1010,
142 /// The server has encountered an unexpected condition that prevented it from fulfilling the request.
143 InternalError = 1011,
144 /// MUST NOT be set as a status code in a Close control frame by an endpoint.
145 ///
146 /// The connection was closed due to a failure to perform a TLS handshake.
147 TLSHandshake = 1015,
148}
149
150impl From<CloseCode> for u16 {
151 #[inline]
152 fn from(code: CloseCode) -> Self {
153 code as u16
154 }
155}
156
157impl From<u16> for CloseCode {
158 #[inline]
159 fn from(value: u16) -> Self {
160 match value {
161 1000 => CloseCode::Normal,
162 1001 => CloseCode::Away,
163 1002 => CloseCode::ProtocolError,
164 1003 => CloseCode::Unsupported,
165 1005 => CloseCode::NoStatusRcvd,
166 1006 => CloseCode::Abnormal,
167 1007 => CloseCode::InvalidPayload,
168 1009 => CloseCode::MessageTooBig,
169 1010 => CloseCode::MandatoryExt,
170 1011 => CloseCode::InternalError,
171 1015 => CloseCode::TLSHandshake,
172 _ => CloseCode::PolicyViolation,
173 }
174 }
175}
176
177impl PartialEq<u16> for CloseCode {
178 #[inline]
179 fn eq(&self, other: &u16) -> bool {
180 (*self as u16) == *other
181 }
182}
183
184/// This trait is responsible for encoding websocket closed frame.
185pub trait CloseReason {
186 /// Encoded close reason as bytes
187 type Bytes;
188 /// Encode websocket close frame.
189 fn to_bytes(self) -> Self::Bytes;
190}
191
192impl CloseReason for () {
193 type Bytes = [u8; 0];
194 fn to_bytes(self) -> Self::Bytes {
195 [0; 0]
196 }
197}
198
199impl CloseReason for u16 {
200 type Bytes = [u8; 2];
201 fn to_bytes(self) -> Self::Bytes {
202 self.to_be_bytes()
203 }
204}
205
206impl CloseReason for CloseCode {
207 type Bytes = [u8; 2];
208 fn to_bytes(self) -> Self::Bytes {
209 (self as u16).to_be_bytes()
210 }
211}
212
213impl CloseReason for &str {
214 type Bytes = Vec<u8>;
215 fn to_bytes(self) -> Self::Bytes {
216 CloseReason::to_bytes((CloseCode::Normal, self))
217 }
218}
219
220impl<Code, Msg> CloseReason for (Code, Msg)
221where
222 Code: Into<u16>,
223 Msg: AsRef<[u8]>,
224{
225 type Bytes = Vec<u8>;
226 fn to_bytes(self) -> Self::Bytes {
227 let (code, reason) = (self.0.into(), self.1.as_ref());
228 let mut data = Vec::with_capacity(2 + reason.len());
229 data.extend_from_slice(&code.to_be_bytes());
230 data.extend_from_slice(reason);
231 data
232 }
233}