|
@@ -1,28 +1,49 @@
|
|
|
+//! # Nostr Protocol Types
|
|
|
+//!
|
|
|
+//! The types needed to interact with a Nostr relayer, or to be become one.
|
|
|
+//#![deny(missing_docs, warnings)]
|
|
|
+
|
|
|
use serde::{
|
|
|
de::{self, Deserializer},
|
|
|
Deserialize, Serialize,
|
|
|
};
|
|
|
use std::convert::TryFrom;
|
|
|
-use thiserror::Error;
|
|
|
use types::{Event, SubscriptionId};
|
|
|
|
|
|
pub mod client;
|
|
|
pub mod types;
|
|
|
|
|
|
-#[derive(Debug, Error)]
|
|
|
-pub enum Error {}
|
|
|
-
|
|
|
#[derive(Serialize, Debug, Clone)]
|
|
|
+/// Message
|
|
|
+///
|
|
|
+/// All the messages needed to interact with a Nostr protocol, are abstracted in
|
|
|
+/// this structure.
|
|
|
+///
|
|
|
+/// This Message can be used to compose messages to communicate with a relayer,
|
|
|
+/// or by a relayer to parse messages from a client
|
|
|
pub enum Message {
|
|
|
+ /// Close a subscription
|
|
|
Close(types::SubscriptionId),
|
|
|
+ /// An Event from a client. This is when a client wants to publish an
|
|
|
+ /// event. The event must be signed.
|
|
|
EventFromClient(types::Event),
|
|
|
- EventFromServer(types::SubscriptionId, types::Event),
|
|
|
+ /// The relayer sends an event. This happens when an event matches
|
|
|
+ /// subscription that was created by a request
|
|
|
+ EventFromRelayer(types::SubscriptionId, types::Event),
|
|
|
+ /// Creates a subscription. Client tells the relayer which kind of events
|
|
|
+ /// they'd like to hear about
|
|
|
Request(client::Request),
|
|
|
+ /// This is how server communicates about errors (most likely protocol
|
|
|
+ /// errors) to the client
|
|
|
Notice(String),
|
|
|
+ /// The relayer sent all the events that matches your request already, from
|
|
|
+ /// now on, new events will be relayed as they appear and matches your
|
|
|
+ /// request
|
|
|
EndOfStoredEvents(String),
|
|
|
}
|
|
|
|
|
|
impl Message {
|
|
|
+ /// Returns the current message as a Request, if possible
|
|
|
pub fn as_request(&self) -> Option<&client::Request> {
|
|
|
match self {
|
|
|
Self::Request(x) => Some(x),
|
|
@@ -30,6 +51,7 @@ impl Message {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Returns the current Message as an EndOfStorageEvent, if possible
|
|
|
pub fn as_end_of_stored_events(&self) -> Option<&str> {
|
|
|
match self {
|
|
|
Self::EndOfStoredEvents(subscription_id) => Some(subscription_id),
|
|
@@ -37,13 +59,16 @@ impl Message {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub fn as_event_from_server(&self) -> Option<(&types::SubscriptionId, &types::Event)> {
|
|
|
+ /// Returns the message as current server as an event generated by a
|
|
|
+ /// relayer, if possible
|
|
|
+ pub fn as_event_from_relayer(&self) -> Option<(&types::SubscriptionId, &types::Event)> {
|
|
|
match self {
|
|
|
- Self::EventFromServer(id, event) => Some((id, event)),
|
|
|
+ Self::EventFromRelayer(id, event) => Some((id, event)),
|
|
|
_ => None,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Returns the current message as an event from the client, if possible
|
|
|
pub fn as_event_from_client(&self) -> Option<&types::Event> {
|
|
|
match self {
|
|
|
Self::EventFromClient(event) => Some(event),
|
|
@@ -51,6 +76,7 @@ impl Message {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Returns the current message as a notice, if possible
|
|
|
pub fn as_notice(&self) -> Option<&str> {
|
|
|
match self {
|
|
|
Self::Notice(x) => Some(x),
|
|
@@ -58,6 +84,7 @@ impl Message {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Returns the current message as a close subscription id if possible
|
|
|
pub fn as_close_subscription_id(&self) -> Option<&types::SubscriptionId> {
|
|
|
match self {
|
|
|
Self::Close(x) => Some(x),
|
|
@@ -117,7 +144,7 @@ impl<'de> de::Deserialize<'de> for Message {
|
|
|
.is_valid()
|
|
|
.map_err(|e| de::Error::custom(e.to_string()))?;
|
|
|
|
|
|
- Ok(Self::EventFromServer(subscription_id, event))
|
|
|
+ Ok(Self::EventFromRelayer(subscription_id, event))
|
|
|
}
|
|
|
2 => {
|
|
|
let event: Event = serde_json::from_value(array[1].clone())
|
|
@@ -197,9 +224,9 @@ mod test {
|
|
|
fn event_from_server() {
|
|
|
let json = "[\"EVENT\",\"640bddcc93eae\",{\"content\":\"🤙\",\"created_at\":1676637072,\"id\":\"a3eaa71e4f46c1a69ac0596ae7c2af35807fc0b0d3b208b79a36eef67ef51743\",\"kind\":7,\"pubkey\":\"b2815682cfc83fcd2c3add05785cf4573dd388457069974cc6d8cca06b3c3b78\",\"sig\":\"93a3e9c4f6cb9a704885c4f77f6d7b16153e8eedc967603602606147f8c78d426f547d54120b80b33bd2101de638c06f2932df4daf53d66ca9b1341f2fd45729\",\"tags\":[[\"p\",\"8fe53b37518e3dbe9bab26d912292001d8b882de9456b7b08b615f912dc8bf4a\",\"\",\"mention\"],[\"e\",\"eb278e983fcedbb0d143c4250c879d078d037586c5dca8e1cf1a104f9846a460\"],[\"p\",\"2bda4f03446bc1c6ff00594e350a1e7ec57fb9cdc4a7b52694223d56ce0599e9\"]]}]";
|
|
|
let message: Message = serde_json::from_str(json).expect("valid message");
|
|
|
- assert!(message.as_event_from_server().is_some());
|
|
|
+ assert!(message.as_event_from_relayer().is_some());
|
|
|
|
|
|
- let (_, event) = message.as_event_from_server().expect("event");
|
|
|
+ let (_, event) = message.as_event_from_relayer().expect("event");
|
|
|
assert_eq!(
|
|
|
"🤙".to_owned(),
|
|
|
event.data.content.try_to_string().expect("string")
|
|
@@ -210,9 +237,9 @@ mod test {
|
|
|
fn follow_list() {
|
|
|
let json = r#"["EVENT","640e914a22321",{"content":"{\"wss:\\/\\/nos.lol\":{\"write\":true,\"read\":true},\"wss:\\/\\/relay.damus.io\":{\"write\":true,\"read\":true},\"wss:\\/\\/brb.io\":{\"write\":true,\"read\":true},\"wss:\\/\\/nostr.orangepill.dev\":{\"write\":true,\"read\":true},\"wss:\\/\\/relay.current.fyi\":{\"write\":true,\"read\":true},\"wss:\\/\\/eden.nostr.land\":{\"write\":true,\"read\":true},\"wss:\\/\\/relay.snort.social\":{\"write\":true,\"read\":true}}","created_at":1678476548,"id":"b8d7f6a19c3d9625b9aade947166708fbc6ab2dd7e3f3af84f1de08ea10d6f38","kind":3,"pubkey":"b2815682cfc83fcd2c3add05785cf4573dd388457069974cc6d8cca06b3c3b78","sig":"352485a162805e72a1e278a4a7bc33facd54a71e0f4c23934f35eee57eaa38c62e6260bf7624e2bd96bc6bcf93373b06c5245e28a266bfe2fbf064224e713fd6","tags":[["p","3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681"],["p","b2815682cfc83fcd2c3add05785cf4573dd388457069974cc6d8cca06b3c3b78"],["p","387519cafd325668ecffe59577f37238638da4cf2d985b82f932fc81d33da1e8"],["p","81d0ccce4591fc4e19e3ef752a2b003ef23a986cb31e7835ea7d8d7cd96d47ea"],["p","0861144c765ea10e39a48473a51bee604886e18abd0f831cc5ed7651e68a1caf"],["p","1779284c21126b5e1af6dcb84949ceacad781ce4ce0d1691292a41229465a54a"],["p","d7df5567015930b17c125b3a7cf29bef23aa5a68d09cd6518d291359606aab7b"],["p","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2"],["p","32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"],["p","a47457722e10ba3a271fbe7040259a3c4da2cf53bfd1e198138214d235064fc2"],["p","e1055729d51e037b3c14e8c56e2c79c22183385d94aadb32e5dc88092cd0fef4"],["p","2bda4f03446bc1c6ff00594e350a1e7ec57fb9cdc4a7b52694223d56ce0599e9"],["p","c57717ec7a6af20b836a9468282948dc0adba64d30abfb40aa8c6664dde3cfc7"],["p","6094dd769f94fab1a2915c1a3d8360e49cec84977f433a872bea1763466db784"]]}]"#;
|
|
|
let message: Message = serde_json::from_str(json).expect("valid message");
|
|
|
- assert!(message.as_event_from_server().is_some());
|
|
|
+ assert!(message.as_event_from_relayer().is_some());
|
|
|
|
|
|
- let (_, event) = message.as_event_from_server().expect("event");
|
|
|
+ let (_, event) = message.as_event_from_relayer().expect("event");
|
|
|
assert_eq!(event.data.tags.len(), 14);
|
|
|
event
|
|
|
.data
|
|
@@ -228,15 +255,15 @@ mod test {
|
|
|
fn direct_message() {
|
|
|
let json = r#"["EVENT","640e9851d461a",{"content":"/9Xk4PfEF8hU+C1wq4grww==?iv=XB/ytLhL0WKQ1of4wXIXCg==","created_at":1677726088,"id":"4643c79276730e25a8510163622335bb9d44aecdd0c596409804abb29910652d","kind":4,"pubkey":"b2815682cfc83fcd2c3add05785cf4573dd388457069974cc6d8cca06b3c3b78","sig":"23790fae080eaa87f2abf2df4e5fd49cecc67e58271910d7e871fb197641294cad92c2a6fff1501982d776648eecb1e4650ccfbb742a2d901226a9b00c310489","tags":[["p","b2815682cfc83fcd2c3add05785cf4573dd388457069974cc6d8cca06b3c3b78"]]}]"#;
|
|
|
let message: Message = serde_json::from_str(json).expect("valid message");
|
|
|
- assert!(message.as_event_from_server().is_some());
|
|
|
+ assert!(message.as_event_from_relayer().is_some());
|
|
|
|
|
|
- let (_, event) = message.as_event_from_server().expect("event");
|
|
|
- let content = Content::DirectMessage(EncryptedData {
|
|
|
+ let (_, event) = message.as_event_from_relayer().expect("event");
|
|
|
+ let content = Content::EncryptedDirectMessage(EncryptedData {
|
|
|
encrypted_message: vec![
|
|
|
255, 213, 228, 224, 247, 196, 23, 200, 84, 248, 45, 112, 171, 136, 43, 195,
|
|
|
],
|
|
|
iv: vec![
|
|
|
- 255, 213, 228, 224, 247, 196, 23, 200, 84, 248, 45, 112, 171, 136, 43, 195,
|
|
|
+ 92, 31, 242, 180, 184, 75, 209, 98, 144, 214, 135, 248, 193, 114, 23, 10,
|
|
|
],
|
|
|
});
|
|
|
assert_eq!(event.data.tags.len(), 1);
|