tangle_indexer


git clone https://radroots.dev/git/tangle_indexer.git
Log | Files | Refs | Submodules | LICENSE

commit 753b7016cb68e3903bf950ebce489fb731224d56
parent 82c5991a05dd6a37dc2342d1e081ec9fda9b2157
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sat,  2 Aug 2025 19:42:07 +0000

Add `nostr-rs-relay` relay events records parser.

Diffstat:
Mcrates/indexer/src/domain/event/kind.rs | 24++++++++++++------------
Mcrates/indexer/src/domain/event/mod.rs | 2+-
Mcrates/indexer/src/domain/indexer.rs | 4++--
Mcrates/indexer/src/lib.rs | 34+++++++++++++++++++++++++++++-----
Acrates/indexer/src/relay/event.rs | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Dcrates/indexer/src/relay/model.rs | 36------------------------------------
Acrates/indexer/src/relay/record.rs | 37+++++++++++++++++++++++++++++++++++++
7 files changed, 133 insertions(+), 56 deletions(-)

diff --git a/crates/indexer/src/domain/event/kind.rs b/crates/indexer/src/domain/event/kind.rs @@ -5,27 +5,27 @@ use std::fmt; use crate::domain::event::{IndexerKey, METADATA_INDEX_DIRECTORY}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum IndexerEvent { +pub enum IndexerEventKind { Metadata, } -impl IndexerEvent { - pub const ALL: [IndexerEvent; 1] = [IndexerEvent::Metadata]; +impl IndexerEventKind { + pub const ALL: [IndexerEventKind; 1] = [IndexerEventKind::Metadata]; pub const fn as_u64(self) -> u64 { match self { - IndexerEvent::Metadata => 0, + IndexerEventKind::Metadata => 0, } } pub const fn paths(self) -> &'static [IndexerKey] { match self { - IndexerEvent::Metadata => &METADATA_INDEX_DIRECTORY, + IndexerEventKind::Metadata => &METADATA_INDEX_DIRECTORY, } } } -impl fmt::Display for IndexerEvent { +impl fmt::Display for IndexerEventKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_u64()) } @@ -33,20 +33,20 @@ impl fmt::Display for IndexerEvent { #[derive(thiserror::Error, Debug)] #[error("unknown event kind: {0}")] -pub struct IndexerEventParseError(pub u64); +pub struct IndexerEventKindParseError(pub u64); -impl TryFrom<u64> for IndexerEvent { - type Error = IndexerEventParseError; +impl TryFrom<u64> for IndexerEventKind { + type Error = IndexerEventKindParseError; fn try_from(val: u64) -> Result<Self, Self::Error> { match val { - 0 => Ok(IndexerEvent::Metadata), - other => Err(IndexerEventParseError(other)), + 0 => Ok(IndexerEventKind::Metadata), + other => Err(IndexerEventKindParseError(other)), } } } -impl Serialize for IndexerEvent { +impl Serialize for IndexerEventKind { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, diff --git a/crates/indexer/src/domain/event/mod.rs b/crates/indexer/src/domain/event/mod.rs @@ -2,4 +2,4 @@ mod key; mod kind; pub use key::{IndexerKey, METADATA_INDEX_DIRECTORY}; -pub use kind::{IndexerEvent, IndexerEventParseError}; +pub use kind::{IndexerEventKind, IndexerEventKindParseError}; diff --git a/crates/indexer/src/domain/indexer.rs b/crates/indexer/src/domain/indexer.rs @@ -1,10 +1,10 @@ use anyhow::{Context, Result}; use indexer_utils::file::fs_mkdir; -use crate::{config::Settings, IndexerEvent}; +use crate::{config::Settings, IndexerEventKind}; pub fn create_index_dirs(settings: &Settings) -> Result<()> { - for kind in IndexerEvent::ALL { + for kind in IndexerEventKind::ALL { let kind_str = kind.as_u64().to_string(); for subdir in kind.paths() { diff --git a/crates/indexer/src/lib.rs b/crates/indexer/src/lib.rs @@ -1,6 +1,9 @@ use anyhow::{Context, Result}; use indexer_utils::sqlite::{sqlite_conn, sqlite_stmt}; -use std::time::{Duration, Instant}; +use std::{ + collections::HashMap, + time::{Duration, Instant}, +}; use tracing::info; pub mod cli; @@ -13,15 +16,18 @@ pub mod domain { } pub mod relay { - pub mod model; + pub mod event; + pub mod record; } pub use config::Settings; -pub use domain::event::{IndexerEvent, IndexerKey}; -pub use relay::model::RelayEventRecord; +pub use domain::event::{IndexerEventKind, IndexerKey}; +pub use relay::record::RelayEventRecord; + +use crate::relay::event::RelayIndexerEvent; pub async fn run(settings: Settings) -> Result<()> { - let select_event_kinds = IndexerEvent::ALL + let select_event_kinds = IndexerEventKind::ALL .iter() .map(|k| k.as_u64().to_string()) .collect::<Vec<_>>() @@ -52,6 +58,24 @@ pub async fn run(settings: Settings) -> Result<()> { info!(record_count = records.len(), "Loaded RelayEventRecords"); + let records_by_kind: HashMap<IndexerEventKind, Vec<RelayIndexerEvent>> = records + .into_iter() + .map(RelayIndexerEvent::try_from) + .collect::<Result<Vec<_>>>()? + .into_iter() + .fold( + HashMap::<IndexerEventKind, Vec<RelayIndexerEvent>>::new(), + |mut acc, ev| { + acc.entry(ev.kind).or_default().push(ev); + acc + }, + ); + + info!( + records_count_by_kind = records_by_kind.len(), + "Loaded RelayIndexerEvents" + ); + // sleep let elapsed = iteration_start.elapsed(); let interval = Duration::from_secs(settings.service.flush_interval); diff --git a/crates/indexer/src/relay/event.rs b/crates/indexer/src/relay/event.rs @@ -0,0 +1,52 @@ +use anyhow::{Context, Result}; +use serde::{Deserialize, Serialize}; + +use crate::{domain::event::IndexerEventKindParseError, IndexerEventKind, RelayEventRecord}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RelayRawEvent { + pub id: String, + pub pubkey: String, + pub created_at: u32, + pub kind: u32, + pub tags: Vec<Vec<String>>, + pub content: String, + pub sig: String, +} + +#[derive(Debug, Clone, Serialize)] +pub struct RelayIndexerEvent { + pub id: String, + pub author: String, + pub created_at: u32, + pub pubkey: String, + pub kind: IndexerEventKind, + pub tags: Vec<Vec<String>>, + pub content: String, + pub hash: String, + pub sig: String, +} + +impl TryFrom<RelayEventRecord> for RelayIndexerEvent { + type Error = anyhow::Error; + + fn try_from(rec: RelayEventRecord) -> Result<Self> { + let raw: RelayRawEvent = serde_json::from_str(&rec.content) + .with_context(|| format!("Failed to parse relay JSON for event {}", rec.event_hash))?; + + let kind = IndexerEventKind::try_from(raw.kind as u64) + .map_err(|e: IndexerEventKindParseError| anyhow::anyhow!(e))?; + + Ok(RelayIndexerEvent { + id: raw.id.to_lowercase(), + author: rec.author.to_lowercase(), + created_at: raw.created_at, + pubkey: raw.pubkey.to_lowercase(), + kind, + tags: raw.tags, + content: raw.content, + hash: rec.event_hash, + sig: raw.sig.to_lowercase(), + }) + } +} diff --git a/crates/indexer/src/relay/model.rs b/crates/indexer/src/relay/model.rs @@ -1,36 +0,0 @@ -use indexer_utils::sqlite::{RustqliteError, SqliteResult, SqliteRow, SqliteType}; -use serde::Serialize; - -use crate::domain::event::{IndexerEvent, IndexerEventParseError}; - -#[derive(Clone, Debug, Serialize)] -pub struct RelayEventRecord { - pub event_hash: String, - pub author: String, - pub created_at: u32, - pub kind: IndexerEvent, - pub content: String, -} - -impl RelayEventRecord { - pub fn from_row(row: &SqliteRow) -> SqliteResult<Self> { - let event_hash: String = row.get(0)?; - let author: String = row.get(1)?; - let created_at: u32 = row.get(2)?; - let kind_num: u32 = row.get(3)?; - - let kind = - IndexerEvent::try_from(kind_num as u64).map_err(|e: IndexerEventParseError| { - RustqliteError::FromSqlConversionFailure(3, SqliteType::Integer, Box::new(e)) - })?; - - let content: String = row.get(4)?; - Ok(RelayEventRecord { - event_hash, - author, - created_at, - kind, - content, - }) - } -} diff --git a/crates/indexer/src/relay/record.rs b/crates/indexer/src/relay/record.rs @@ -0,0 +1,37 @@ +use indexer_utils::sqlite::{RustqliteError, SqliteResult, SqliteRow, SqliteType}; +use serde::Serialize; + +use crate::domain::event::{IndexerEventKind, IndexerEventKindParseError}; + +#[derive(Clone, Debug, Serialize)] +pub struct RelayEventRecord { + pub event_hash: String, + pub author: String, + pub created_at: u32, + pub kind: IndexerEventKind, + pub content: String, +} + +impl RelayEventRecord { + pub fn from_row(row: &SqliteRow) -> SqliteResult<Self> { + let event_hash: String = row.get(0)?; + let author: String = row.get(1)?; + let created_at: u32 = row.get(2)?; + let kind_num: u32 = row.get(3)?; + + let kind = IndexerEventKind::try_from(kind_num as u64).map_err( + |e: IndexerEventKindParseError| { + RustqliteError::FromSqlConversionFailure(3, SqliteType::Integer, Box::new(e)) + }, + )?; + + let content: String = row.get(4)?; + Ok(RelayEventRecord { + event_hash, + author, + created_at, + kind, + content, + }) + } +}