ns-indexer 0.6.0

Name & Service Protocol indexer service in Rust
Documentation
use axum::extract::State;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use validator::{Validate, ValidationError};

use ns_axum_web::erring::{HTTPError, SuccessResponse};
use ns_axum_web::object::PackObject;
use ns_protocol::ns;

use crate::db::scylladb::ScyllaDB;
use crate::indexer::{Indexer, IndexerState};

mod inscription;
mod name;
mod service;
mod utxo;

pub use inscription::InscriptionAPI;
pub use name::NameAPI;
pub use service::ServiceAPI;
pub use utxo::UtxoAPI;

#[derive(Serialize, Deserialize)]
pub struct AppVersion {
    pub name: String,
    pub version: String,
}

#[derive(Serialize, Deserialize)]
pub struct AppHealth {
    pub block_height: u64,
    pub inscription_height: u64,
}

pub struct IndexerAPI {
    pub(crate) scylla: Arc<ScyllaDB>,
    pub(crate) state: Arc<IndexerState>,
}

impl IndexerAPI {
    pub fn new(indexer: Arc<Indexer>) -> Self {
        Self {
            scylla: indexer.scylla.clone(),
            state: indexer.state.clone(),
        }
    }
}

pub async fn version(
    to: PackObject<()>,
    State(_): State<Arc<IndexerAPI>>,
) -> PackObject<AppVersion> {
    to.with(AppVersion {
        name: crate::APP_NAME.to_string(),
        version: crate::APP_VERSION.to_string(),
    })
}

pub async fn healthz(
    to: PackObject<()>,
    State(app): State<Arc<IndexerAPI>>,
) -> Result<PackObject<SuccessResponse<AppHealth>>, HTTPError> {
    let last_accepted_state = app.state.last_accepted.read().await;
    let (block_height, height) = match *last_accepted_state {
        Some(ref last_accepted) => (last_accepted.block_height, last_accepted.height),
        None => (0, 0),
    };
    Ok(to.with(SuccessResponse::new(AppHealth {
        block_height,
        inscription_height: height,
    })))
}

#[derive(Debug, Deserialize, Validate)]
pub struct QueryName {
    #[validate(custom = "validate_name")]
    pub name: String,
    #[validate(range(min = 0))]
    pub sequence: Option<i64>,
    #[validate(range(min = 0))]
    pub code: Option<i64>,
}

#[derive(Debug, Deserialize, Validate)]
pub struct QueryHeight {
    #[validate(range(min = 0))]
    pub height: i64,
}

#[derive(Debug, Deserialize, Validate)]
pub struct QueryNamePagination {
    #[validate(custom = "validate_name")]
    pub name: String,
    pub page_token: Option<i64>,
    #[validate(range(min = 2, max = 1000))]
    pub page_size: Option<u16>,
}

#[derive(Debug, Deserialize, Validate)]
pub struct QueryPubkey {
    pub pubkey: String,
}

#[derive(Debug, Deserialize, Validate)]
pub struct QueryAddress {
    pub address: String,
}

fn validate_name(name: &str) -> Result<(), ValidationError> {
    if !ns::valid_name(name) {
        return Err(ValidationError::new("invalid name"));
    }

    Ok(())
}