message.rs (9017B)
1 use crate::Error; 2 use crate::Event; 3 use crate::Result; 4 use serde_json::Value; 5 6 use ewebsock::{WsEvent, WsMessage}; 7 8 #[derive(Debug, Eq, PartialEq)] 9 pub struct CommandResult { 10 event_id: String, 11 status: bool, 12 message: String, 13 } 14 15 #[derive(Debug, Eq, PartialEq)] 16 pub enum RelayMessage { 17 OK(CommandResult), 18 Eose(String), 19 Event(String, Event), 20 Notice(String), 21 } 22 23 #[derive(Debug)] 24 pub enum RelayEvent { 25 Opened, 26 Closed, 27 Other(WsMessage), 28 Message(RelayMessage), 29 } 30 31 impl TryFrom<WsEvent> for RelayEvent { 32 type Error = Error; 33 34 fn try_from(message: WsEvent) -> Result<Self> { 35 match message { 36 WsEvent::Opened => Ok(RelayEvent::Opened), 37 WsEvent::Closed => Ok(RelayEvent::Closed), 38 WsEvent::Message(ws_msg) => ws_msg.try_into(), 39 WsEvent::Error(s) => Err(s.into()), 40 } 41 } 42 } 43 44 impl TryFrom<WsMessage> for RelayEvent { 45 type Error = Error; 46 47 fn try_from(wsmsg: WsMessage) -> Result<Self> { 48 match wsmsg { 49 WsMessage::Text(s) => RelayMessage::from_json(&s).map(RelayEvent::Message), 50 wsmsg => Ok(RelayEvent::Other(wsmsg)), 51 } 52 } 53 } 54 55 impl RelayMessage { 56 pub fn eose(subid: String) -> Self { 57 RelayMessage::Eose(subid) 58 } 59 60 pub fn notice(msg: String) -> Self { 61 RelayMessage::Notice(msg) 62 } 63 64 pub fn ok(event_id: String, status: bool, message: String) -> Self { 65 RelayMessage::OK(CommandResult { 66 event_id: event_id, 67 status, 68 message: message, 69 }) 70 } 71 72 pub fn event(ev: Event, sub_id: String) -> Self { 73 RelayMessage::Event(sub_id, ev) 74 } 75 76 // I was lazy and took this from the nostr crate. thx yuki! 77 pub fn from_json(msg: &str) -> Result<Self> { 78 if msg.is_empty() { 79 return Err(Error::MessageEmpty); 80 } 81 82 let v: Vec<Value> = serde_json::from_str(msg).map_err(|_| Error::MessageDecodeFailed)?; 83 84 // Notice 85 // Relay response format: ["NOTICE", <message>] 86 if v[0] == "NOTICE" { 87 if v.len() != 2 { 88 return Err(Error::MessageDecodeFailed); 89 } 90 let v_notice: String = 91 serde_json::from_value(v[1].clone()).map_err(|_| Error::MessageDecodeFailed)?; 92 return Ok(Self::notice(v_notice)); 93 } 94 95 // Event 96 // Relay response format: ["EVENT", <subscription id>, <event JSON>] 97 if v[0] == "EVENT" { 98 if v.len() != 3 { 99 return Err(Error::MessageDecodeFailed); 100 } 101 102 let event = 103 Event::from_json(&v[2].to_string()).map_err(|_| Error::MessageDecodeFailed)?; 104 105 let subscription_id: String = 106 serde_json::from_value(v[1].clone()).map_err(|_| Error::MessageDecodeFailed)?; 107 108 return Ok(Self::event(event, subscription_id)); 109 } 110 111 // EOSE (NIP-15) 112 // Relay response format: ["EOSE", <subscription_id>] 113 if v[0] == "EOSE" { 114 if v.len() != 2 { 115 return Err(Error::MessageDecodeFailed); 116 } 117 118 let subscription_id: String = 119 serde_json::from_value(v[1].clone()).map_err(|_| Error::MessageDecodeFailed)?; 120 121 return Ok(Self::eose(subscription_id)); 122 } 123 124 // OK (NIP-20) 125 // Relay response format: ["OK", <event_id>, <true|false>, <message>] 126 if v[0] == "OK" { 127 if v.len() != 4 { 128 return Err(Error::MessageDecodeFailed); 129 } 130 131 let event_id: String = 132 serde_json::from_value(v[1].clone()).map_err(|_| Error::MessageDecodeFailed)?; 133 134 let status: bool = 135 serde_json::from_value(v[2].clone()).map_err(|_| Error::MessageDecodeFailed)?; 136 137 let message: String = 138 serde_json::from_value(v[3].clone()).map_err(|_| Error::MessageDecodeFailed)?; 139 140 return Ok(Self::ok(event_id, status, message)); 141 } 142 143 Err(Error::MessageDecodeFailed) 144 } 145 } 146 147 #[cfg(test)] 148 mod tests { 149 use super::*; 150 151 #[test] 152 fn test_handle_valid_notice() -> Result<()> { 153 let valid_notice_msg = r#"["NOTICE","Invalid event format!"]"#; 154 let handled_valid_notice_msg = RelayMessage::notice("Invalid event format!".to_string()); 155 156 assert_eq!( 157 RelayMessage::from_json(valid_notice_msg)?, 158 handled_valid_notice_msg 159 ); 160 161 Ok(()) 162 } 163 #[test] 164 fn test_handle_invalid_notice() { 165 //Missing content 166 let invalid_notice_msg = r#"["NOTICE"]"#; 167 //The content is not string 168 let invalid_notice_msg_content = r#"["NOTICE": 404]"#; 169 170 assert_eq!( 171 RelayMessage::from_json(invalid_notice_msg).unwrap_err(), 172 Error::MessageDecodeFailed 173 ); 174 assert_eq!( 175 RelayMessage::from_json(invalid_notice_msg_content).unwrap_err(), 176 Error::MessageDecodeFailed 177 ); 178 } 179 180 #[test] 181 fn test_handle_valid_event() -> Result<()> { 182 let valid_event_msg = r#"["EVENT", "random_string", {"id":"70b10f70c1318967eddf12527799411b1a9780ad9c43858f5e5fcd45486a13a5","pubkey":"379e863e8357163b5bce5d2688dc4f1dcc2d505222fb8d74db600f30535dfdfe","created_at":1612809991,"kind":1,"tags":[],"content":"test","sig":"273a9cd5d11455590f4359500bccb7a89428262b96b3ea87a756b770964472f8c3e87f5d5e64d8d2e859a71462a3f477b554565c4f2f326cb01dd7620db71502"}]"#; 183 184 let id = "70b10f70c1318967eddf12527799411b1a9780ad9c43858f5e5fcd45486a13a5"; 185 let pubkey = "379e863e8357163b5bce5d2688dc4f1dcc2d505222fb8d74db600f30535dfdfe"; 186 let created_at = 1612809991; 187 let kind = 1; 188 let tags = vec![]; 189 let content = "test"; 190 let sig = "273a9cd5d11455590f4359500bccb7a89428262b96b3ea87a756b770964472f8c3e87f5d5e64d8d2e859a71462a3f477b554565c4f2f326cb01dd7620db71502"; 191 192 let handled_event = Event::new_dummy(id, pubkey, created_at, kind, tags, content, sig); 193 194 assert_eq!( 195 RelayMessage::from_json(valid_event_msg)?, 196 RelayMessage::event(handled_event?, "random_string".to_string()) 197 ); 198 199 Ok(()) 200 } 201 202 #[test] 203 fn test_handle_invalid_event() { 204 //Mising Event field 205 let invalid_event_msg = r#"["EVENT", "random_string"]"#; 206 //Event JSON with incomplete content 207 let invalid_event_msg_content = r#"["EVENT", "random_string", {"id":"70b10f70c1318967eddf12527799411b1a9780ad9c43858f5e5fcd45486a13a5","pubkey":"379e863e8357163b5bce5d2688dc4f1dcc2d505222fb8d74db600f30535dfdfe"}]"#; 208 209 assert_eq!( 210 RelayMessage::from_json(invalid_event_msg).unwrap_err(), 211 Error::MessageDecodeFailed 212 ); 213 214 assert_eq!( 215 RelayMessage::from_json(invalid_event_msg_content).unwrap_err(), 216 Error::MessageDecodeFailed 217 ); 218 } 219 220 #[test] 221 fn test_handle_valid_eose() -> Result<()> { 222 let valid_eose_msg = r#"["EOSE","random-subscription-id"]"#; 223 let handled_valid_eose_msg = RelayMessage::eose("random-subscription-id".to_string()); 224 225 assert_eq!( 226 RelayMessage::from_json(valid_eose_msg)?, 227 handled_valid_eose_msg 228 ); 229 230 Ok(()) 231 } 232 #[test] 233 fn test_handle_invalid_eose() { 234 // Missing subscription ID 235 assert_eq!( 236 RelayMessage::from_json(r#"["EOSE"]"#).unwrap_err(), 237 Error::MessageDecodeFailed 238 ); 239 240 // The subscription ID is not string 241 assert_eq!( 242 RelayMessage::from_json(r#"["EOSE", 404]"#).unwrap_err(), 243 Error::MessageDecodeFailed 244 ); 245 } 246 247 #[test] 248 fn test_handle_valid_ok() -> Result<()> { 249 let valid_ok_msg = r#"["OK", "b1a649ebe8b435ec71d3784793f3bbf4b93e64e17568a741aecd4c7ddeafce30", true, "pow: difficulty 25>=24"]"#; 250 let handled_valid_ok_msg = RelayMessage::ok( 251 "b1a649ebe8b435ec71d3784793f3bbf4b93e64e17568a741aecd4c7ddeafce30".to_string(), 252 true, 253 "pow: difficulty 25>=24".into(), 254 ); 255 256 assert_eq!(RelayMessage::from_json(valid_ok_msg)?, handled_valid_ok_msg); 257 258 Ok(()) 259 } 260 #[test] 261 fn test_handle_invalid_ok() { 262 // Missing params 263 assert_eq!( 264 RelayMessage::from_json( 265 r#"["OK", "b1a649ebe8b435ec71d3784793f3bbf4b93e64e17568a741aecd4c7ddeafce30"]"# 266 ) 267 .unwrap_err(), 268 Error::MessageDecodeFailed 269 ); 270 271 // Invalid status 272 assert_eq!( 273 RelayMessage::from_json(r#"["OK", "b1a649ebe8b435ec71d3784793f3bbf4b93e64e17568a741aecd4c7ddeafce30", hello, ""]"#).unwrap_err(), 274 Error::MessageDecodeFailed 275 ); 276 277 // Invalid message 278 assert_eq!( 279 RelayMessage::from_json(r#"["OK", "b1a649ebe8b435ec71d3784793f3bbf4b93e64e17568a741aecd4c7ddeafce30", hello, 404]"#).unwrap_err(), 280 Error::MessageDecodeFailed 281 ); 282 } 283 }