Skip to content

Commit

Permalink
db: allow to disable events store in MemoryDatabase
Browse files Browse the repository at this point in the history
  • Loading branch information
yukibtc committed Oct 23, 2023
1 parent 4003bd5 commit 78c2aea
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 55 deletions.
2 changes: 1 addition & 1 deletion crates/nostr-sdk-db/examples/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use nostr_sdk_db::NostrDatabase;
#[tokio::main]
async fn main() {
let keys = Keys::generate();
let database = MemoryDatabase::new();
let database = MemoryDatabase::new(true);

for i in 0..50_000 {
let event = EventBuilder::new_text_note(format!("Event #{i}"), &[])
Expand Down
3 changes: 3 additions & 0 deletions crates/nostr-sdk-db/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub enum DatabaseError {
/// Not supported
#[error("method not supported by current backend")]
NotSupported,
/// Feature disabled
#[error("feature disabled for current backend")]
FeatureDisabled,
/// Not found
#[error("not found")]
NotFound,
Expand Down
134 changes: 82 additions & 52 deletions crates/nostr-sdk-db/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,31 @@ impl From<Error> for DatabaseError {
}

/// Memory Database (RAM)
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct MemoryDatabase {
store_events: bool,
seen_event_ids: Arc<RwLock<HashMap<EventId, HashSet<Url>>>>,
events: Arc<RwLock<HashMap<EventId, Event>>>,
// TODO: add messages queue? (messages not sent)
}

impl Default for MemoryDatabase {
fn default() -> Self {
Self::new(false)
}
}

impl MemoryDatabase {
/// New Memory database
pub fn new() -> Self {
Self::default()
///
/// If `store_events` arg is set to `true`, the seen events will be stored in memory (a lot of it could be used).
/// If it's set to `false`, only the [`EventId`] will be stored (instead of the full [`Event`])
pub fn new(store_events: bool) -> Self {
Self {
store_events,
seen_event_ids: Arc::new(RwLock::new(HashMap::new())),
events: Arc::new(RwLock::new(HashMap::new())),
}
}

fn _event_id_seen(
Expand Down Expand Up @@ -81,50 +95,54 @@ impl MemoryDatabase {
) -> Result<bool, DatabaseError> {
self.event_id_seen(event.id, None).await?;

if event.is_expired() || event.is_ephemeral() {
tracing::warn!("Event {} not saved: expired or ephemeral", event.id);
return Ok(false);
}
if self.store_events {
if event.is_expired() || event.is_ephemeral() {
tracing::warn!("Event {} not saved: expired or ephemeral", event.id);
return Ok(false);
}

let mut should_insert: bool = true;

if event.is_replaceable() {
let filter: Filter = Filter::new()
.author(event.pubkey.to_string())
.kind(event.kind);
let res: Vec<Event> = self._query(events, vec![filter]).await?;
if let Some(ev) = res.into_iter().next() {
if ev.created_at >= event.created_at {
should_insert = false;
} else if ev.created_at < event.created_at {
events.remove(&ev.id);
let mut should_insert: bool = true;

if event.is_replaceable() {
let filter: Filter = Filter::new()
.author(event.pubkey.to_string())
.kind(event.kind);
let res: Vec<Event> = self._query(events, vec![filter]).await?;
if let Some(ev) = res.into_iter().next() {
if ev.created_at >= event.created_at {
should_insert = false;
} else if ev.created_at < event.created_at {
events.remove(&ev.id);
}
}
}
} else if event.is_parameterized_replaceable() {
match event.identifier() {
Some(identifier) => {
let filter: Filter = Filter::new()
.author(event.pubkey.to_string())
.kind(event.kind)
.identifier(identifier);
let res: Vec<Event> = self._query(events, vec![filter]).await?;
if let Some(ev) = res.into_iter().next() {
if ev.created_at >= event.created_at {
should_insert = false;
} else if ev.created_at < event.created_at {
events.remove(&ev.id);
} else if event.is_parameterized_replaceable() {
match event.identifier() {
Some(identifier) => {
let filter: Filter = Filter::new()
.author(event.pubkey.to_string())
.kind(event.kind)
.identifier(identifier);
let res: Vec<Event> = self._query(events, vec![filter]).await?;
if let Some(ev) = res.into_iter().next() {
if ev.created_at >= event.created_at {
should_insert = false;
} else if ev.created_at < event.created_at {
events.remove(&ev.id);
}
}
}
None => should_insert = false,
}
None => should_insert = false,
}
}

if should_insert {
events.insert(event.id, event);
Ok(true)
if should_insert {
events.insert(event.id, event);
Ok(true)
} else {
tracing::warn!("Event {} not saved: unknown", event.id);
Ok(false)
}
} else {
tracing::warn!("Event {} not saved: unknown", event.id);
Ok(false)
}
}
Expand Down Expand Up @@ -180,27 +198,39 @@ impl NostrDatabase for MemoryDatabase {
}

async fn event_by_id(&self, event_id: EventId) -> Result<Event, Self::Err> {
let events = self.events.read().await;
events
.get(&event_id)
.cloned()
.ok_or(DatabaseError::NotFound)
if self.store_events {
let events = self.events.read().await;
events
.get(&event_id)
.cloned()
.ok_or(DatabaseError::NotFound)
} else {
Err(DatabaseError::FeatureDisabled)
}
}

async fn query(&self, filters: Vec<Filter>) -> Result<Vec<Event>, Self::Err> {
let events = self.events.read().await;
self._query(&events, filters).await
if self.store_events {
let events = self.events.read().await;
self._query(&events, filters).await
} else {
Err(DatabaseError::FeatureDisabled)
}
}

async fn event_ids_by_filters(&self, filters: Vec<Filter>) -> Result<Vec<EventId>, Self::Err> {
let events = self.events.read().await;
let mut list: Vec<EventId> = Vec::new();
for event in events.values() {
if filters.match_event(event) {
list.push(event.id);
if self.store_events {
let events = self.events.read().await;
let mut list: Vec<EventId> = Vec::new();
for event in events.values() {
if filters.match_event(event) {
list.push(event.id);
}
}
Ok(list)
} else {
Err(DatabaseError::FeatureDisabled)
}
Ok(list)
}

async fn wipe(&self) -> Result<(), Self::Err> {
Expand Down
2 changes: 1 addition & 1 deletion crates/nostr-sdk/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl ClientBuilder {
pub fn new(keys: &Keys) -> Self {
Self {
keys: keys.clone(),
database: Arc::new(MemoryDatabase::new()),
database: Arc::new(MemoryDatabase::default()),
opts: Options::default(),
#[cfg(feature = "nip46")]
remote_signer: None,
Expand Down
2 changes: 1 addition & 1 deletion crates/nostr-sdk/src/relay/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl Drop for RelayPool {
impl RelayPool {
/// Create new `RelayPool`
pub fn new(opts: RelayPoolOptions) -> Self {
Self::with_database(opts, Arc::new(MemoryDatabase::new()))
Self::with_database(opts, Arc::new(MemoryDatabase::default()))
}

/// New with database
Expand Down

0 comments on commit 78c2aea

Please sign in to comment.