notedeck

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

mod.rs (6532B)


      1 mod broadcast;
      2 mod compaction;
      3 mod coordinator;
      4 mod identity;
      5 mod limits;
      6 pub mod message;
      7 mod multicast;
      8 mod outbox;
      9 pub mod pool;
     10 mod queue;
     11 pub mod subs_debug;
     12 mod subscription;
     13 mod transparent;
     14 mod websocket;
     15 
     16 pub use broadcast::{BroadcastCache, BroadcastRelay};
     17 pub use identity::{
     18     NormRelayUrl, OutboxSubId, RelayId, RelayReqId, RelayReqStatus, RelayType, RelayUrlPkgs,
     19 };
     20 pub use limits::{
     21     RelayCoordinatorLimits, RelayLimitations, SubPass, SubPassGuardian, SubPassRevocation,
     22 };
     23 pub use multicast::{MulticastRelay, MulticastRelayCache};
     24 use nostrdb::Filter;
     25 pub use outbox::{OutboxPool, OutboxSession, OutboxSessionHandler};
     26 pub use queue::QueuedTasks;
     27 pub use subscription::{
     28     FullModificationTask, ModifyFiltersTask, ModifyRelaysTask, ModifyTask, OutboxSubscriptions,
     29     OutboxTask, SubscribeTask,
     30 };
     31 pub use websocket::{WebsocketConn, WebsocketRelay};
     32 
     33 #[cfg(test)]
     34 pub mod test_utils;
     35 
     36 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
     37 pub enum RelayStatus {
     38     Connected,
     39     Connecting,
     40     Disconnected,
     41 }
     42 
     43 enum UnownedRelay<'a> {
     44     Websocket(&'a mut WebsocketRelay),
     45     Multicast(&'a mut MulticastRelay),
     46 }
     47 
     48 /// RawEventData is the event raw data from a relay
     49 pub struct RawEventData<'a> {
     50     pub url: &'a str,
     51     pub event_json: &'a str,
     52     pub relay_type: RelayImplType,
     53 }
     54 
     55 /// RelayImplType identifies whether an event came from a websocket or multicast relay.
     56 pub enum RelayImplType {
     57     Websocket,
     58     Multicast,
     59 }
     60 
     61 pub enum RelayTask {
     62     Unsubscribe,
     63     Subscribe,
     64 }
     65 
     66 pub struct FilterMetadata {
     67     filter_json_size: usize,
     68     last_seen: Option<u64>,
     69 }
     70 
     71 pub struct MetadataFilters {
     72     filters: Vec<Filter>,
     73     meta: Vec<FilterMetadata>,
     74 }
     75 
     76 impl MetadataFilters {
     77     pub fn new(filters: Vec<Filter>) -> Self {
     78         let meta = filters
     79             .iter()
     80             .map(|f| FilterMetadata {
     81                 filter_json_size: f.json().ok().map(|j| j.len()).unwrap_or(0),
     82                 last_seen: None,
     83             })
     84             .collect();
     85         Self { filters, meta }
     86     }
     87 
     88     pub fn json_size_sum(&self) -> usize {
     89         self.meta.iter().map(|f| f.filter_json_size).sum()
     90     }
     91 
     92     pub fn since_optimize(&mut self) {
     93         for (filter, meta) in self.filters.iter_mut().zip(self.meta.iter()) {
     94             let Some(last_seen) = meta.last_seen else {
     95                 continue;
     96             };
     97 
     98             *filter = filter.clone().since_mut(last_seen);
     99         }
    100     }
    101 
    102     pub fn get_filters(&self) -> &Vec<Filter> {
    103         &self.filters
    104     }
    105 
    106     #[allow(dead_code)]
    107     pub fn iter(&self) -> MetadataFiltersIter<'_> {
    108         MetadataFiltersIter {
    109             filters: self.filters.iter(),
    110             meta: self.meta.iter(),
    111         }
    112     }
    113 
    114     pub fn iter_mut(&mut self) -> MetadataFiltersIterMut<'_> {
    115         MetadataFiltersIterMut {
    116             filters: self.filters.iter_mut(),
    117             meta: self.meta.iter_mut(),
    118         }
    119     }
    120 
    121     #[allow(dead_code)]
    122     pub fn is_empty(&self) -> bool {
    123         self.filters.iter().all(|f| f.num_elements() == 0)
    124     }
    125 }
    126 
    127 #[allow(dead_code)]
    128 pub struct MetadataFiltersIter<'a> {
    129     filters: std::slice::Iter<'a, Filter>,
    130     meta: std::slice::Iter<'a, FilterMetadata>,
    131 }
    132 
    133 impl<'a> Iterator for MetadataFiltersIter<'a> {
    134     type Item = (&'a Filter, &'a FilterMetadata);
    135 
    136     fn next(&mut self) -> Option<Self::Item> {
    137         Some((self.filters.next()?, self.meta.next()?))
    138     }
    139 }
    140 
    141 pub struct MetadataFiltersIterMut<'a> {
    142     filters: std::slice::IterMut<'a, Filter>,
    143     meta: std::slice::IterMut<'a, FilterMetadata>,
    144 }
    145 
    146 impl<'a> Iterator for MetadataFiltersIterMut<'a> {
    147     type Item = (&'a mut Filter, &'a mut FilterMetadata);
    148 
    149     fn next(&mut self) -> Option<Self::Item> {
    150         Some((self.filters.next()?, self.meta.next()?))
    151     }
    152 }
    153 
    154 #[cfg(test)]
    155 mod tests {
    156     use super::*;
    157 
    158     fn filter_has_since(filter: &Filter, expected: u64) -> bool {
    159         let json = filter.json().expect("filter json");
    160         json.contains(&format!("\"since\":{}", expected))
    161     }
    162 
    163     #[test]
    164     fn since_optimize_applies_last_seen_to_filter() {
    165         let filter = Filter::new().kinds(vec![1]).build();
    166         let mut metadata_filters = MetadataFilters::new(vec![filter]);
    167 
    168         // Initially no since
    169         let json_before = metadata_filters.get_filters()[0]
    170             .json()
    171             .expect("filter json");
    172         assert!(
    173             !json_before.contains("\"since\""),
    174             "filter should not have since initially"
    175         );
    176 
    177         // Set last_seen on metadata
    178         metadata_filters.meta[0].last_seen = Some(12345);
    179 
    180         // Call since_optimize
    181         metadata_filters.since_optimize();
    182 
    183         // Now filter should have since
    184         assert!(
    185             filter_has_since(&metadata_filters.get_filters()[0], 12345),
    186             "filter should have since:12345 after optimization"
    187         );
    188     }
    189 
    190     #[test]
    191     fn since_optimize_skips_filters_without_last_seen() {
    192         let filter1 = Filter::new().kinds(vec![1]).build();
    193         let filter2 = Filter::new().kinds(vec![2]).build();
    194         let mut metadata_filters = MetadataFilters::new(vec![filter1, filter2]);
    195 
    196         // Only set last_seen on first filter
    197         metadata_filters.meta[0].last_seen = Some(99999);
    198 
    199         metadata_filters.since_optimize();
    200 
    201         // First filter should have since
    202         assert!(
    203             filter_has_since(&metadata_filters.get_filters()[0], 99999),
    204             "first filter should have since"
    205         );
    206 
    207         // Second filter should NOT have since
    208         let json_second = metadata_filters.get_filters()[1]
    209             .json()
    210             .expect("filter json");
    211         assert!(
    212             !json_second.contains("\"since\""),
    213             "second filter should not have since"
    214         );
    215     }
    216 
    217     #[test]
    218     fn since_optimize_overwrites_existing_since() {
    219         // Create filter with initial since value
    220         let filter = Filter::new().kinds(vec![1]).since(100).build();
    221         let mut metadata_filters = MetadataFilters::new(vec![filter]);
    222 
    223         // Verify initial since
    224         assert!(
    225             filter_has_since(&metadata_filters.get_filters()[0], 100),
    226             "filter should have initial since:100"
    227         );
    228 
    229         // Set different last_seen
    230         metadata_filters.meta[0].last_seen = Some(200);
    231         metadata_filters.since_optimize();
    232 
    233         // Since should be updated to new value
    234         assert!(
    235             filter_has_since(&metadata_filters.get_filters()[0], 200),
    236             "filter should have updated since:200"
    237         );
    238     }
    239 }