From 8d002e025dd249223302c538c06cd844c3528de6 Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Tue, 24 Oct 2023 12:45:37 +0200 Subject: [PATCH] Init `nostr-sdk-redb` crate --- Cargo.lock | 62 ++++++++++++- crates/nostr-sdk-db/src/lib.rs | 3 +- crates/nostr-sdk-redb/Cargo.toml | 18 ++++ crates/nostr-sdk-redb/src/lib.rs | 155 +++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 crates/nostr-sdk-redb/Cargo.toml create mode 100644 crates/nostr-sdk-redb/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fa731eb11..85e8d2da5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,6 +257,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.0" @@ -555,6 +561,16 @@ dependencies = [ "libc", ] +[[package]] +name = "flatbuffers" +version = "23.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + [[package]] name = "flate2" version = "1.0.27" @@ -1109,6 +1125,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "nostr-sdk-fbs" +version = "0.1.0" +dependencies = [ + "flatbuffers", + "nostr", +] + [[package]] name = "nostr-sdk-ffi" version = "0.1.0" @@ -1148,6 +1172,16 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "nostr-sdk-redb" +version = "0.1.0" +dependencies = [ + "nostr-sdk-db", + "nostr-sdk-fbs", + "redb", + "thiserror", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1255,6 +1289,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3-build-config" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" +dependencies = [ + "once_cell", + "target-lexicon", +] + [[package]] name = "quote" version = "1.0.33" @@ -1294,6 +1338,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redb" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58f6da33e3b54de2ef82201ce2b465e67f337deb15d45f54355e0f77202bb4" +dependencies = [ + "libc", + "pyo3-build-config", +] + [[package]] name = "regex" version = "1.9.5" @@ -1414,7 +1468,7 @@ version = "0.38.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -1678,6 +1732,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + [[package]] name = "termcolor" version = "1.3.0" diff --git a/crates/nostr-sdk-db/src/lib.rs b/crates/nostr-sdk-db/src/lib.rs index 1b55b018c..98f77f0cb 100644 --- a/crates/nostr-sdk-db/src/lib.rs +++ b/crates/nostr-sdk-db/src/lib.rs @@ -9,7 +9,8 @@ use std::collections::HashSet; -use async_trait::async_trait; +pub use async_trait::async_trait; +pub use nostr; use nostr::{Event, EventId, Filter, Timestamp, Url}; mod error; diff --git a/crates/nostr-sdk-redb/Cargo.toml b/crates/nostr-sdk-redb/Cargo.toml new file mode 100644 index 000000000..9e85daddc --- /dev/null +++ b/crates/nostr-sdk-redb/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "nostr-sdk-redb" +version = "0.1.0" +edition = "2021" +description = "TODO" +authors = ["Yuki Kishimoto "] +homepage.workspace = true +repository.workspace = true +license.workspace = true +readme = "README.md" +rust-version.workspace = true +keywords = ["nostr", "sdk", "db", "redb"] + +[dependencies] +nostr-sdk-db = { version = "0.1", path = "../nostr-sdk-db" } +nostr-sdk-fbs = { version = "0.1", path = "../nostr-sdk-fbs" } +redb = "1.3" +thiserror = { workspace = true } diff --git a/crates/nostr-sdk-redb/src/lib.rs b/crates/nostr-sdk-redb/src/lib.rs new file mode 100644 index 000000000..632444f26 --- /dev/null +++ b/crates/nostr-sdk-redb/src/lib.rs @@ -0,0 +1,155 @@ +// Copyright (c) 2022-2023 Yuki Kishimoto +// Distributed under the MIT software license + +use std::collections::HashSet; +use std::path::Path; + +use nostr_sdk_db::nostr::{Event, EventId, Filter, Timestamp, Url}; +use nostr_sdk_db::{async_trait, Backend, DatabaseError, DatabaseOptions, NostrDatabase}; +use nostr_sdk_fbs::FlatBufferBuilder; +use redb::{Database, TableDefinition}; +use thiserror::Error; + +const EVENTS: TableDefinition<&[u8], &[u8]> = TableDefinition::new("events"); + +/// Redb Database Error +#[derive(Debug, Error)] +pub enum Error { + /// Redb opening related errors + #[error(transparent)] + RedbOpen(#[from] redb::DatabaseError), + /// Redb transaction errors + #[error(transparent)] + RedbTx(#[from] redb::TransactionError), + /// Redb table errors + #[error(transparent)] + RedbTable(#[from] redb::TableError), + /// Redb storage errors + #[error(transparent)] + RedbStorage(#[from] redb::StorageError), + /// Redb commit errors + #[error(transparent)] + RedbCommit(#[from] redb::CommitError), + /// Redb errors + #[error(transparent)] + Redb(#[from] redb::Error), +} + +impl From for DatabaseError { + fn from(e: Error) -> Self { + DatabaseError::backend(e) + } +} + +/// Redb Database (LMDB-like) +#[derive(Debug)] +pub struct RedbDatabase { + db: Database, +} + +impl RedbDatabase { + pub fn new

(path: P) -> Result + where + P: AsRef, + { + Ok(Self { + db: Database::create(path)?, + }) + } +} + +#[async_trait] +impl NostrDatabase for RedbDatabase { + type Err = DatabaseError; + + fn backend(&self) -> Backend { + Backend::Custom(String::from("redb")) + } + + fn opts(&self) -> DatabaseOptions { + DatabaseOptions::default() + } + + async fn save_event(&self, event: &Event) -> Result { + let write_txn = self.db.begin_write().map_err(DatabaseError::backend)?; + { + // Open table + let mut table = write_txn + .open_table(EVENTS) + .map_err(DatabaseError::backend)?; + + // Serialize event + let mut fbb = FlatBufferBuilder::new(); + let ser = nostr_sdk_fbs::serialize_event(&mut fbb, event); + + // Insert + table + .insert(event.id.as_bytes(), ser) + .map_err(DatabaseError::backend)?; + } + + // Save + write_txn.commit().map_err(DatabaseError::backend)?; + + Ok(true) + } + + async fn has_event_already_been_seen(&self, _event_id: EventId) -> Result { + todo!() + } + + async fn event_id_seen( + &self, + _event_id: EventId, + _relay_url: Option, + ) -> Result<(), Self::Err> { + todo!() + } + + async fn event_ids_seen( + &self, + _event_ids: Vec, + _relay_url: Option, + ) -> Result<(), Self::Err> { + todo!() + } + + async fn event_recently_seen_on_relays( + &self, + _event_id: EventId, + ) -> Result>, Self::Err> { + todo!() + } + + async fn event_by_id(&self, _event_id: EventId) -> Result { + /* let read_txn = self.db.begin_read().map_err(DatabaseError::backend)?; + let table = read_txn + .open_table(EVENTS) + .map_err(DatabaseError::backend)?; + let value = table + .get(b"my_key".as_slice()) + .map_err(DatabaseError::backend)? + .unwrap() + .value(); */ + todo!() + } + + async fn query(&self, _filters: Vec) -> Result, Self::Err> { + todo!() + } + + async fn event_ids_by_filters(&self, _filters: Vec) -> Result, Self::Err> { + todo!() + } + + async fn negentropy_items( + &self, + _filter: &Filter, + ) -> Result, Self::Err> { + todo!() + } + + async fn wipe(&self) -> Result<(), Self::Err> { + todo!() + } +}