notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

multi_subscriber.rs (4080B)


      1 use enostr::{Filter, RelayPool};
      2 use nostrdb::{Ndb, Note, Transaction};
      3 use tracing::{debug, error, info};
      4 use uuid::Uuid;
      5 
      6 use crate::{filter::UnifiedSubscription, note::NoteRef, Error};
      7 
      8 pub struct MultiSubscriber {
      9     filters: Vec<Filter>,
     10     sub: Option<UnifiedSubscription>,
     11     subscribers: u32,
     12 }
     13 
     14 impl MultiSubscriber {
     15     pub fn new(filters: Vec<Filter>) -> Self {
     16         Self {
     17             filters,
     18             sub: None,
     19             subscribers: 0,
     20         }
     21     }
     22 
     23     fn real_subscribe(
     24         ndb: &Ndb,
     25         pool: &mut RelayPool,
     26         filters: Vec<Filter>,
     27     ) -> Option<UnifiedSubscription> {
     28         let subid = Uuid::new_v4().to_string();
     29         let sub = ndb.subscribe(&filters).ok()?;
     30 
     31         pool.subscribe(subid.clone(), filters);
     32 
     33         Some(UnifiedSubscription {
     34             local: sub,
     35             remote: subid,
     36         })
     37     }
     38 
     39     pub fn unsubscribe(&mut self, ndb: &Ndb, pool: &mut RelayPool) {
     40         if self.subscribers == 0 {
     41             error!("No subscribers to unsubscribe from");
     42             return;
     43         }
     44 
     45         self.subscribers -= 1;
     46         if self.subscribers == 0 {
     47             let sub = match self.sub {
     48                 Some(ref sub) => sub,
     49                 None => {
     50                     error!("No remote subscription to unsubscribe from");
     51                     return;
     52                 }
     53             };
     54             let local_sub = &sub.local;
     55             if let Err(e) = ndb.unsubscribe(*local_sub) {
     56                 error!(
     57                     "failed to unsubscribe from object: {e}, subid:{}, {} active subscriptions",
     58                     local_sub.id(),
     59                     ndb.subscription_count()
     60                 );
     61             } else {
     62                 info!(
     63                     "Unsubscribed from object subid:{}. {} active subscriptions",
     64                     local_sub.id(),
     65                     ndb.subscription_count()
     66                 );
     67             }
     68 
     69             // unsub from remote
     70             pool.unsubscribe(sub.remote.clone());
     71             self.sub = None;
     72         } else {
     73             info!(
     74                 "Locally unsubscribing. {} active ndb subscriptions. {} active subscriptions for this object",
     75                 ndb.subscription_count(),
     76                 self.subscribers,
     77             );
     78         }
     79     }
     80 
     81     pub fn subscribe(&mut self, ndb: &Ndb, pool: &mut RelayPool) {
     82         self.subscribers += 1;
     83         if self.subscribers == 1 {
     84             if self.sub.is_some() {
     85                 error!("Object is first subscriber, but it already had remote subscription");
     86                 return;
     87             }
     88 
     89             self.sub = Self::real_subscribe(ndb, pool, self.filters.clone());
     90             info!(
     91                 "Remotely subscribing to object. {} total active subscriptions, {} on this object",
     92                 ndb.subscription_count(),
     93                 self.subscribers,
     94             );
     95 
     96             if self.sub.is_none() {
     97                 error!("Error subscribing remotely to object");
     98             }
     99         } else {
    100             info!(
    101                 "Locally subscribing. {} total active subscriptions, {} for this object",
    102                 ndb.subscription_count(),
    103                 self.subscribers,
    104             )
    105         }
    106     }
    107 
    108     pub fn poll_for_notes(&mut self, ndb: &Ndb, txn: &Transaction) -> Result<Vec<NoteRef>, Error> {
    109         let sub = self.sub.as_ref().ok_or(Error::no_active_sub())?;
    110         let new_note_keys = ndb.poll_for_notes(sub.local, 500);
    111 
    112         if new_note_keys.is_empty() {
    113             return Ok(vec![]);
    114         } else {
    115             debug!("{} new notes! {:?}", new_note_keys.len(), new_note_keys);
    116         }
    117 
    118         let mut notes: Vec<Note<'_>> = Vec::with_capacity(new_note_keys.len());
    119         for key in new_note_keys {
    120             let note = if let Ok(note) = ndb.get_note_by_key(txn, key) {
    121                 note
    122             } else {
    123                 continue;
    124             };
    125 
    126             notes.push(note);
    127         }
    128 
    129         let note_refs: Vec<NoteRef> = notes.iter().map(|n| NoteRef::from_note(n)).collect();
    130 
    131         Ok(note_refs)
    132     }
    133 }