nostr_types/types/
client_message.rs1use crate::types::{Event, Filter, SubscriptionId};
2use serde::de::Error as DeError;
3use serde::de::{Deserialize, Deserializer, IgnoredAny, SeqAccess, Visitor};
4use serde::ser::{Serialize, SerializeSeq, Serializer};
5use std::fmt;
6
7#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum ClientMessage {
10 Event(Box<Event>),
12
13 Req(SubscriptionId, Filter),
15
16 Close(SubscriptionId),
18
19 Auth(Box<Event>),
21
22 Count(SubscriptionId, Filter),
24
25 NegOpen(SubscriptionId, Filter, String),
27
28 NegMsg(SubscriptionId, String),
30
31 NegClose(SubscriptionId),
33}
34
35impl ClientMessage {
36 #[allow(dead_code)]
38 pub(crate) async fn mock() -> ClientMessage {
39 ClientMessage::Event(Box::new(Event::mock().await))
40 }
41}
42
43impl Serialize for ClientMessage {
44 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45 where
46 S: Serializer,
47 {
48 match self {
49 ClientMessage::Event(event) => {
50 let mut seq = serializer.serialize_seq(Some(2))?;
51 seq.serialize_element("EVENT")?;
52 seq.serialize_element(&event)?;
53 seq.end()
54 }
55 ClientMessage::Req(id, filter) => {
56 let mut seq = serializer.serialize_seq(Some(3))?;
57 seq.serialize_element("REQ")?;
58 seq.serialize_element(&id)?;
59 seq.serialize_element(&filter)?;
60 seq.end()
61 }
62 ClientMessage::Close(id) => {
63 let mut seq = serializer.serialize_seq(Some(2))?;
64 seq.serialize_element("CLOSE")?;
65 seq.serialize_element(&id)?;
66 seq.end()
67 }
68 ClientMessage::Auth(event) => {
69 let mut seq = serializer.serialize_seq(Some(2))?;
70 seq.serialize_element("AUTH")?;
71 seq.serialize_element(&event)?;
72 seq.end()
73 }
74 ClientMessage::Count(id, filter) => {
75 let mut seq = serializer.serialize_seq(Some(3))?;
76 seq.serialize_element("COUNT")?;
77 seq.serialize_element(&id)?;
78 seq.serialize_element(&filter)?;
79 seq.end()
80 }
81 ClientMessage::NegOpen(subid, filter, msg) => {
82 let mut seq = serializer.serialize_seq(Some(4))?;
83 seq.serialize_element("NEG-OPEN")?;
84 seq.serialize_element(&subid)?;
85 seq.serialize_element(&filter)?;
86 seq.serialize_element(&msg)?;
87 seq.end()
88 }
89 ClientMessage::NegMsg(subid, msg) => {
90 let mut seq = serializer.serialize_seq(Some(3))?;
91 seq.serialize_element("NEG-MSG")?;
92 seq.serialize_element(&subid)?;
93 seq.serialize_element(&msg)?;
94 seq.end()
95 }
96 ClientMessage::NegClose(subid) => {
97 let mut seq = serializer.serialize_seq(Some(2))?;
98 seq.serialize_element("NEG-CLOSE")?;
99 seq.serialize_element(&subid)?;
100 seq.end()
101 }
102 }
103 }
104}
105
106impl<'de> Deserialize<'de> for ClientMessage {
107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108 where
109 D: Deserializer<'de>,
110 {
111 deserializer.deserialize_seq(ClientMessageVisitor)
112 }
113}
114
115struct ClientMessageVisitor;
116
117impl<'de> Visitor<'de> for ClientMessageVisitor {
118 type Value = ClientMessage;
119
120 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 write!(f, "a sequence of strings")
122 }
123
124 fn visit_seq<A>(self, mut seq: A) -> Result<ClientMessage, A::Error>
125 where
126 A: SeqAccess<'de>,
127 {
128 let word: &str = seq
129 .next_element()?
130 .ok_or_else(|| DeError::custom("Message missing initial string field"))?;
131 let mut output: Option<ClientMessage> = None;
132 if word == "EVENT" {
133 let event: Event = seq
134 .next_element()?
135 .ok_or_else(|| DeError::custom("Message missing event field"))?;
136 output = Some(ClientMessage::Event(Box::new(event)))
137 } else if word == "REQ" {
138 let id: SubscriptionId = seq
139 .next_element()?
140 .ok_or_else(|| DeError::custom("Message missing id field"))?;
141 let filter: Filter = seq
142 .next_element()?
143 .ok_or_else(|| DeError::custom("Message missing filter field"))?;
144 output = Some(ClientMessage::Req(id, filter))
145 } else if word == "COUNT" {
146 let id: SubscriptionId = seq
147 .next_element()?
148 .ok_or_else(|| DeError::custom("Message missing filter field"))?;
149 let filter: Filter = seq
150 .next_element()?
151 .ok_or_else(|| DeError::custom("Message missing filter field"))?;
152 output = Some(ClientMessage::Count(id, filter))
153 } else if word == "CLOSE" {
154 let id: SubscriptionId = seq
155 .next_element()?
156 .ok_or_else(|| DeError::custom("Message missing id field"))?;
157 output = Some(ClientMessage::Close(id))
158 } else if word == "AUTH" {
159 let event: Event = seq
160 .next_element()?
161 .ok_or_else(|| DeError::custom("Message missing event field"))?;
162 output = Some(ClientMessage::Auth(Box::new(event)))
163 } else if word == "NEG-OPEN" {
164 let id: SubscriptionId = seq
165 .next_element()?
166 .ok_or_else(|| DeError::custom("Message missing id field"))?;
167 let filter: Filter = seq
168 .next_element()?
169 .ok_or_else(|| DeError::custom("Message missing filter"))?;
170 let msg: String = seq
171 .next_element()?
172 .ok_or_else(|| DeError::custom("Message missing message"))?;
173 output = Some(ClientMessage::NegOpen(id, filter, msg))
174 } else if word == "NEG-MSG" {
175 let id: SubscriptionId = seq
176 .next_element()?
177 .ok_or_else(|| DeError::custom("Message missing id field"))?;
178 let msg: String = seq
179 .next_element()?
180 .ok_or_else(|| DeError::custom("Message missing message"))?;
181 output = Some(ClientMessage::NegMsg(id, msg))
182 } else if word == "NEG-CLOSE" {
183 let id: SubscriptionId = seq
184 .next_element()?
185 .ok_or_else(|| DeError::custom("Message missing id field"))?;
186 output = Some(ClientMessage::NegClose(id))
187 }
188
189 while let Some(_ignored) = seq.next_element::<IgnoredAny>()? {}
191
192 match output {
193 Some(cm) => Ok(cm),
194 None => Err(DeError::custom(format!("Unknown Message: {word}"))),
195 }
196 }
197}
198
199#[cfg(test)]
200mod test {
201 use super::*;
202 use crate::Event;
203
204 test_serde_async! {ClientMessage, test_client_message_serde}
205
206 test_serde_val_async! {
207 test_client_message_serde_event,
208 ClientMessage::Event(Box::new(Event::mock().await))
209 }
210 test_serde_val! {
211 test_client_message_serde_req,
212 ClientMessage::Req(SubscriptionId::mock(), Filter::mock())
213 }
214 test_serde_val! {
215 test_client_message_serde_close,
216 ClientMessage::Close(SubscriptionId::mock())
217 }
218 test_serde_val_async! {
219 test_client_message_serde_auth,
220 ClientMessage::Auth(Box::new(Event::mock().await))
221 }
222 test_serde_val! {
223 test_client_message_serde_negopen,
224 ClientMessage::NegOpen(SubscriptionId::mock(), Filter::mock(), "dummy".to_string())
225 }
226 test_serde_val! {
227 test_client_message_serde_negmsg,
228 ClientMessage::NegMsg(SubscriptionId::mock(), "dummy".to_string())
229 }
230 test_serde_val! {
231 test_client_message_serde_negclose,
232 ClientMessage::NegClose(SubscriptionId::mock())
233 }
234}