Skip to content

Commit a34669c

Browse files
committed
Refactoring
Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 2d8ac36 commit a34669c

File tree

9 files changed

+262
-164
lines changed

9 files changed

+262
-164
lines changed

crates/nostr-sdk/examples/bot.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@
22
// Copyright (c) 2023-2025 Rust Nostr Developers
33
// Distributed under the MIT software license
44

5+
use nostr_gossip_sqlite::prelude::*;
56
use nostr_sdk::prelude::*;
67

78
#[tokio::main]
89
async fn main() -> Result<()> {
910
tracing_subscriber::fmt::init();
1011

1112
let keys = Keys::parse("nsec12kcgs78l06p30jz7z7h3n2x2cy99nw2z6zspjdp7qc206887mwvs95lnkx")?;
13+
let gossip = NostrGossipSqlite::open("db/gossip.db").await?;
1214
let client = Client::builder()
1315
.signer(keys.clone())
14-
.opts(ClientOptions::new().gossip(true))
16+
.gossip(gossip)
1517
.build();
1618

1719
println!("Bot public key: {}", keys.public_key().to_bech32()?);

crates/nostr-sdk/src/client/mod.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::time::Duration;
1313
use async_utility::futures_util::stream::{BoxStream, FuturesUnordered};
1414
use nostr::prelude::*;
1515
use nostr_database::prelude::*;
16-
use nostr_gossip::{BestRelaySelection, GossipListKind, NostrGossip};
16+
use nostr_gossip::{BestRelaySelection, GossipListKind, GossipPublicKeyStatus, NostrGossip};
1717
use nostr_relay_pool::prelude::*;
1818
use tokio::sync::{broadcast, Semaphore};
1919

@@ -1339,14 +1339,14 @@ impl Client {
13391339
where
13401340
I: IntoIterator<Item = PublicKey>,
13411341
{
1342-
let mut outdated_public_keys: HashSet<PublicKey> = HashSet::new();
1342+
let mut outdated_public_keys: HashMap<PublicKey, Timestamp> = HashMap::new();
13431343

13441344
for public_key in public_keys.into_iter() {
13451345
// Get the public key status
13461346
let status = gossip.status(&public_key, gossip_kind).await?;
13471347

1348-
if status.is_outdated() {
1349-
outdated_public_keys.insert(public_key);
1348+
if let GossipPublicKeyStatus::Outdated { created_at } = status {
1349+
outdated_public_keys.insert(public_key, created_at.unwrap_or_default());
13501350
}
13511351
}
13521352

@@ -1363,7 +1363,7 @@ impl Client {
13631363

13641364
// Compose database filter
13651365
let db_filter: Filter = Filter::default()
1366-
.authors(outdated_public_keys.clone())
1366+
.authors(outdated_public_keys.keys().copied())
13671367
.kind(kind);
13681368

13691369
// Get events from database
@@ -1387,9 +1387,7 @@ impl Client {
13871387
let mut futures = FuturesUnordered::new();
13881388

13891389
// Try to fetch from relays only the newer events (last created_at + 1)
1390-
for event in stored_events.iter() {
1391-
let author = event.pubkey;
1392-
let created_at = event.created_at;
1390+
for (author, created_at) in outdated_public_keys.iter() {
13931391
let urls = urls.clone();
13941392
let semaphore = semaphore.clone();
13951393

@@ -1399,9 +1397,9 @@ impl Client {
13991397

14001398
// Construct filter
14011399
let filter: Filter = Filter::new()
1402-
.author(author)
1400+
.author(*author)
14031401
.kind(kind)
1404-
.since(created_at + Duration::from_secs(1))
1402+
.since(*created_at + Duration::from_secs(1))
14051403
.limit(1);
14061404

14071405
// Fetch the event
@@ -1415,7 +1413,8 @@ impl Client {
14151413
}
14161414

14171415
// Keep track of the missing public keys
1418-
let mut missing_public_keys: HashSet<PublicKey> = outdated_public_keys;
1416+
let mut missing_public_keys: HashSet<PublicKey> =
1417+
outdated_public_keys.keys().copied().collect();
14191418

14201419
while let Some(result) = futures.next().await {
14211420
if let Ok(events) = result {

gossip/nostr-gossip-sqlite/doc/database.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
- `id`: Public Key ID
66
- `public_key`: Public Key 32-byte array
77

8+
## Lists table
9+
10+
- `event_created_at`: UNIX timestamp
11+
- `last_checked_at`: UNIX timestamp of the last check
12+
813
## Relays table
914

1015
- `id`: Relay ID
11-
12-
TODO
16+
- `url`: Relay URL

gossip/nostr-gossip-sqlite/migrations/001_init.sql

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,23 @@ PRAGMA foreign_keys = ON;
33
CREATE TABLE public_keys(
44
id INTEGER PRIMARY KEY AUTOINCREMENT,
55
public_key BLOB NOT NULL UNIQUE,
6-
last_nip17_update BIGINT DEFAULT NULL,
7-
last_nip65_update BIGINT DEFAULT NULL,
86
CHECK (length(public_key) = 32)
97
);
108

119
CREATE INDEX idx_public_keys_public_key ON public_keys(public_key);
1210

11+
CREATE TABLE lists(
12+
id INTEGER PRIMARY KEY AUTOINCREMENT,
13+
public_key_id INTEGER NOT NULL,
14+
event_kind INTEGER NOT NULL,
15+
event_created_at BIGINT DEFAULT NULL,
16+
last_checked_at BIGINT DEFAULT NULL,
17+
UNIQUE(public_key_id, event_kind),
18+
FOREIGN KEY (public_key_id) REFERENCES public_keys(id) ON DELETE CASCADE
19+
);
20+
21+
CREATE INDEX idx_lists_pub_kind ON lists(public_key_id, event_kind);
22+
1323
CREATE TABLE relays(
1424
id INTEGER PRIMARY KEY AUTOINCREMENT,
1525
url TEXT NOT NULL UNIQUE

gossip/nostr-gossip-sqlite/src/constant.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@
44

55
use std::time::Duration;
66

7+
use crate::flags::Flags;
8+
79
pub(super) const PUBKEY_METADATA_OUTDATED_AFTER: Duration = Duration::from_secs(60 * 60); // 60 min
10+
11+
pub(super) const READ_WRITE_FLAGS: Flags = Flags::read_write();

gossip/nostr-gossip-sqlite/src/flags.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
use sqlx::encode::IsNull;
2+
use sqlx::error::BoxDynError;
3+
use sqlx::sqlite::SqliteTypeInfo;
4+
use sqlx::{Database, Encode, Sqlite, Type};
5+
16
pub(crate) struct Flags(u16);
27

38
impl Flags {
4-
//pub(crate) const NONE: Self = Self(0); // 0
9+
pub(crate) const NONE: Self = Self(0); // 0
510

611
pub(crate) const READ: Self = Self(1 << 0); // 1
712

@@ -13,11 +18,19 @@ impl Flags {
1318

1419
pub(crate) const RECEIVED: Self = Self(1 << 4); // 16
1520

16-
// /// New empty flags.
17-
// #[inline]
18-
// pub(crate) const fn new() -> Self {
19-
// Self::NONE
20-
// }
21+
/// New empty flags.
22+
#[inline]
23+
pub(crate) const fn new() -> Self {
24+
Self::NONE
25+
}
26+
27+
/// New flags with [`READ`] and [`WRITE`].
28+
pub(crate) const fn read_write() -> Self {
29+
let mut flags: Self = Self::new();
30+
flags.add(Self::READ);
31+
flags.add(Self::WRITE);
32+
flags
33+
}
2134

2235
/// Add flag.
2336
#[inline]
@@ -32,7 +45,23 @@ impl Flags {
3245
// }
3346

3447
#[inline]
35-
pub(crate) const fn as_u16(&self) -> u16 {
48+
const fn as_u16(&self) -> u16 {
3649
self.0
3750
}
3851
}
52+
53+
impl Type<Sqlite> for Flags {
54+
fn type_info() -> SqliteTypeInfo {
55+
<u16 as Type<Sqlite>>::type_info()
56+
}
57+
}
58+
59+
impl<'a> Encode<'a, Sqlite> for Flags {
60+
fn encode_by_ref(
61+
&self,
62+
buf: &mut <Sqlite as Database>::ArgumentBuffer<'a>,
63+
) -> Result<IsNull, BoxDynError> {
64+
let val: u16 = self.as_u16();
65+
<u16 as Encode<Sqlite>>::encode_by_ref(&val, buf)
66+
}
67+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use sqlx::FromRow;
22

33
#[derive(FromRow)]
4-
pub(super) struct PublicKeyRow {
5-
pub(super) last_nip17_update: Option<i64>,
6-
pub(super) last_nip65_update: Option<i64>,
4+
pub(super) struct ListRow {
5+
pub(super) event_created_at: Option<i64>,
6+
pub(super) last_checked_at: Option<i64>,
77
}

0 commit comments

Comments
 (0)