nostr_types/types/
client_message.rs

1use 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/// A message from a client to a relay
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum ClientMessage {
10    /// An event
11    Event(Box<Event>),
12
13    /// A subscription request
14    Req(SubscriptionId, Filter),
15
16    /// A request to close a subscription
17    Close(SubscriptionId),
18
19    /// Used to send authentication events
20    Auth(Box<Event>),
21
22    /// Count
23    Count(SubscriptionId, Filter),
24
25    /// Negentropy Initiation
26    NegOpen(SubscriptionId, Filter, String),
27
28    /// Negentropy Message
29    NegMsg(SubscriptionId, String),
30
31    /// Negentropy Close
32    NegClose(SubscriptionId),
33}
34
35impl ClientMessage {
36    // Mock data for testing
37    #[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        // Consume any trailing fields
190        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}