1use bitflags::bitflags;
2use bytes::{Bytes, BytesMut};
3use bytestring::ByteString;
4use tokio_util::codec::{Decoder, Encoder};
5
6use super::{
7 frame::Parser,
8 proto::{CloseReason, OpCode},
9 ProtocolError,
10};
11
12#[derive(Debug, PartialEq, Eq)]
14pub enum Message {
15 Text(ByteString),
17
18 Binary(Bytes),
20
21 Continuation(Item),
23
24 Ping(Bytes),
26
27 Pong(Bytes),
29
30 Close(Option<CloseReason>),
32
33 Nop,
35}
36
37#[derive(Debug, PartialEq, Eq)]
39pub enum Frame {
40 Text(Bytes),
42
43 Binary(Bytes),
45
46 Continuation(Item),
48
49 Ping(Bytes),
51
52 Pong(Bytes),
54
55 Close(Option<CloseReason>),
57}
58
59#[derive(Debug, PartialEq, Eq)]
61pub enum Item {
62 FirstText(Bytes),
63 FirstBinary(Bytes),
64 Continue(Bytes),
65 Last(Bytes),
66}
67
68#[derive(Debug, Clone)]
70pub struct Codec {
71 flags: Flags,
72 max_size: usize,
73}
74
75bitflags! {
76 #[derive(Debug, Clone, Copy)]
77 struct Flags: u8 {
78 const SERVER = 0b0000_0001;
79 const CONTINUATION = 0b0000_0010;
80 const W_CONTINUATION = 0b0000_0100;
81 }
82}
83
84impl Codec {
85 pub const fn new() -> Codec {
87 Codec {
88 max_size: 65_536,
89 flags: Flags::SERVER,
90 }
91 }
92
93 #[must_use = "This returns the a new Codec, without modifying the original."]
97 pub fn max_size(mut self, size: usize) -> Self {
98 self.max_size = size;
99 self
100 }
101
102 #[must_use = "This returns the a new Codec, without modifying the original."]
106 pub fn client_mode(mut self) -> Self {
107 self.flags.remove(Flags::SERVER);
108 self
109 }
110}
111
112impl Default for Codec {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118impl Encoder<Message> for Codec {
119 type Error = ProtocolError;
120
121 fn encode(&mut self, item: Message, dst: &mut BytesMut) -> Result<(), Self::Error> {
122 match item {
123 Message::Text(txt) => Parser::write_message(
124 dst,
125 txt,
126 OpCode::Text,
127 true,
128 !self.flags.contains(Flags::SERVER),
129 ),
130 Message::Binary(bin) => Parser::write_message(
131 dst,
132 bin,
133 OpCode::Binary,
134 true,
135 !self.flags.contains(Flags::SERVER),
136 ),
137 Message::Ping(txt) => Parser::write_message(
138 dst,
139 txt,
140 OpCode::Ping,
141 true,
142 !self.flags.contains(Flags::SERVER),
143 ),
144 Message::Pong(txt) => Parser::write_message(
145 dst,
146 txt,
147 OpCode::Pong,
148 true,
149 !self.flags.contains(Flags::SERVER),
150 ),
151 Message::Close(reason) => {
152 Parser::write_close(dst, reason, !self.flags.contains(Flags::SERVER))
153 }
154 Message::Continuation(cont) => match cont {
155 Item::FirstText(data) => {
156 if self.flags.contains(Flags::W_CONTINUATION) {
157 return Err(ProtocolError::ContinuationStarted);
158 } else {
159 self.flags.insert(Flags::W_CONTINUATION);
160 Parser::write_message(
161 dst,
162 &data[..],
163 OpCode::Text,
164 false,
165 !self.flags.contains(Flags::SERVER),
166 )
167 }
168 }
169 Item::FirstBinary(data) => {
170 if self.flags.contains(Flags::W_CONTINUATION) {
171 return Err(ProtocolError::ContinuationStarted);
172 } else {
173 self.flags.insert(Flags::W_CONTINUATION);
174 Parser::write_message(
175 dst,
176 &data[..],
177 OpCode::Binary,
178 false,
179 !self.flags.contains(Flags::SERVER),
180 )
181 }
182 }
183 Item::Continue(data) => {
184 if self.flags.contains(Flags::W_CONTINUATION) {
185 Parser::write_message(
186 dst,
187 &data[..],
188 OpCode::Continue,
189 false,
190 !self.flags.contains(Flags::SERVER),
191 )
192 } else {
193 return Err(ProtocolError::ContinuationNotStarted);
194 }
195 }
196 Item::Last(data) => {
197 if self.flags.contains(Flags::W_CONTINUATION) {
198 self.flags.remove(Flags::W_CONTINUATION);
199 Parser::write_message(
200 dst,
201 &data[..],
202 OpCode::Continue,
203 true,
204 !self.flags.contains(Flags::SERVER),
205 )
206 } else {
207 return Err(ProtocolError::ContinuationNotStarted);
208 }
209 }
210 },
211 Message::Nop => {}
212 }
213 Ok(())
214 }
215}
216
217impl Decoder for Codec {
218 type Item = Frame;
219 type Error = ProtocolError;
220
221 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
222 let Some((finished, opcode, payload)) =
223 Parser::parse(src, self.flags.contains(Flags::SERVER), self.max_size)?
224 else {
225 return Ok(None);
226 };
227
228 if !finished {
229 return match opcode {
230 OpCode::Continue => {
232 if self.flags.contains(Flags::CONTINUATION) {
233 Ok(Some(Frame::Continuation(Item::Continue(
234 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
235 ))))
236 } else {
237 Err(ProtocolError::ContinuationNotStarted)
238 }
239 }
240 OpCode::Binary => {
241 if !self.flags.contains(Flags::CONTINUATION) {
242 self.flags.insert(Flags::CONTINUATION);
243 Ok(Some(Frame::Continuation(Item::FirstBinary(
244 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
245 ))))
246 } else {
247 Err(ProtocolError::ContinuationStarted)
248 }
249 }
250 OpCode::Text => {
251 if !self.flags.contains(Flags::CONTINUATION) {
252 self.flags.insert(Flags::CONTINUATION);
253 Ok(Some(Frame::Continuation(Item::FirstText(
254 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
255 ))))
256 } else {
257 Err(ProtocolError::ContinuationStarted)
258 }
259 }
260 _ => {
261 tracing::error!("Unfinished fragment {opcode:?}");
262 Err(ProtocolError::ContinuationFragment(opcode))
263 }
264 };
265 }
266
267 match opcode {
268 OpCode::Continue => {
269 if self.flags.contains(Flags::CONTINUATION) {
270 self.flags.remove(Flags::CONTINUATION);
271 Ok(Some(Frame::Continuation(Item::Last(
272 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
273 ))))
274 } else {
275 Err(ProtocolError::ContinuationNotStarted)
276 }
277 }
278 OpCode::Bad => Err(ProtocolError::BadOpCode),
279 OpCode::Close => {
280 if let Some(ref pl) = payload {
281 let close_reason = Parser::try_parse_close_payload(pl)?;
282 Ok(Some(Frame::Close(close_reason)))
283 } else {
284 Ok(Some(Frame::Close(None)))
285 }
286 }
287 OpCode::Ping => Ok(Some(Frame::Ping(
288 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
289 ))),
290 OpCode::Pong => Ok(Some(Frame::Pong(
291 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
292 ))),
293 OpCode::Binary => {
294 if self.flags.contains(Flags::CONTINUATION) {
295 Err(ProtocolError::ContinuationStarted)
296 } else {
297 Ok(Some(Frame::Binary(
298 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
299 )))
300 }
301 }
302 OpCode::Text => {
303 if self.flags.contains(Flags::CONTINUATION) {
304 Err(ProtocolError::ContinuationStarted)
305 } else {
306 Ok(Some(Frame::Text(
307 payload.map(|pl| pl.freeze()).unwrap_or_else(Bytes::new),
308 )))
309 }
310 }
311 }
312 }
313}