upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-08 11:20:35 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-08 11:23:28 +0000
commit5d02ad6b893f9059044914c115d77cf9d8e589c3 (patch)
treeb727f9c44d2f2d4e203dc2344e4c9bd5144a77dd /src/nostr
parent075307804bf66bba10f5bc55cb40e2e6a98a65ee (diff)
refactor: replace hardcoded Kind constants with rust-nostr variants
- Replace KIND_REPOSITORY_ANNOUNCEMENT with Kind::GitRepoAnnouncement - Replace KIND_REPOSITORY_STATE with Kind::RepoState - Replace KIND_PR with Kind::GitPullRequest - Replace KIND_PR_UPDATE with Kind::GitPullRequestUpdate - Replace KIND_USER_GRASP_LIST with Kind::GitUserGraspList - Replace KIND_PATCH with Kind::GitPatch - Replace KIND_ISSUE with Kind::GitIssue - Replace KIND_COMMENT with Kind::Comment - Replace all Kind::Custom(30617|30618|1617|1618|1619|1621|1111|10317) patterns - Remove all hardcoded KIND_* constants from events.rs - Update all match statements to use Kind enum directly - Update all filter builders to use Kind variants - Update all test helpers and assertions Benefits: - Type safety: compiler prevents wrong kind numbers - Readability: Kind::GitRepoAnnouncement is self-documenting - Maintainability: single source of truth (rust-nostr) - IDE support: full autocompletion and refactoring - Standards: aligns with rust-nostr best practices Files modified: 21 Constants removed: 9 Patterns replaced: 100+ Tests passing: 222/222
Diffstat (limited to 'src/nostr')
-rw-r--r--src/nostr/builder.rs17
-rw-r--r--src/nostr/events.rs56
-rw-r--r--src/nostr/policy/announcement.rs14
3 files changed, 37 insertions, 50 deletions
diff --git a/src/nostr/builder.rs b/src/nostr/builder.rs
index 81f7fbb..939ccef 100644
--- a/src/nostr/builder.rs
+++ b/src/nostr/builder.rs
@@ -12,10 +12,7 @@ use nostr_lmdb::NostrLmdb;
12use nostr_relay_builder::prelude::*; 12use nostr_relay_builder::prelude::*;
13 13
14use crate::config::{Config, DatabaseBackend}; 14use crate::config::{Config, DatabaseBackend};
15use crate::nostr::events::{ 15use crate::nostr::events::RepositoryAnnouncement;
16 RepositoryAnnouncement, KIND_PR, KIND_PR_UPDATE, KIND_REPOSITORY_ANNOUNCEMENT,
17 KIND_REPOSITORY_STATE, KIND_USER_GRASP_LIST,
18};
19use crate::nostr::policy::{ 16use crate::nostr::policy::{
20 AnnouncementPolicy, AnnouncementResult, PolicyContext, PrEventPolicy, ReferenceResult, 17 AnnouncementPolicy, AnnouncementResult, PolicyContext, PrEventPolicy, ReferenceResult,
21 RelatedEventPolicy, StatePolicy, StateResult, 18 RelatedEventPolicy, StatePolicy, StateResult,
@@ -377,11 +374,13 @@ impl WritePolicy for Nip34WritePolicy {
377 // Sync uses localhost:0 as a dummy address 374 // Sync uses localhost:0 as a dummy address
378 let is_synced = addr.ip().is_loopback() && addr.port() == 0; 375 let is_synced = addr.ip().is_loopback() && addr.port() == 0;
379 376
380 match event.kind.as_u16() { 377 match event.kind {
381 KIND_REPOSITORY_ANNOUNCEMENT => self.handle_announcement(event).await, 378 Kind::GitRepoAnnouncement => self.handle_announcement(event).await,
382 KIND_REPOSITORY_STATE => self.handle_state(event, is_synced).await, 379 Kind::RepoState => self.handle_state(event, is_synced).await,
383 KIND_PR | KIND_PR_UPDATE => self.handle_pr_event(event, is_synced).await, 380 Kind::GitPullRequest | Kind::GitPullRequestUpdate => {
384 KIND_USER_GRASP_LIST => { 381 self.handle_pr_event(event, is_synced).await
382 }
383 Kind::GitUserGraspList => {
385 // Accept all kind 10317 (User Grasp List) events 384 // Accept all kind 10317 (User Grasp List) events
386 // for better GRASP repository discovery 385 // for better GRASP repository discovery
387 tracing::debug!( 386 tracing::debug!(
diff --git a/src/nostr/events.rs b/src/nostr/events.rs
index 1fcb75e..4f7c907 100644
--- a/src/nostr/events.rs
+++ b/src/nostr/events.rs
@@ -9,20 +9,12 @@
9use anyhow::{anyhow, Result}; 9use anyhow::{anyhow, Result};
10use nostr_sdk::{Event, Kind, TagKind, ToBech32}; 10use nostr_sdk::{Event, Kind, TagKind, ToBech32};
11 11
12/// NIP-34 Repository Announcement (kind 30617) 12// NOTE: Using rust-nostr Kind variants instead of hardcoded constants:
13pub const KIND_REPOSITORY_ANNOUNCEMENT: u16 = 30617; 13// - KIND_REPOSITORY_ANNOUNCEMENT -> Kind::GitRepoAnnouncement (30617)
14 14// - KIND_REPOSITORY_STATE -> Kind::RepoState (30618)
15/// NIP-34 Repository State Announcement (kind 30618) 15// - KIND_PR -> Kind::GitPullRequest (1618)
16pub const KIND_REPOSITORY_STATE: u16 = 30618; 16// - KIND_PR_UPDATE -> Kind::GitPullRequestUpdate (1619)
17 17// - KIND_USER_GRASP_LIST -> Kind::GitUserGraspList (10317)
18/// NIP-34 Pull Request (kind 1618) - has `c` tag for commit
19pub const KIND_PR: u16 = 1618;
20
21/// NIP-34 Pull Request Update (kind 1619) - has `c` tag for commit
22pub const KIND_PR_UPDATE: u16 = 1619;
23
24/// User Grasp List (kind 10317) - user's personal list of GRASP repositories
25pub const KIND_USER_GRASP_LIST: u16 = 10317;
26 18
27/// Repository announcement details extracted from NIP-34 event 19/// Repository announcement details extracted from NIP-34 event
28#[derive(Debug, Clone)] 20#[derive(Debug, Clone)]
@@ -40,10 +32,10 @@ pub struct RepositoryAnnouncement {
40impl RepositoryAnnouncement { 32impl RepositoryAnnouncement {
41 /// Parse a repository announcement from a NIP-34 kind 30617 event 33 /// Parse a repository announcement from a NIP-34 kind 30617 event
42 pub fn from_event(event: Event) -> Result<Self> { 34 pub fn from_event(event: Event) -> Result<Self> {
43 if event.kind != Kind::from(KIND_REPOSITORY_ANNOUNCEMENT) { 35 if event.kind != Kind::GitRepoAnnouncement {
44 return Err(anyhow!( 36 return Err(anyhow!(
45 "Invalid event kind: expected {}, got {}", 37 "Invalid event kind: expected {}, got {}",
46 KIND_REPOSITORY_ANNOUNCEMENT, 38 Kind::GitRepoAnnouncement,
47 event.kind 39 event.kind
48 )); 40 ));
49 } 41 }
@@ -197,10 +189,10 @@ pub struct TagState {
197impl RepositoryState { 189impl RepositoryState {
198 /// Parse a repository state from a NIP-34 kind 30618 event 190 /// Parse a repository state from a NIP-34 kind 30618 event
199 pub fn from_event(event: Event) -> Result<Self> { 191 pub fn from_event(event: Event) -> Result<Self> {
200 if event.kind != Kind::from(KIND_REPOSITORY_STATE) { 192 if event.kind != Kind::RepoState {
201 return Err(anyhow!( 193 return Err(anyhow!(
202 "Invalid event kind: expected {}, got {}", 194 "Invalid event kind: expected {}, got {}",
203 KIND_REPOSITORY_STATE, 195 Kind::RepoState,
204 event.kind 196 event.kind
205 )); 197 ));
206 } 198 }
@@ -346,10 +338,10 @@ impl RepositoryState {
346/// Returns Ok(()) if valid, Err with reason if invalid. 338/// Returns Ok(()) if valid, Err with reason if invalid.
347pub fn validate_announcement(event: &Event, domain: &str) -> Result<()> { 339pub fn validate_announcement(event: &Event, domain: &str) -> Result<()> {
348 // Must be kind 30617 340 // Must be kind 30617
349 if event.kind != Kind::from(KIND_REPOSITORY_ANNOUNCEMENT) { 341 if event.kind != Kind::GitRepoAnnouncement {
350 return Err(anyhow!( 342 return Err(anyhow!(
351 "Invalid kind: expected {}", 343 "Invalid kind: expected {}",
352 KIND_REPOSITORY_ANNOUNCEMENT 344 Kind::GitRepoAnnouncement
353 )); 345 ));
354 } 346 }
355 347
@@ -381,8 +373,8 @@ pub fn validate_announcement(event: &Event, domain: &str) -> Result<()> {
381/// Returns Ok(()) if valid, Err with reason if invalid. 373/// Returns Ok(()) if valid, Err with reason if invalid.
382pub fn validate_state(event: &Event) -> Result<()> { 374pub fn validate_state(event: &Event) -> Result<()> {
383 // Must be kind 30618 375 // Must be kind 30618
384 if event.kind != Kind::from(KIND_REPOSITORY_STATE) { 376 if event.kind != Kind::RepoState {
385 return Err(anyhow!("Invalid kind: expected {}", KIND_REPOSITORY_STATE)); 377 return Err(anyhow!("Invalid kind: expected {}", Kind::RepoState));
386 } 378 }
387 379
388 // Must have identifier 380 // Must have identifier
@@ -433,7 +425,7 @@ mod tests {
433 )); 425 ));
434 } 426 }
435 427
436 EventBuilder::new(Kind::from(KIND_REPOSITORY_ANNOUNCEMENT), "Test repository") 428 EventBuilder::new(Kind::GitRepoAnnouncement, "Test repository")
437 .tags(tags) 429 .tags(tags)
438 .sign_with_keys(keys) 430 .sign_with_keys(keys)
439 .unwrap() 431 .unwrap()
@@ -454,7 +446,7 @@ mod tests {
454 )); 446 ));
455 } 447 }
456 448
457 EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 449 EventBuilder::new(Kind::RepoState, "")
458 .tags(tags) 450 .tags(tags)
459 .sign_with_keys(keys) 451 .sign_with_keys(keys)
460 .unwrap() 452 .unwrap()
@@ -483,7 +475,7 @@ mod tests {
483 #[test] 475 #[test]
484 fn test_parse_announcement_missing_identifier() { 476 fn test_parse_announcement_missing_identifier() {
485 let keys = create_test_keys(); 477 let keys = create_test_keys();
486 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_ANNOUNCEMENT), "Test repository") 478 let event = EventBuilder::new(Kind::GitRepoAnnouncement, "Test repository")
487 .sign_with_keys(&keys) 479 .sign_with_keys(&keys)
488 .unwrap(); 480 .unwrap();
489 481
@@ -579,7 +571,7 @@ mod tests {
579 #[test] 571 #[test]
580 fn test_validate_state_missing_identifier() { 572 fn test_validate_state_missing_identifier() {
581 let keys = create_test_keys(); 573 let keys = create_test_keys();
582 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 574 let event = EventBuilder::new(Kind::RepoState, "")
583 .sign_with_keys(&keys) 575 .sign_with_keys(&keys)
584 .unwrap(); 576 .unwrap();
585 577
@@ -614,7 +606,7 @@ mod tests {
614 vec![maintainer_keys.public_key().to_hex()], 606 vec![maintainer_keys.public_key().to_hex()],
615 )); 607 ));
616 608
617 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_ANNOUNCEMENT), "Test repository") 609 let event = EventBuilder::new(Kind::GitRepoAnnouncement, "Test repository")
618 .tags(tags) 610 .tags(tags)
619 .sign_with_keys(&keys) 611 .sign_with_keys(&keys)
620 .unwrap(); 612 .unwrap();
@@ -649,7 +641,7 @@ mod tests {
649 vec!["e5f6g7h8".to_string()], 641 vec!["e5f6g7h8".to_string()],
650 )); 642 ));
651 643
652 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 644 let event = EventBuilder::new(Kind::RepoState, "")
653 .tags(tags) 645 .tags(tags)
654 .sign_with_keys(&keys) 646 .sign_with_keys(&keys)
655 .unwrap(); 647 .unwrap();
@@ -683,7 +675,7 @@ mod tests {
683 vec!["ref: refs/heads/main".to_string()], 675 vec!["ref: refs/heads/main".to_string()],
684 )); 676 ));
685 677
686 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 678 let event = EventBuilder::new(Kind::RepoState, "")
687 .tags(tags) 679 .tags(tags)
688 .sign_with_keys(&keys) 680 .sign_with_keys(&keys)
689 .unwrap(); 681 .unwrap();
@@ -716,7 +708,7 @@ mod tests {
716 vec!["refs/heads/develop".to_string()], 708 vec!["refs/heads/develop".to_string()],
717 )); 709 ));
718 710
719 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 711 let event = EventBuilder::new(Kind::RepoState, "")
720 .tags(tags) 712 .tags(tags)
721 .sign_with_keys(&keys) 713 .sign_with_keys(&keys)
722 .unwrap(); 714 .unwrap();
@@ -740,7 +732,7 @@ mod tests {
740 ), 732 ),
741 ]; 733 ];
742 734
743 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 735 let event = EventBuilder::new(Kind::RepoState, "")
744 .tags(tags) 736 .tags(tags)
745 .sign_with_keys(&keys) 737 .sign_with_keys(&keys)
746 .unwrap(); 738 .unwrap();
@@ -773,7 +765,7 @@ mod tests {
773 vec!["refs/heads/develop".to_string()], 765 vec!["refs/heads/develop".to_string()],
774 )); 766 ));
775 767
776 let event = EventBuilder::new(Kind::from(KIND_REPOSITORY_STATE), "") 768 let event = EventBuilder::new(Kind::RepoState, "")
777 .tags(tags) 769 .tags(tags)
778 .sign_with_keys(&keys) 770 .sign_with_keys(&keys)
779 .unwrap(); 771 .unwrap();
diff --git a/src/nostr/policy/announcement.rs b/src/nostr/policy/announcement.rs
index 353738b..61840fb 100644
--- a/src/nostr/policy/announcement.rs
+++ b/src/nostr/policy/announcement.rs
@@ -5,9 +5,7 @@
5use nostr_relay_builder::prelude::{Alphabet, Event, Filter, Kind, PublicKey, SingleLetterTag}; 5use nostr_relay_builder::prelude::{Alphabet, Event, Filter, Kind, PublicKey, SingleLetterTag};
6 6
7use super::PolicyContext; 7use super::PolicyContext;
8use crate::nostr::events::{ 8use crate::nostr::events::{validate_announcement, RepositoryAnnouncement};
9 validate_announcement, RepositoryAnnouncement, KIND_REPOSITORY_ANNOUNCEMENT,
10};
11 9
12/// Result of announcement policy evaluation 10/// Result of announcement policy evaluation
13#[derive(Debug)] 11#[derive(Debug)]
@@ -121,12 +119,10 @@ impl AnnouncementPolicy {
121 author: &PublicKey, 119 author: &PublicKey,
122 ) -> Result<bool, String> { 120 ) -> Result<bool, String> {
123 // Query all announcements with this identifier that are already in the database 121 // Query all announcements with this identifier that are already in the database
124 let filter = Filter::new() 122 let filter = Filter::new().kind(Kind::GitRepoAnnouncement).custom_tag(
125 .kind(Kind::from(KIND_REPOSITORY_ANNOUNCEMENT)) 123 SingleLetterTag::lowercase(Alphabet::D),
126 .custom_tag( 124 identifier.to_string(),
127 SingleLetterTag::lowercase(Alphabet::D), 125 );
128 identifier.to_string(),
129 );
130 126
131 let announcements: Vec<Event> = match self.ctx.database.query(filter).await { 127 let announcements: Vec<Event> = match self.ctx.database.query(filter).await {
132 Ok(events) => events.into_iter().collect(), 128 Ok(events) => events.into_iter().collect(),