Skip to content

Commit c55ebb1

Browse files
committed
Add nostr-gossip crate
Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent a499845 commit c55ebb1

File tree

11 files changed

+246
-0
lines changed

11 files changed

+246
-0
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
- nostr-blossom
3636
- nostr-http-file-storage
3737
- nostr-database
38+
- nostr-gossip
3839
- nostr-lmdb
3940
- nostr-indexeddb --target wasm32-unknown-unknown
4041
- nostr-ndb

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ members = [
88
"database/nostr-lmdb",
99
"database/nostr-ndb",
1010

11+
# Gossip
12+
"gossip/nostr-gossip",
13+
1114
# Remote File Storage implementations
1215
"rfs/nostr-blossom",
1316
"rfs/nostr-http-file-storage",
@@ -39,6 +42,7 @@ negentropy = { version = "0.5", default-features = false }
3942
nostr = { version = "0.43", path = "./crates/nostr", default-features = false }
4043
nostr-connect = { version = "0.43", path = "./signer/nostr-connect", default-features = false }
4144
nostr-database = { version = "0.43", path = "./database/nostr-database", default-features = false }
45+
nostr-gossip = { version = "0.43.0", path = "./gossip/nostr-gossip", default-features = false }
4246
nostr-lmdb = { version = "0.43", path = "./database/nostr-lmdb", default-features = false }
4347
nostr-ndb = { version = "0.43", path = "./database/nostr-ndb", default-features = false }
4448
nostr-relay-builder = { version = "0.43", path = "./crates/nostr-relay-builder", default-features = false }

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The project is split up into several crates:
1313
- [**nostr-lmdb**](./database/nostr-lmdb): LMDB storage backend
1414
- [**nostr-ndb**](./database/nostr-ndb): [nostrdb](https://github.com/damus-io/nostrdb) storage backend
1515
- [**nostr-indexeddb**](./database/nostr-indexeddb): IndexedDB storage backend
16+
- [**nostr-gossip**](./gossip/nostr-gossip): Gossip traits
1617
- Remote File Storage implementations:
1718
- [**nostr-blossom**](./rfs/nostr-blossom): A library for interacting with the Blossom protocol
1819
- [**nostr-http-file-storage**](./rfs/nostr-http-file-storage): HTTP File Storage client (NIP-96)

contrib/scripts/check-crates.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ buildargs=(
3434
"-p nostr-blossom"
3535
"-p nostr-http-file-storage"
3636
"-p nostr-database"
37+
"-p nostr-gossip"
3738
"-p nostr-lmdb"
3839
"-p nostr-indexeddb --target wasm32-unknown-unknown"
3940
"-p nostr-ndb"

gossip/nostr-gossip/CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Changelog
2+
3+
<!-- All notable changes to this project will be documented in this file. -->
4+
5+
<!-- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -->
6+
<!-- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -->
7+
8+
<!-- Template
9+
10+
## Unreleased
11+
12+
### Breaking changes
13+
14+
### Changed
15+
16+
### Added
17+
18+
### Fixed
19+
20+
### Removed
21+
22+
### Deprecated
23+
24+
-->
25+
26+
## Unreleased
27+
28+
First release.

gossip/nostr-gossip/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "nostr-gossip"
3+
version = "0.43.0"
4+
edition = "2021"
5+
description = "Nostr gossip traits"
6+
authors.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
license.workspace = true
10+
readme = "README.md"
11+
rust-version.workspace = true
12+
keywords = ["nostr", "gossip"]
13+
14+
[dependencies]
15+
nostr = { workspace = true, features = ["std"] }

gossip/nostr-gossip/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Nostr gossip traits
2+
3+
## Changelog
4+
5+
All notable changes to this library are documented in the [CHANGELOG.md](CHANGELOG.md).
6+
7+
## State
8+
9+
**This library is in an ALPHA state**, things that are implemented generally work but the API will change in breaking ways.
10+
11+
## Donations
12+
13+
`rust-nostr` is free and open-source. This means we do not earn any revenue by selling it. Instead, we rely on your financial support. If you actively use any of the `rust-nostr` libs/software/services, then please [donate](https://rust-nostr.org/donate).
14+
15+
## License
16+
17+
This project is distributed under the MIT software license - see the [LICENSE](../../LICENSE) file for details

gossip/nostr-gossip/src/error.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2022-2023 Yuki Kishimoto
2+
// Copyright (c) 2023-2025 Rust Nostr Developers
3+
// Distributed under the MIT software license
4+
5+
//! Nostr Gossip error
6+
7+
use std::fmt;
8+
9+
/// Gossip Error
10+
#[derive(Debug)]
11+
pub enum GossipError {
12+
/// An error happened in the underlying database backend.
13+
Backend(Box<dyn std::error::Error + Send + Sync>),
14+
}
15+
16+
impl std::error::Error for GossipError {}
17+
18+
impl fmt::Display for GossipError {
19+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
match self {
21+
Self::Backend(e) => e.fmt(f),
22+
}
23+
}
24+
}
25+
26+
impl GossipError {
27+
/// Create a new backend error
28+
///
29+
/// Shorthand for `Error::Backend(Box::new(error))`.
30+
#[inline]
31+
pub fn backend<E>(error: E) -> Self
32+
where
33+
E: std::error::Error + Send + Sync + 'static,
34+
{
35+
Self::Backend(Box::new(error))
36+
}
37+
}

gossip/nostr-gossip/src/lib.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright (c) 2022-2023 Yuki Kishimoto
2+
// Copyright (c) 2023-2025 Rust Nostr Developers
3+
// Distributed under the MIT software license
4+
5+
//! Nostr Gossip
6+
7+
#![forbid(unsafe_code)]
8+
#![warn(missing_docs)]
9+
#![warn(rustdoc::bare_urls)]
10+
#![warn(clippy::large_futures)]
11+
12+
use std::any::Any;
13+
use std::collections::HashSet;
14+
use std::fmt::Debug;
15+
16+
use nostr::prelude::*;
17+
18+
pub mod error;
19+
pub mod prelude;
20+
21+
use self::error::GossipError;
22+
23+
/// Gossip list kind
24+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25+
pub enum GossipListKind {
26+
/// NIP-17
27+
Nip17,
28+
/// NIP-65
29+
Nip65,
30+
}
31+
32+
/// Public key status
33+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
34+
pub enum GossipPublicKeyStatus {
35+
/// The public key data is updated
36+
Updated,
37+
/// The public key data is outdated
38+
Outdated,
39+
}
40+
41+
impl GossipPublicKeyStatus {
42+
/// Check if the public key data is outdated
43+
#[inline]
44+
pub fn is_outdated(&self) -> bool {
45+
matches!(self, Self::Outdated)
46+
}
47+
}
48+
49+
/// Best relay selection.
50+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
51+
pub enum BestRelaySelection {
52+
/// Get all the best relays for **reading** and **writing** events (NIP-65)
53+
All {
54+
/// Limit for read relays
55+
read: usize,
56+
/// Limit for write relays
57+
write: usize,
58+
/// Limit for hints
59+
hints: usize,
60+
/// Limit for most received relays
61+
most_received: usize,
62+
},
63+
/// Get the best relays for **reading** events (NIP-65)
64+
Read {
65+
/// Limit
66+
limit: usize,
67+
},
68+
/// Get the best relays for **writing** events (NIP-65)
69+
Write {
70+
/// Limit
71+
limit: usize,
72+
},
73+
/// Get the best relays for **reading** and **writing** private messages (NIP-17)
74+
PrivateMessage {
75+
/// Limit
76+
limit: usize,
77+
},
78+
/// Relays found in hints
79+
Hints {
80+
/// Limit
81+
limit: usize,
82+
},
83+
/// Relays that received most events
84+
MostReceived {
85+
/// Limit
86+
limit: usize,
87+
},
88+
}
89+
90+
/// Nostr gossip trait.
91+
pub trait NostrGossip: Any + Debug + Send + Sync {
92+
/// Process an [`Event`]
93+
///
94+
/// Optionally takes the [`RelayUrl`] from where the [`Event`] comes from.
95+
fn process<'a>(
96+
&'a self,
97+
event: &'a Event,
98+
relay_url: Option<&'a RelayUrl>,
99+
) -> BoxedFuture<'a, Result<(), GossipError>>;
100+
101+
/// Check the [`PublicKey`] status
102+
fn status<'a>(
103+
&'a self,
104+
public_key: &'a PublicKey,
105+
list: GossipListKind,
106+
) -> BoxedFuture<'a, Result<GossipPublicKeyStatus, GossipError>>;
107+
108+
/// Update the last check timestamp for stale [`PublicKey`].
109+
fn update_fetch_attempt<'a>(
110+
&'a self,
111+
public_key: &'a PublicKey,
112+
list: GossipListKind,
113+
) -> BoxedFuture<'a, Result<(), GossipError>>;
114+
115+
/// Get the best relays for a [`PublicKey`].
116+
fn get_best_relays<'a>(
117+
&'a self,
118+
public_key: &'a PublicKey,
119+
selection: BestRelaySelection,
120+
) -> BoxedFuture<'a, Result<HashSet<RelayUrl>, GossipError>>;
121+
}

0 commit comments

Comments
 (0)