rainier_websocket/
message.rs1use serde::Serialize;
4use serde_json::Value;
5
6use rainier_support::{Error, Result};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Message {
15 Text(String),
17 Binary(Vec<u8>),
19 Close(Option<String>),
25}
26
27impl Message {
28 pub fn text(body: impl Into<String>) -> Self {
30 Message::Text(body.into())
31 }
32
33 pub fn binary(body: impl Into<Vec<u8>>) -> Self {
35 Message::Binary(body.into())
36 }
37
38 pub fn json(value: &impl Serialize) -> Result<Self> {
41 serde_json::to_string(value)
42 .map(Message::Text)
43 .map_err(|e| Error::internal(format!("a socket message must serialise: {e}")))
44 }
45
46 pub fn as_text(&self) -> Option<&str> {
48 match self {
49 Message::Text(text) => Some(text),
50 _ => None,
51 }
52 }
53
54 pub fn as_bytes(&self) -> &[u8] {
56 match self {
57 Message::Text(text) => text.as_bytes(),
58 Message::Binary(bytes) => bytes,
59 Message::Close(reason) => reason.as_deref().unwrap_or("").as_bytes(),
60 }
61 }
62
63 pub fn parse_json(&self) -> Result<Value> {
68 let text = self
69 .as_text()
70 .ok_or_else(|| Error::bad_request("expected a text frame, got a binary one."))?;
71
72 serde_json::from_str(text)
73 .map_err(|e| Error::bad_request(format!("that is not valid JSON: {e}")))
74 }
75
76 pub fn is_close(&self) -> bool {
78 matches!(self, Message::Close(_))
79 }
80
81 pub fn len(&self) -> usize {
83 self.as_bytes().len()
84 }
85
86 pub fn is_empty(&self) -> bool {
88 self.len() == 0
89 }
90}
91
92impl From<&str> for Message {
93 fn from(text: &str) -> Self {
94 Message::text(text)
95 }
96}
97
98impl From<String> for Message {
99 fn from(text: String) -> Self {
100 Message::Text(text)
101 }
102}
103
104impl From<Vec<u8>> for Message {
105 fn from(bytes: Vec<u8>) -> Self {
106 Message::Binary(bytes)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn json_round_trips_through_a_text_frame() {
116 let message = Message::json(&serde_json::json!({ "room": 1 })).unwrap();
117
118 assert!(matches!(message, Message::Text(_)));
119 assert_eq!(message.parse_json().unwrap()["room"], 1);
120 }
121
122 #[test]
123 fn nonsense_from_a_client_is_a_bad_request_not_a_500() {
124 let err = Message::text("{not json").parse_json().unwrap_err();
125 assert_eq!(err.status(), 400, "{}", err.message());
126 }
127
128 #[test]
129 fn asking_a_binary_frame_for_json_says_which_kind_it_was() {
130 let err = Message::binary(vec![1, 2, 3]).parse_json().unwrap_err();
131 assert!(err.message().contains("binary"), "{}", err.message());
132 }
133}