@@ -18,6 +18,21 @@ use self::constant::{
1818
1919const P_TAG : SingleLetterTag = SingleLetterTag :: lowercase ( Alphabet :: P ) ;
2020
21+ pub ( crate ) enum GossipKind {
22+ Nip17 ,
23+ Nip65 ,
24+ }
25+
26+ impl GossipKind {
27+ #[ allow( clippy:: wrong_self_convention) ]
28+ pub ( crate ) fn to_event_kind ( self ) -> Kind {
29+ match self {
30+ Self :: Nip17 => Kind :: InboxRelays ,
31+ Self :: Nip65 => Kind :: RelayList ,
32+ }
33+ }
34+ }
35+
2136#[ derive( Debug ) ]
2237pub enum BrokenDownFilters {
2338 /// Filters by url
@@ -145,7 +160,7 @@ impl Gossip {
145160 }
146161
147162 /// Check for what public keys the metadata are outdated or not existent (both for NIP17 and NIP65)
148- pub async fn check_outdated < I > ( & self , public_keys : I ) -> HashSet < PublicKey >
163+ pub async fn check_outdated < I > ( & self , public_keys : I , kind : & GossipKind ) -> HashSet < PublicKey >
149164 where
150165 I : IntoIterator < Item = PublicKey > ,
151166 {
@@ -161,14 +176,28 @@ impl Gossip {
161176 continue ;
162177 }
163178
164- // Check if collections are empty
165- let empty: bool =
166- lists. nip17 . collection . is_empty ( ) || lists. nip65 . collection . is_empty ( ) ;
179+ let ( empty, expired) = match kind {
180+ GossipKind :: Nip17 => {
181+ // Check if the collection is empty
182+ let empty: bool = lists. nip17 . collection . is_empty ( ) ;
167183
168- // Check if expired
169- let expired: bool = lists. nip17 . last_update + PUBKEY_METADATA_OUTDATED_AFTER
170- < now
171- || lists. nip65 . last_update + PUBKEY_METADATA_OUTDATED_AFTER < now;
184+ // Check if expired
185+ let expired: bool =
186+ lists. nip17 . last_update + PUBKEY_METADATA_OUTDATED_AFTER < now;
187+
188+ ( empty, expired)
189+ }
190+ GossipKind :: Nip65 => {
191+ // Check if the collection is empty
192+ let empty: bool = lists. nip65 . collection . is_empty ( ) ;
193+
194+ // Check if expired
195+ let expired: bool =
196+ lists. nip65 . last_update + PUBKEY_METADATA_OUTDATED_AFTER < now;
197+
198+ ( empty, expired)
199+ }
200+ } ;
172201
173202 if empty || expired {
174203 outdated. insert ( public_key) ;
@@ -372,7 +401,11 @@ impl Gossip {
372401 self . map_nip65_relays ( txn, public_keys, RelayMetadata :: Read )
373402 }
374403
375- pub async fn break_down_filter ( & self , filter : Filter ) -> BrokenDownFilters {
404+ pub async fn break_down_filter (
405+ & self ,
406+ filter : Filter ,
407+ pattern : GossipFilterPattern ,
408+ ) -> BrokenDownFilters {
376409 let txn = self . public_keys . read ( ) . await ;
377410
378411 // Extract `p` tag from generic tags and parse public key hex
@@ -390,7 +423,9 @@ impl Gossip {
390423 self . map_nip65_outbox_relays ( & txn, authors) ;
391424
392425 // Extend with NIP17 relays
393- outbox. extend ( self . map_nip17_relays ( & txn, authors) ) ;
426+ if pattern. has_nip17 ( ) {
427+ outbox. extend ( self . map_nip17_relays ( & txn, authors) ) ;
428+ }
394429
395430 // No relay available for the authors
396431 if outbox. is_empty ( ) {
@@ -417,7 +452,9 @@ impl Gossip {
417452 self . map_nip65_inbox_relays ( & txn, p_public_keys) ;
418453
419454 // Extend with NIP17 relays
420- inbox. extend ( self . map_nip17_relays ( & txn, p_public_keys) ) ;
455+ if pattern. has_nip17 ( ) {
456+ inbox. extend ( self . map_nip17_relays ( & txn, p_public_keys) ) ;
457+ }
421458
422459 // No relay available for the p tags
423460 if inbox. is_empty ( ) {
@@ -446,7 +483,9 @@ impl Gossip {
446483 self . get_nip65_relays ( & txn, authors. union ( p_public_keys) , None ) ;
447484
448485 // Extend with NIP17 relays
449- relays. extend ( self . get_nip17_relays ( & txn, authors. union ( p_public_keys) ) ) ;
486+ if pattern. has_nip17 ( ) {
487+ relays. extend ( self . get_nip17_relays ( & txn, authors. union ( p_public_keys) ) ) ;
488+ }
450489
451490 // No relay available for the authors and p tags
452491 if relays. is_empty ( ) {
@@ -561,6 +600,38 @@ fn extract_nip65_relay_list(
561600 map
562601}
563602
603+ pub ( crate ) enum GossipFilterPattern {
604+ Nip65 ,
605+ Nip65AndNip17 ,
606+ }
607+
608+ impl GossipFilterPattern {
609+ #[ inline]
610+ fn has_nip17 ( & self ) -> bool {
611+ matches ! ( self , Self :: Nip65AndNip17 )
612+ }
613+ }
614+
615+ /// Use both NIP-65 and NIP-17 if:
616+ /// - the `kinds` field contains the [`Kind::GiftWrap`];
617+ /// - if it's set a `#p` tag and no kind is specified
618+ pub ( crate ) fn find_filter_pattern ( filter : & Filter ) -> GossipFilterPattern {
619+ let ( are_kinds_empty, has_gift_wrap_kind) : ( bool , bool ) = match & filter. kinds {
620+ Some ( kinds) if kinds. is_empty ( ) => ( true , false ) ,
621+ Some ( kinds) => ( false , kinds. contains ( & Kind :: GiftWrap ) ) ,
622+ None => ( true , false ) ,
623+ } ;
624+ let has_p_tags: bool = filter. generic_tags . contains_key ( & P_TAG ) ;
625+
626+ // TODO: use both also if there are only IDs?
627+
628+ if has_gift_wrap_kind || ( has_p_tags && are_kinds_empty) {
629+ return GossipFilterPattern :: Nip65AndNip17 ;
630+ }
631+
632+ GossipFilterPattern :: Nip65
633+ }
634+
564635#[ cfg( test) ]
565636mod tests {
566637 use super :: * ;
@@ -736,7 +807,10 @@ mod tests {
736807
737808 // Single author
738809 let filter = Filter :: new ( ) . author ( keys_a. public_key ) ;
739- match graph. break_down_filter ( filter. clone ( ) ) . await {
810+ match graph
811+ . break_down_filter ( filter. clone ( ) , GossipFilterPattern :: Nip65 )
812+ . await
813+ {
740814 BrokenDownFilters :: Filters ( map) => {
741815 assert_eq ! ( map. get( & damus_url) . unwrap( ) , & filter) ;
742816 assert_eq ! ( map. get( & nostr_bg_url) . unwrap( ) , & filter) ;
@@ -748,7 +822,10 @@ mod tests {
748822
749823 // Multiple authors
750824 let authors_filter = Filter :: new ( ) . authors ( [ keys_a. public_key , keys_b. public_key ] ) ;
751- match graph. break_down_filter ( authors_filter. clone ( ) ) . await {
825+ match graph
826+ . break_down_filter ( authors_filter. clone ( ) , GossipFilterPattern :: Nip65 )
827+ . await
828+ {
752829 BrokenDownFilters :: Filters ( map) => {
753830 assert_eq ! ( map. get( & damus_url) . unwrap( ) , & authors_filter) ;
754831 assert_eq ! (
@@ -775,7 +852,10 @@ mod tests {
775852
776853 // Other filter
777854 let search_filter = Filter :: new ( ) . search ( "Test" ) . limit ( 10 ) ;
778- match graph. break_down_filter ( search_filter. clone ( ) ) . await {
855+ match graph
856+ . break_down_filter ( search_filter. clone ( ) , GossipFilterPattern :: Nip65 )
857+ . await
858+ {
779859 BrokenDownFilters :: Other ( filter) => {
780860 assert_eq ! ( filter, search_filter) ;
781861 }
@@ -784,7 +864,10 @@ mod tests {
784864
785865 // Single p tags
786866 let p_tag_filter = Filter :: new ( ) . pubkey ( keys_a. public_key ) ;
787- match graph. break_down_filter ( p_tag_filter. clone ( ) ) . await {
867+ match graph
868+ . break_down_filter ( p_tag_filter. clone ( ) , GossipFilterPattern :: Nip65 )
869+ . await
870+ {
788871 BrokenDownFilters :: Filters ( map) => {
789872 assert_eq ! ( map. get( & damus_url) . unwrap( ) , & p_tag_filter) ;
790873 assert_eq ! ( map. get( & nostr_bg_url) . unwrap( ) , & p_tag_filter) ;
@@ -801,7 +884,10 @@ mod tests {
801884 let filter = Filter :: new ( )
802885 . author ( keys_a. public_key )
803886 . pubkey ( keys_b. public_key ) ;
804- match graph. break_down_filter ( filter. clone ( ) ) . await {
887+ match graph
888+ . break_down_filter ( filter. clone ( ) , GossipFilterPattern :: Nip65 )
889+ . await
890+ {
805891 BrokenDownFilters :: Filters ( map) => {
806892 assert_eq ! ( map. get( & damus_url) . unwrap( ) , & filter) ;
807893 assert_eq ! ( map. get( & nostr_bg_url) . unwrap( ) , & filter) ;
@@ -817,7 +903,10 @@ mod tests {
817903 // test orphan filters
818904 let random_keys = Keys :: generate ( ) ;
819905 let filter = Filter :: new ( ) . author ( random_keys. public_key ) ;
820- match graph. break_down_filter ( filter. clone ( ) ) . await {
906+ match graph
907+ . break_down_filter ( filter. clone ( ) , GossipFilterPattern :: Nip65 )
908+ . await
909+ {
821910 BrokenDownFilters :: Orphan ( f) => {
822911 assert_eq ! ( f, filter) ;
823912 }
0 commit comments