kind.rs (4705B)
1 use crate::error::{Error, FilterError}; 2 use crate::filter; 3 use crate::filter::FilterState; 4 use crate::timeline::Timeline; 5 use enostr::{Filter, Pubkey}; 6 use nostrdb::{Ndb, Transaction}; 7 use std::fmt::Display; 8 use tracing::{error, warn}; 9 10 #[derive(Clone, Debug)] 11 pub enum PubkeySource { 12 Explicit(Pubkey), 13 DeckAuthor, 14 } 15 16 #[derive(Debug, Clone)] 17 pub enum ListKind { 18 Contact(PubkeySource), 19 } 20 21 /// 22 /// What kind of timeline is it? 23 /// - Follow List 24 /// - Notifications 25 /// - DM 26 /// - filter 27 /// - ... etc 28 /// 29 #[derive(Debug, Clone)] 30 pub enum TimelineKind { 31 List(ListKind), 32 33 Notifications(PubkeySource), 34 35 Profile(PubkeySource), 36 37 Universe, 38 39 /// Generic filter 40 Generic, 41 } 42 43 impl Display for TimelineKind { 44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 45 match self { 46 TimelineKind::List(ListKind::Contact(_src)) => f.write_str("Contacts"), 47 TimelineKind::Generic => f.write_str("Timeline"), 48 TimelineKind::Notifications(_) => f.write_str("Notifications"), 49 TimelineKind::Profile(_) => f.write_str("Profile"), 50 TimelineKind::Universe => f.write_str("Universe"), 51 } 52 } 53 } 54 55 impl TimelineKind { 56 pub fn contact_list(pk: PubkeySource) -> Self { 57 TimelineKind::List(ListKind::Contact(pk)) 58 } 59 60 pub fn profile(pk: PubkeySource) -> Self { 61 TimelineKind::Profile(pk) 62 } 63 64 pub fn notifications(pk: PubkeySource) -> Self { 65 TimelineKind::Notifications(pk) 66 } 67 68 pub fn into_timeline(self, ndb: &Ndb, default_user: Option<&[u8; 32]>) -> Option<Timeline> { 69 match self { 70 TimelineKind::Universe => Some(Timeline::new( 71 TimelineKind::Universe, 72 FilterState::ready(vec![Filter::new() 73 .kinds([1]) 74 .limit(filter::default_limit()) 75 .build()]), 76 )), 77 78 TimelineKind::Generic => { 79 warn!("you can't convert a TimelineKind::Generic to a Timeline"); 80 None 81 } 82 83 TimelineKind::Profile(pk_src) => { 84 let pk = match &pk_src { 85 PubkeySource::DeckAuthor => default_user?, 86 PubkeySource::Explicit(pk) => pk.bytes(), 87 }; 88 89 let filter = Filter::new() 90 .authors([pk]) 91 .kinds([1]) 92 .limit(filter::default_limit()) 93 .build(); 94 95 Some(Timeline::new( 96 TimelineKind::profile(pk_src), 97 FilterState::ready(vec![filter]), 98 )) 99 } 100 101 TimelineKind::Notifications(pk_src) => { 102 let pk = match &pk_src { 103 PubkeySource::DeckAuthor => default_user?, 104 PubkeySource::Explicit(pk) => pk.bytes(), 105 }; 106 107 let notifications_filter = Filter::new() 108 .pubkeys([pk]) 109 .kinds([1]) 110 .limit(crate::filter::default_limit()) 111 .build(); 112 113 Some(Timeline::new( 114 TimelineKind::notifications(pk_src), 115 FilterState::ready(vec![notifications_filter]), 116 )) 117 } 118 119 TimelineKind::List(ListKind::Contact(pk_src)) => { 120 let pk = match &pk_src { 121 PubkeySource::DeckAuthor => default_user?, 122 PubkeySource::Explicit(pk) => pk.bytes(), 123 }; 124 125 let contact_filter = Filter::new().authors([pk]).kinds([3]).limit(1).build(); 126 127 let txn = Transaction::new(ndb).expect("txn"); 128 let results = ndb 129 .query(&txn, &[contact_filter.clone()], 1) 130 .expect("contact query failed?"); 131 132 if results.is_empty() { 133 return Some(Timeline::new( 134 TimelineKind::contact_list(pk_src), 135 FilterState::needs_remote(vec![contact_filter.clone()]), 136 )); 137 } 138 139 match Timeline::contact_list(&results[0].note) { 140 Err(Error::Filter(FilterError::EmptyContactList)) => Some(Timeline::new( 141 TimelineKind::contact_list(pk_src), 142 FilterState::needs_remote(vec![contact_filter]), 143 )), 144 Err(e) => { 145 error!("Unexpected error: {e}"); 146 None 147 } 148 Ok(tl) => Some(tl), 149 } 150 } 151 } 152 } 153 }