nostr_rust

My fork of nostr_rust
git clone git://jb55.com/nostr_rust
Log | Files | Refs | README

nostr_client.rs (10689B)


      1 use std::collections::HashMap;
      2 use std::sync::{Arc, Mutex};
      3 
      4 use crate::events::Event;
      5 use crate::req::{Req, ReqFilter};
      6 use crate::websocket::SimplifiedWS;
      7 use serde_json::{json, Value};
      8 use tungstenite::Message;
      9 
     10 /// Nostr Client
     11 pub struct Client {
     12     pub relays: HashMap<String, Arc<Mutex<SimplifiedWS>>>,
     13     pub subscriptions: HashMap<String, Vec<Message>>,
     14 }
     15 
     16 impl Client {
     17     /// Create a new client with a list of default relays
     18     ///
     19     /// # Example
     20     /// ```rust
     21     /// use nostr_rust::nostr_client::Client;
     22     /// let client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
     23     /// ```
     24     pub fn new(default_relays: Vec<&str>) -> Result<Self, String> {
     25         let mut client = Self {
     26             relays: HashMap::new(),
     27             subscriptions: HashMap::new(),
     28         };
     29 
     30         for relay in default_relays {
     31             client.add_relay(relay)?;
     32         }
     33 
     34         Ok(client)
     35     }
     36 }
     37 
     38 impl Client {
     39     /// Add a relay to the client
     40     /// # Example
     41     /// ```rust
     42     /// use nostr_rust::nostr_client::Client;
     43     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
     44     /// client.add_relay("wss://relay.damus.io").unwrap();
     45     /// ```
     46     pub fn add_relay(&mut self, relay: &str) -> Result<(), String> {
     47         let client = match SimplifiedWS::new(relay) {
     48             Ok(client) => client,
     49             Err(err) => return Err(format!("Error connecting to relay: {}", err)),
     50         };
     51 
     52         // Check if relay is already added
     53         if self.relays.contains_key(relay) {
     54             return Err(format!("Relay {} already added", relay));
     55         }
     56 
     57         self.relays
     58             .insert(relay.to_string(), Arc::new(Mutex::new(client)));
     59 
     60         Ok(())
     61     }
     62 
     63     /// Remove a relay from the client
     64     /// # Example
     65     /// ```rust
     66     /// use nostr_rust::nostr_client::Client;
     67     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
     68     /// client.remove_relay("wss://nostr-pub.wellorder.net").unwrap();
     69     /// ```
     70     pub fn remove_relay(&mut self, relay: &str) -> Result<(), String> {
     71         println!("Removing relay {}", relay);
     72         if !self.relays.contains_key(relay) {
     73             println!("Relay {} not found", relay);
     74             return Err(format!("Relay {} not found", relay));
     75         }
     76 
     77         println!("Removing relay {}", relay);
     78 
     79         // Close the connection
     80         self.relays
     81             .remove(relay)
     82             .unwrap()
     83             .lock()
     84             .unwrap()
     85             .socket
     86             .close(None)
     87             .unwrap();
     88 
     89         Ok(())
     90     }
     91 
     92     /// Publish a Nostr event
     93     pub fn publish_event(&mut self, event: &Event) -> Result<(), String> {
     94         let json_stringified = json!(["EVENT", event]).to_string();
     95         let message = Message::text(json_stringified);
     96 
     97         for relay in self.relays.values() {
     98             let mut relay = relay.lock().unwrap();
     99             relay.send_message(&message)?;
    100         }
    101 
    102         Ok(())
    103     }
    104 
    105     /// Get next data from the relays
    106     /// # Example
    107     /// ```rust
    108     /// use std::{
    109     ///  sync::{Arc, Mutex},
    110     ///  thread,
    111     /// };
    112     /// use tungstenite::Message;
    113     /// use nostr_rust::{nostr_client::Client, req::ReqFilter};
    114     ///
    115     /// fn handle_message(relay_url: &String, message: &Message) -> Result<(), String> {
    116     ///   println!("Received message: {:?}", message);
    117     ///
    118     ///   Ok(())
    119     /// }
    120     ///
    121     /// let mut client = Arc::new(Mutex::new(Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap()));
    122     ///
    123     /// // Run a new thread to listen
    124     /// let nostr_clone = client.clone();
    125     /// let nostr_thread = thread::spawn(move || loop {
    126     ///    let events = nostr_clone.lock().unwrap().next_data().unwrap();
    127     ///    
    128     ///   for (relay_url, message) in events.iter() {
    129     ///     handle_message(relay_url, message).unwrap();
    130     ///   }
    131     /// });
    132     ///
    133     /// // Subscribe to the most beautiful Nostr profile event
    134     /// client
    135     /// .lock()
    136     /// .unwrap()
    137     /// .subscribe(vec![ReqFilter {
    138     ///     ids: None,
    139     ///     authors: Some(vec![
    140     ///         "884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string(),
    141     ///     ]),
    142     ///     kinds: None,
    143     ///     e: None,
    144     ///     p: None,
    145     ///     since: None,
    146     ///     until: None,
    147     ///     limit: Some(1),
    148     /// }])
    149     /// .unwrap();
    150     ///
    151     /// // Wait 3s for the thread to finish
    152     /// std::thread::sleep(std::time::Duration::from_secs(3));
    153     /// ```
    154     pub fn next_data(&mut self) -> Result<Vec<(String, tungstenite::Message)>, String> {
    155         let mut events: Vec<(String, tungstenite::Message)> = Vec::new();
    156 
    157         for (relay_name, socket) in self.relays.iter() {
    158             let message = socket.lock().unwrap().read_message()?;
    159             events.push((relay_name.clone(), message));
    160         }
    161 
    162         Ok(events)
    163     }
    164 
    165     /// Subscribe
    166     /// # Example
    167     /// ```rust
    168     /// use nostr_rust::{nostr_client::Client, req::ReqFilter};
    169     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
    170     /// client
    171     /// .subscribe(vec![ReqFilter { // None means generate a random ID
    172     ///     ids: None,
    173     ///     authors: Some(vec![
    174     ///         "884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string(),
    175     ///     ]),
    176     ///     kinds: None,
    177     ///     e: None,
    178     ///     p: None,
    179     ///     since: None,
    180     ///     until: None,
    181     ///     limit: Some(1),
    182     /// }])
    183     /// .unwrap();
    184     /// ```
    185     pub fn subscribe(&mut self, filters: Vec<ReqFilter>) -> Result<String, String> {
    186         let req = Req::new(None, filters);
    187         let message = Message::text(req.to_string());
    188 
    189         for relay in self.relays.values() {
    190             let mut relay = relay.lock().unwrap();
    191             relay.send_message(&message)?;
    192         }
    193 
    194         Ok(req.subscription_id)
    195     }
    196 
    197     /// Subscribe with a specific ID
    198     ///
    199     /// # Example
    200     /// ```rust
    201     /// use nostr_rust::{nostr_client::Client, req::ReqFilter};
    202     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
    203     /// client
    204     /// .subscribe_with_id("my_subscription_id", vec![ReqFilter {
    205     ///    ids: None,
    206     ///    authors: Some(vec![
    207     ///      "884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string(),
    208     ///    ]),
    209     ///    kinds: None,
    210     ///    e: None,
    211     ///    p: None,
    212     ///    since: None,
    213     ///    until: None,
    214     ///    limit: Some(1),
    215     /// }])
    216     /// .unwrap();
    217     /// ```
    218     pub fn subscribe_with_id(
    219         &mut self,
    220         subscription_id: &str,
    221         filters: Vec<ReqFilter>,
    222     ) -> Result<(), String> {
    223         let req = Req::new(Some(subscription_id), filters);
    224         let message = Message::text(req.to_string());
    225 
    226         for relay in self.relays.values() {
    227             let mut relay = relay.lock().unwrap();
    228             relay.send_message(&message)?;
    229         }
    230 
    231         Ok(())
    232     }
    233 
    234     /// Unsubscribe
    235     /// # Example
    236     /// ```rust
    237     /// use nostr_rust::{nostr_client::Client, req::ReqFilter};
    238     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
    239     /// let subscription_id = client
    240     /// .subscribe(vec![ReqFilter {
    241     ///    ids: None,
    242     ///   authors: Some(vec![
    243     ///        "884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string(),
    244     ///   ]),
    245     ///  kinds: None,
    246     ///  e: None,
    247     ///  p: None,
    248     ///  since: None,
    249     ///  until: None,
    250     ///  limit: Some(1),
    251     /// }])
    252     /// .unwrap();
    253     /// client.unsubscribe(&subscription_id).unwrap();
    254     /// ```
    255     pub fn unsubscribe(&mut self, subscription_id: &str) -> Result<(), String> {
    256         let message = Message::text(json!(["CLOSE", subscription_id]).to_string());
    257 
    258         for relay in self.relays.values() {
    259             let mut relay = relay.lock().unwrap();
    260             relay.send_message(&message)?;
    261         }
    262 
    263         Ok(())
    264     }
    265 
    266     /// Add event to a subscription
    267     pub fn add_event(&mut self, subscription_id: &str, message: Message) {
    268         // Check if the subscription exists
    269         if !self.subscriptions.contains_key(subscription_id) {
    270             self.subscriptions
    271                 .insert(subscription_id.to_string(), Vec::new());
    272         }
    273 
    274         // Check if the message is already in the subscription
    275         if !self.subscriptions[subscription_id].contains(&message) {
    276             // Add the message to the subscription
    277             self.subscriptions
    278                 .get_mut(subscription_id)
    279                 .unwrap()
    280                 .push(message);
    281         }
    282     }
    283 
    284     /// Get events and remove them from the subscription
    285     pub fn get_events(&mut self, subscription_id: &str) -> Option<Vec<Message>> {
    286         self.subscriptions.remove(subscription_id)
    287     }
    288 
    289     /// Get events of a given filters
    290     ///
    291     /// # Example
    292     /// ```rust
    293     /// use nostr_rust::{nostr_client::Client, req::ReqFilter};
    294     /// let mut client = Client::new(vec!["wss://nostr-pub.wellorder.net"]).unwrap();
    295     /// let events = client.get_events_of(vec![ReqFilter {
    296     ///    ids: None,
    297     ///    authors: Some(vec!["884704bd421721e292edbff42eb77547fe115c6ff9825b08fc366be4cd69e9f6".to_string()]),
    298     ///    kinds: Some(vec![3]),
    299     ///    e: None,
    300     ///    p: None,
    301     ///    since: None,
    302     ///    until: None,
    303     ///    limit: Some(1),
    304     /// }]).unwrap();
    305     /// ```
    306     pub fn get_events_of(&mut self, filters: Vec<ReqFilter>) -> Result<Vec<Event>, String> {
    307         let mut events: Vec<Event> = Vec::new();
    308 
    309         // Subscribe
    310         let id = self.subscribe(filters)?;
    311 
    312         // Get the events
    313         loop {
    314             let data = self.next_data()?;
    315             let mut break_loop = false;
    316 
    317             for (_, message) in data {
    318                 let event: Value = serde_json::from_str(&message.to_string()).unwrap();
    319 
    320                 if event[0] == "EOSE" && event[1].as_str() == Some(&id) {
    321                     break_loop = true;
    322                     break;
    323                 }
    324 
    325                 self.add_event(&id, message);
    326             }
    327 
    328             if break_loop {
    329                 break;
    330             }
    331         }
    332 
    333         // unsubscribe
    334         self.unsubscribe(&id).unwrap();
    335 
    336         // Get the events
    337         if let Some(messages) = self.get_events(&id) {
    338             for message in messages {
    339                 let event: Value = serde_json::from_str(&message.to_string()).unwrap();
    340                 let event_object: Event = serde_json::from_value(event[2].clone()).unwrap();
    341                 events.push(event_object);
    342             }
    343         }
    344         Ok(events)
    345     }
    346 }