From 2f662f8be0b3ace8e62a54ccf34f4bf14c593f74 Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Thu, 12 Dec 2024 10:24:22 +0100 Subject: [PATCH] database: add `SaveEventStatus` enum Return `SaveEventStatus` enum instead of `bool` for `NostrEventsDatabase::save_event` method to provide more detailed feedback about event insertion. This change includes support for rejection reasons. Closes https://github.com/rust-nostr/nostr/issues/673 Signed-off-by: Yuki Kishimoto --- CHANGELOG.md | 2 + bindings/nostr-sdk-ffi/src/database/mod.rs | 59 ++++++++++++++-- bindings/nostr-sdk-js/src/database/mod.rs | 43 ++++++++++-- crates/nostr-cli/src/main.rs | 4 +- crates/nostr-database/src/events/helper.rs | 70 ++++++++++--------- crates/nostr-database/src/events/mod.rs | 42 +++++++++-- crates/nostr-database/src/lib.rs | 1 + crates/nostr-database/src/memory.rs | 10 +-- crates/nostr-indexeddb/src/lib.rs | 17 ++--- crates/nostr-lmdb/src/lib.rs | 24 ++++--- crates/nostr-lmdb/src/store/mod.rs | 26 +++---- crates/nostr-ndb/src/lib.rs | 5 +- crates/nostr-relay-builder/src/local/inner.rs | 3 +- 13 files changed, 213 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb4c95f3..d91ae6476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * nostr: refactor `MachineReadablePrefix::parse` method to use `&str` directly ([Yuki Kishimoto]) * nostr: update `RelayMessage::Notice` variant ([Yuki Kishimoto]) * database: reduce default in-memory database limit to `35_000` ([Yuki Kishimoto]) +* database: update `NostrEventsDatabase::save_event` method signature ([Yuki Kishimoto]) * pool: replace `Option` with `String` in `Output::failed` ([Yuki Kishimoto]) * sdk: update `fetch_*` and `stream_*` methods signature ([Yuki Kishimoto]) * bindings: remove redundant parsing methods from `EventId`, `Coordinate`, `PublicKey` and `SecretKey` ([Yuki Kishimoto]) @@ -64,6 +65,7 @@ * nostr: add `Tags::challenge` method ([Yuki Kishimoto]) * nostr: add `RelayUrl::is_local_addr` ([Yuki Kishimoto]) * database: impl PartialEq and Eq for `Events` ([Yuki Kishimoto]) +* database: add `SaveEventStatus` enum ([Yuki Kishimoto]) * pool: add `ReceiverStream` ([Yuki Kishimoto]) * sdk: automatically resend event after NIP-42 authentication ([Yuki Kishimoto]) * relay-builder: add NIP42 support ([Yuki Kishimoto]) diff --git a/bindings/nostr-sdk-ffi/src/database/mod.rs b/bindings/nostr-sdk-ffi/src/database/mod.rs index f6c39b410..edd67f4dd 100644 --- a/bindings/nostr-sdk-ffi/src/database/mod.rs +++ b/bindings/nostr-sdk-ffi/src/database/mod.rs @@ -10,7 +10,7 @@ use nostr_sdk::prelude::{self, IntoNostrDatabase, NostrEventsDatabaseExt}; use nostr_sdk::NdbDatabase; #[cfg(feature = "lmdb")] use nostr_sdk::NostrLMDB; -use uniffi::Object; +use uniffi::{Enum, Object}; pub mod events; @@ -18,6 +18,57 @@ use self::events::Events; use crate::error::Result; use crate::protocol::{Event, EventId, Filter, Metadata, PublicKey}; +/// Reason why event wasn't stored into the database +#[derive(Enum)] +pub enum RejectedReason { + /// Ephemeral events aren't expected to be stored + Ephemeral, + /// The event already exists + Duplicate, + /// The event was deleted + Deleted, + /// The event is expired + Expired, + /// The event was replaced + Replaced, + /// Attempt to delete a non-owned event + InvalidDelete, + /// Other reason + Other, +} + +impl From for RejectedReason { + fn from(status: prelude::RejectedReason) -> Self { + match status { + prelude::RejectedReason::Ephemeral => Self::Ephemeral, + prelude::RejectedReason::Duplicate => Self::Duplicate, + prelude::RejectedReason::Deleted => Self::Deleted, + prelude::RejectedReason::Expired => Self::Expired, + prelude::RejectedReason::Replaced => Self::Replaced, + prelude::RejectedReason::InvalidDelete => Self::InvalidDelete, + prelude::RejectedReason::Other => Self::Other, + } + } +} + +/// Save event status +#[derive(Enum)] +pub enum SaveEventStatus { + /// The event has been successfully saved + Success, + /// The event has been rejected + Rejected(RejectedReason), +} + +impl From for SaveEventStatus { + fn from(status: prelude::SaveEventStatus) -> Self { + match status { + prelude::SaveEventStatus::Success => Self::Success, + prelude::SaveEventStatus::Rejected(reason) => Self::Rejected(reason.into()), + } + } +} + #[derive(Object)] pub struct NostrDatabase { inner: Arc, @@ -69,10 +120,8 @@ impl NostrDatabase { // TODO: re-allow to use custom database (only for events)? /// Save [`Event`] into store - /// - /// Return `true` if event was successfully saved into database. - pub async fn save_event(&self, event: &Event) -> Result { - Ok(self.inner.save_event(event.deref()).await?) + pub async fn save_event(&self, event: &Event) -> Result { + Ok(self.inner.save_event(event.deref()).await?.into()) } /// Get list of relays that have seen the [`EventId`] diff --git a/bindings/nostr-sdk-js/src/database/mod.rs b/bindings/nostr-sdk-js/src/database/mod.rs index cf43f9c71..6f2caacbc 100644 --- a/bindings/nostr-sdk-js/src/database/mod.rs +++ b/bindings/nostr-sdk-js/src/database/mod.rs @@ -18,6 +18,41 @@ use crate::protocol::key::JsPublicKey; use crate::protocol::types::{JsFilter, JsMetadata}; use crate::JsStringArray; +#[wasm_bindgen(js_name = SaveEventStatus)] +pub enum JsSaveEventStatus { + /// The event has been successfully saved into the database + Success, + /// Ephemeral events aren't expected to be stored + Ephemeral, + /// The event already exists + Duplicate, + /// The event was deleted + Deleted, + /// The event is expired + Expired, + /// The event was replaced + Replaced, + /// Attempt to delete a non-owned event + InvalidDelete, + /// Other reason + Other, +} + +impl From for JsSaveEventStatus { + fn from(status: SaveEventStatus) -> Self { + match status { + SaveEventStatus::Success => Self::Success, + SaveEventStatus::Rejected(RejectedReason::Ephemeral) => Self::Ephemeral, + SaveEventStatus::Rejected(RejectedReason::Duplicate) => Self::Duplicate, + SaveEventStatus::Rejected(RejectedReason::Deleted) => Self::Deleted, + SaveEventStatus::Rejected(RejectedReason::Expired) => Self::Expired, + SaveEventStatus::Rejected(RejectedReason::Replaced) => Self::Replaced, + SaveEventStatus::Rejected(RejectedReason::InvalidDelete) => Self::InvalidDelete, + SaveEventStatus::Rejected(RejectedReason::Other) => Self::Other, + } + } +} + /// Nostr Database #[wasm_bindgen(js_name = NostrDatabase)] pub struct JsNostrDatabase { @@ -63,11 +98,9 @@ impl JsNostrDatabase { /// Save `Event` into store /// - /// Return `true` if event was successfully saved into database. - /// - /// **This method assume that `Event` was already verified** - pub async fn save_event(&self, event: &JsEvent) -> Result { - self.inner.save_event(event).await.map_err(into_err) + /// **This method assumes that `Event` was already verified** + pub async fn save_event(&self, event: &JsEvent) -> Result { + Ok(self.inner.save_event(event).await.map_err(into_err)?.into()) } /// Get list of relays that have seen the [`EventId`] #[wasm_bindgen(js_name = eventSeenOnRelays)] diff --git a/crates/nostr-cli/src/main.rs b/crates/nostr-cli/src/main.rs index 5da8d8731..49e047533 100644 --- a/crates/nostr-cli/src/main.rs +++ b/crates/nostr-cli/src/main.rs @@ -326,8 +326,8 @@ async fn handle_command(command: ShellCommand, client: &Client) -> Result<()> { let now = Instant::now(); for event in iter { - if let Ok(stored) = db.save_event(&event).await { - if stored { + if let Ok(status) = db.save_event(&event).await { + if status.is_success() { counter += 1; } } diff --git a/crates/nostr-database/src/events/helper.rs b/crates/nostr-database/src/events/helper.rs index ac76ceda1..5ded8dee4 100644 --- a/crates/nostr-database/src/events/helper.rs +++ b/crates/nostr-database/src/events/helper.rs @@ -16,7 +16,7 @@ use nostr::{Alphabet, Event, EventId, Filter, Kind, PublicKey, SingleLetterTag, use tokio::sync::{OwnedRwLockReadGuard, RwLock}; use crate::collections::tree::{BTreeCappedSet, Capacity, InsertResult, OverCapacityPolicy}; -use crate::Events; +use crate::{Events, RejectedReason, SaveEventStatus}; type DatabaseEvent = Arc; @@ -132,10 +132,10 @@ impl From for QueryPattern { } /// Database Event Result -#[derive(Debug, Clone, Default, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct DatabaseEventResult { - /// Handled event should be stored into database? - pub to_store: bool, + /// Status + pub status: SaveEventStatus, /// List of events that should be removed from database pub to_discard: HashSet, } @@ -190,21 +190,33 @@ impl InternalDatabaseHelper { .into_iter() .rev() // Lookup ID: EVENT_ORD_IMPL .filter(|e| !e.is_expired() && !e.kind.is_ephemeral()) - .filter(move |event| self.internal_index_event(event, &now).to_store) + .filter(move |event| self.internal_index_event(event, &now).status.is_success()) } fn internal_index_event(&mut self, event: &Event, now: &Timestamp) -> DatabaseEventResult { // Check if was already added if self.ids.contains_key(&event.id) { - return DatabaseEventResult::default(); + return DatabaseEventResult { + status: SaveEventStatus::Rejected(RejectedReason::Duplicate), + to_discard: HashSet::new(), + }; } // Check if was deleted or is expired - if self.deleted_ids.contains(&event.id) || event.is_expired_at(now) { + if self.deleted_ids.contains(&event.id) { let mut to_discard: HashSet = HashSet::with_capacity(1); to_discard.insert(event.id); return DatabaseEventResult { - to_store: false, + status: SaveEventStatus::Rejected(RejectedReason::Deleted), + to_discard, + }; + } + + if event.is_expired_at(now) { + let mut to_discard: HashSet = HashSet::with_capacity(1); + to_discard.insert(event.id); + return DatabaseEventResult { + status: SaveEventStatus::Rejected(RejectedReason::Expired), to_discard, }; } @@ -216,13 +228,13 @@ impl InternalDatabaseHelper { let created_at: Timestamp = event.created_at; let kind: Kind = event.kind; - let mut should_insert: bool = true; + let mut status: SaveEventStatus = SaveEventStatus::Success; if kind.is_replaceable() { let params: QueryByKindAndAuthorParams = QueryByKindAndAuthorParams::new(kind, author); for ev in self.internal_query_by_kind_and_author(params) { if ev.created_at > created_at || ev.id == event.id { - should_insert = false; + status = SaveEventStatus::Rejected(RejectedReason::Replaced); } else { to_discard.insert(ev.id); } @@ -235,20 +247,20 @@ impl InternalDatabaseHelper { // Check if coordinate was deleted if self.has_coordinate_been_deleted(&coordinate, now) { - should_insert = false; + status = SaveEventStatus::Rejected(RejectedReason::Deleted); } else { let params: QueryByParamReplaceable = QueryByParamReplaceable::new(kind, author, identifier.to_string()); if let Some(ev) = self.internal_query_param_replaceable(params) { if ev.created_at > created_at || ev.id == event.id { - should_insert = false; + status = SaveEventStatus::Rejected(RejectedReason::Replaced); } else { to_discard.insert(ev.id); } } } } - None => should_insert = false, + None => status = SaveEventStatus::Rejected(RejectedReason::Other), } } else if kind == Kind::EventDeletion { // Check `e` tags @@ -256,7 +268,7 @@ impl InternalDatabaseHelper { if let Some(ev) = self.ids.get(id) { if ev.pubkey != author { to_discard.insert(event.id); - should_insert = false; + status = SaveEventStatus::Rejected(RejectedReason::InvalidDelete); break; } @@ -270,7 +282,7 @@ impl InternalDatabaseHelper { for coordinate in event.tags.coordinates() { if coordinate.public_key != author { to_discard.insert(event.id); - should_insert = false; + status = SaveEventStatus::Rejected(RejectedReason::InvalidDelete); break; } @@ -310,7 +322,7 @@ impl InternalDatabaseHelper { self.discard_events(&to_discard); // Insert event - if should_insert { + if status.is_success() { let e: DatabaseEvent = Arc::new(event.clone()); // TODO: avoid clone? let InsertResult { inserted, pop } = self.events.insert(e.clone()); @@ -349,10 +361,7 @@ impl InternalDatabaseHelper { } } - DatabaseEventResult { - to_store: should_insert, - to_discard, - } + DatabaseEventResult { status, to_discard } } fn discard_events(&mut self, ids: &HashSet) { @@ -405,9 +414,12 @@ impl InternalDatabaseHelper { /// /// **This method assume that [`Event`] was already verified** pub fn index_event(&mut self, event: &Event) -> DatabaseEventResult { - // Check if it's expired or ephemeral (in `internal_index_event` is checked only the raw event expiration) - if event.is_expired() || event.kind.is_ephemeral() { - return DatabaseEventResult::default(); + // Check if it's ephemeral + if event.kind.is_ephemeral() { + return DatabaseEventResult { + status: SaveEventStatus::Rejected(RejectedReason::Ephemeral), + to_discard: HashSet::new(), + }; } let now = Timestamp::now(); self.internal_index_event(event, &now) @@ -710,14 +722,8 @@ impl DatabaseHelper { /// Index [`Event`] /// - /// **This method assume that [`Event`] was already verified** + /// **This method assumes that [`Event`] was already verified** pub async fn index_event(&self, event: &Event) -> DatabaseEventResult { - // Check if it's expired or ephemeral - if event.is_expired() || event.kind.is_ephemeral() { - return DatabaseEventResult::default(); - } - - // Acquire write lock let mut inner = self.inner.write().await; inner.index_event(event) } @@ -987,7 +993,7 @@ mod tests { // Test add new replaceable event (metadata) let first_ev_metadata = Event::from_json(REPLACEABLE_EVENT_1).unwrap(); let res = indexes.index_event(&first_ev_metadata).await; - assert!(res.to_store); + assert!(res.status.is_success()); assert!(res.to_discard.is_empty()); assert_eq!( indexes @@ -1002,7 +1008,7 @@ mod tests { // Test add replace metadata let ev = Event::from_json(REPLACEABLE_EVENT_2).unwrap(); let res = indexes.index_event(&ev).await; - assert!(res.to_store); + assert!(res.status.is_success()); assert!(res.to_discard.contains(&first_ev_metadata.id)); assert_eq!( indexes diff --git a/crates/nostr-database/src/events/mod.rs b/crates/nostr-database/src/events/mod.rs index d58a320c1..7bf768f4f 100644 --- a/crates/nostr-database/src/events/mod.rs +++ b/crates/nostr-database/src/events/mod.rs @@ -24,6 +24,42 @@ pub enum DatabaseEventStatus { NotExistent, } +/// Reason why event wasn't stored into the database +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum RejectedReason { + /// Ephemeral events aren't expected to be stored + Ephemeral, + /// The event already exists + Duplicate, + /// The event was deleted + Deleted, + /// The event is expired + Expired, + /// The event was replaced + Replaced, + /// Attempt to delete a non-owned event + InvalidDelete, + /// Other reason + Other, +} + +/// Save event status +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SaveEventStatus { + /// The event has been successfully saved + Success, + /// The event has been rejected + Rejected(RejectedReason), +} + +impl SaveEventStatus { + /// Check if event is successfully saved + #[inline] + pub fn is_success(&self) -> bool { + matches!(self, Self::Success) + } +} + #[doc(hidden)] pub trait IntoNostrEventsDatabase { fn into_database(self) -> Arc; @@ -61,10 +97,8 @@ where pub trait NostrEventsDatabase: fmt::Debug + Send + Sync { /// Save [`Event`] into store /// - /// Return `true` if event was successfully saved into database. - /// - /// **This method assume that [`Event`] was already verified** - async fn save_event(&self, event: &Event) -> Result; + /// **This method assumes that [`Event`] was already verified** + async fn save_event(&self, event: &Event) -> Result; /// Check event status by ID /// diff --git a/crates/nostr-database/src/lib.rs b/crates/nostr-database/src/lib.rs index 7e9bf64aa..4fadbb406 100644 --- a/crates/nostr-database/src/lib.rs +++ b/crates/nostr-database/src/lib.rs @@ -28,6 +28,7 @@ pub use self::error::DatabaseError; pub use self::events::helper::{DatabaseEventResult, DatabaseHelper}; pub use self::events::{ DatabaseEventStatus, IntoNostrEventsDatabase, NostrEventsDatabase, NostrEventsDatabaseExt, + RejectedReason, SaveEventStatus, }; #[cfg(feature = "flatbuf")] pub use self::flatbuffers::{FlatBufferBuilder, FlatBufferDecode, FlatBufferEncode}; diff --git a/crates/nostr-database/src/memory.rs b/crates/nostr-database/src/memory.rs index 3362b93b2..04bfbb9e5 100644 --- a/crates/nostr-database/src/memory.rs +++ b/crates/nostr-database/src/memory.rs @@ -13,7 +13,7 @@ use tokio::sync::RwLock; use crate::{ Backend, DatabaseError, DatabaseEventResult, DatabaseEventStatus, DatabaseHelper, Events, - NostrDatabase, NostrEventsDatabase, + NostrDatabase, NostrEventsDatabase, RejectedReason, SaveEventStatus, }; /// Database options @@ -97,16 +97,16 @@ impl NostrDatabase for MemoryDatabase { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl NostrEventsDatabase for MemoryDatabase { - async fn save_event(&self, event: &Event) -> Result { + async fn save_event(&self, event: &Event) -> Result { if self.opts.events { - let DatabaseEventResult { to_store, .. } = self.helper.index_event(event).await; - Ok(to_store) + let DatabaseEventResult { status, .. } = self.helper.index_event(event).await; + Ok(status) } else { // Mark it as seen let mut seen_event_ids = self.seen_event_ids.write().await; seen_event_ids.seen(event.id, None); - Ok(false) + Ok(SaveEventStatus::Rejected(RejectedReason::Other)) } } diff --git a/crates/nostr-indexeddb/src/lib.rs b/crates/nostr-indexeddb/src/lib.rs index 5f4d5d066..5d46836a6 100644 --- a/crates/nostr-indexeddb/src/lib.rs +++ b/crates/nostr-indexeddb/src/lib.rs @@ -226,14 +226,11 @@ impl WebDatabase { Ok(()) } - async fn _save_event(&self, event: &Event) -> Result { + async fn _save_event(&self, event: &Event) -> Result { // Index event - let DatabaseEventResult { - to_store, - to_discard, - } = self.helper.index_event(event).await; + let DatabaseEventResult { status, to_discard } = self.helper.index_event(event).await; - if to_store { + if status.is_success() { let tx = self .db .transaction_on_one_with_mode(EVENTS_CF, IdbTransactionMode::Readwrite)?; @@ -260,11 +257,9 @@ impl WebDatabase { } tx.await.into_result()?; - - Ok(true) - } else { - Ok(false) } + + Ok(status) } async fn _delete(&self, filter: Filter) -> Result<(), IndexedDBError> { @@ -368,7 +363,7 @@ impl_nostr_database!({ }); impl_nostr_events_database!({ - async fn save_event(&self, event: &Event) -> Result { + async fn save_event(&self, event: &Event) -> Result { self._save_event(event) .await .map_err(DatabaseError::backend) diff --git a/crates/nostr-lmdb/src/lib.rs b/crates/nostr-lmdb/src/lib.rs index 3dca87bb2..715277748 100644 --- a/crates/nostr-lmdb/src/lib.rs +++ b/crates/nostr-lmdb/src/lib.rs @@ -62,7 +62,7 @@ impl NostrDatabase for NostrLMDB { #[async_trait] impl NostrEventsDatabase for NostrLMDB { #[inline] - async fn save_event(&self, event: &Event) -> Result { + async fn save_event(&self, event: &Event) -> Result { self.db .save_event(event) .await @@ -254,10 +254,14 @@ mod tests { (keys, event) } - async fn add_event_with_keys(&self, builder: EventBuilder, keys: &Keys) -> (Event, bool) { + async fn add_event_with_keys( + &self, + builder: EventBuilder, + keys: &Keys, + ) -> (Event, SaveEventStatus) { let event = builder.sign_with_keys(keys).unwrap(); - let stored = self.db.save_event(&event).await.unwrap(); - (event, stored) + let status = self.db.save_event(&event).await.unwrap(); + (event, status) } async fn count_all(&self) -> usize { @@ -314,13 +318,13 @@ mod tests { assert_eq!(db.count_all().await, added_events + 1); // Replace previous event - let (new_expected_event, stored) = db + let (new_expected_event, status) = db .add_event_with_keys( EventBuilder::metadata(&metadata).custom_created_at(now), &keys, ) .await; - assert!(stored); + assert!(status.is_success()); // Test event by ID (MUST be None because replaced) assert!(db.event_by_id(&expected_event.id).await.unwrap().is_none()); @@ -375,7 +379,7 @@ mod tests { assert_eq!(db.count_all().await, added_events + 1); // Replace previous event - let (new_expected_event, stored) = db + let (new_expected_event, status) = db .add_event_with_keys( EventBuilder::new(Kind::ParameterizedReplaceable(33_333), "Test replace") .tag(Tag::identifier("my-id-a")) @@ -383,7 +387,7 @@ mod tests { &keys, ) .await; - assert!(stored); + assert!(status.is_success()); // Test event by ID (MUST be None` because replaced) assert!(db.event_by_id(&expected_event.id).await.unwrap().is_none()); @@ -404,7 +408,7 @@ mod tests { assert_eq!(db.count_all().await, added_events + 1); // Trey to add param replaceable event with older timestamp (MUSTN'T be stored) - let (_, stored) = db + let (_, status) = db .add_event_with_keys( EventBuilder::new(Kind::ParameterizedReplaceable(33_333), "Test replace 2") .tag(Tag::identifier("my-id-a")) @@ -412,7 +416,7 @@ mod tests { &keys, ) .await; - assert!(!stored); + assert!(!status.is_success()); } #[tokio::test] diff --git a/crates/nostr-lmdb/src/store/mod.rs b/crates/nostr-lmdb/src/store/mod.rs index 813510e6c..f5d0bb6dc 100644 --- a/crates/nostr-lmdb/src/store/mod.rs +++ b/crates/nostr-lmdb/src/store/mod.rs @@ -69,9 +69,9 @@ impl Store { } /// Store an event. - pub async fn save_event(&self, event: &Event) -> Result { + pub async fn save_event(&self, event: &Event) -> Result { if event.kind.is_ephemeral() { - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Ephemeral)); } // TODO: avoid this clone @@ -83,14 +83,12 @@ impl Store { // Already exists if db.has_event(&read_txn, event.id.as_bytes())? { - //return Err(Error::Duplicate); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Duplicate)); } // Reject event if ID was deleted if db.is_deleted(&read_txn, &event.id)? { - //return Err(Error::Deleted); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Deleted)); } // Reject event if ADDR was deleted after it's created_at date @@ -99,8 +97,7 @@ impl Store { let coordinate: Coordinate = Coordinate::new(event.kind, event.pubkey); if let Some(time) = db.when_is_coordinate_deleted(&read_txn, &coordinate)? { if event.created_at <= time { - //return Err(Error::Deleted); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Deleted)); } } } @@ -113,8 +110,7 @@ impl Store { Coordinate::new(event.kind, event.pubkey).identifier(identifier); if let Some(time) = db.when_is_coordinate_deleted(&read_txn, &coordinate)? { if event.created_at <= time { - //return Err(Error::Deleted); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Deleted)); } } } @@ -130,9 +126,8 @@ impl Store { db.find_replaceable_event(&read_txn, &event.pubkey, event.kind)? { if stored.created_at > event.created_at { - // return Err(Error::Replaced); txn.abort(); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Replaced)); } let coordinate: Coordinate = Coordinate::new(event.kind, event.pubkey); @@ -151,9 +146,8 @@ impl Store { db.find_parameterized_replaceable_event(&read_txn, &coordinate)? { if stored.created_at > event.created_at { - // return Err(Error::Replaced); txn.abort(); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::Replaced)); } db.remove_parameterized_replaceable( @@ -172,7 +166,7 @@ impl Store { if invalid { txn.abort(); - return Ok(false); + return Ok(SaveEventStatus::Rejected(RejectedReason::InvalidDelete)); } } @@ -182,7 +176,7 @@ impl Store { read_txn.commit()?; txn.commit()?; - Ok(true) + Ok(SaveEventStatus::Success) }) .await? } diff --git a/crates/nostr-ndb/src/lib.rs b/crates/nostr-ndb/src/lib.rs index 16180339f..383bc8eab 100644 --- a/crates/nostr-ndb/src/lib.rs +++ b/crates/nostr-ndb/src/lib.rs @@ -90,13 +90,14 @@ impl NostrDatabase for NdbDatabase { #[async_trait] impl NostrEventsDatabase for NdbDatabase { - async fn save_event(&self, event: &Event) -> Result { + async fn save_event(&self, event: &Event) -> Result { let msg = RelayMessage::event(SubscriptionId::new("ndb"), event.clone()); let json: String = msg.as_json(); self.db .process_event(&json) .map_err(DatabaseError::backend)?; - Ok(true) + // TODO: shouldn't return a success since we don't know if the ingestion was successful or not. + Ok(SaveEventStatus::Success) } async fn check_id(&self, event_id: &EventId) -> Result { diff --git a/crates/nostr-relay-builder/src/local/inner.rs b/crates/nostr-relay-builder/src/local/inner.rs index bab5d15f2..55bf0904f 100644 --- a/crates/nostr-relay-builder/src/local/inner.rs +++ b/crates/nostr-relay-builder/src/local/inner.rs @@ -422,7 +422,8 @@ impl InnerLocalRelay { let msg: RelayMessage = match self.database.save_event(&event).await { Ok(status) => { - if status { + // TODO: match status + if status.is_success() { let event_id = event.id; // Broadcast to channel