Skip to main content

actix_ws/codec/
json.rs

1use actix_web::web::Bytes;
2use bytestring::ByteString;
3use serde::{de::DeserializeOwned, Serialize};
4
5use super::{CodecMessage, EncodedMessage, MessageCodec};
6use crate::AggregatedMessage;
7
8/// JSON codec using `serde_json`.
9///
10/// By default, values are encoded as text frames.
11#[derive(Debug, Clone, Copy, Default)]
12pub struct JsonCodec {
13    send_mode: JsonSendMode,
14}
15
16#[derive(Debug, Clone, Copy, Default)]
17enum JsonSendMode {
18    #[default]
19    Text,
20    Binary,
21}
22
23impl JsonCodec {
24    /// Constructs a new JSON codec.
25    #[must_use]
26    pub fn new() -> Self {
27        Self::default()
28    }
29
30    /// Encodes outgoing values as WebSocket text frames (the default).
31    #[must_use]
32    pub fn text(mut self) -> Self {
33        self.send_mode = JsonSendMode::Text;
34        self
35    }
36
37    /// Encodes outgoing values as WebSocket binary frames.
38    ///
39    /// Incoming frames are still accepted as either text or binary.
40    #[must_use]
41    pub fn binary(mut self) -> Self {
42        self.send_mode = JsonSendMode::Binary;
43        self
44    }
45}
46
47impl<T> MessageCodec<T> for JsonCodec
48where
49    T: Serialize + DeserializeOwned,
50{
51    type Error = serde_json::Error;
52
53    fn encode(&self, item: &T) -> Result<EncodedMessage, Self::Error> {
54        match self.send_mode {
55            JsonSendMode::Text => {
56                let json = serde_json::to_string(item)?;
57                Ok(EncodedMessage::Text(ByteString::from(json)))
58            }
59            JsonSendMode::Binary => {
60                let json = serde_json::to_vec(item)?;
61                Ok(EncodedMessage::Binary(Bytes::from(json)))
62            }
63        }
64    }
65
66    fn decode(&self, msg: AggregatedMessage) -> Result<CodecMessage<T>, Self::Error> {
67        match msg {
68            AggregatedMessage::Text(text) => {
69                serde_json::from_str(text.as_ref()).map(CodecMessage::Item)
70            }
71            AggregatedMessage::Binary(bin) => serde_json::from_slice(&bin).map(CodecMessage::Item),
72            AggregatedMessage::Ping(bytes) => Ok(CodecMessage::Ping(bytes)),
73            AggregatedMessage::Pong(bytes) => Ok(CodecMessage::Pong(bytes)),
74            AggregatedMessage::Close(reason) => Ok(CodecMessage::Close(reason)),
75        }
76    }
77}