ns_indexer/api/
mod.rs

1use axum::extract::State;
2use serde::{Deserialize, Serialize};
3use std::sync::Arc;
4use validator::{Validate, ValidationError};
5
6use ns_axum_web::erring::{HTTPError, SuccessResponse};
7use ns_axum_web::object::PackObject;
8use ns_protocol::ns;
9
10use crate::db::scylladb::ScyllaDB;
11use crate::indexer::{Indexer, IndexerState};
12
13mod inscription;
14mod name;
15mod service;
16mod utxo;
17
18pub use inscription::InscriptionAPI;
19pub use name::NameAPI;
20pub use service::ServiceAPI;
21pub use utxo::UtxoAPI;
22
23#[derive(Serialize, Deserialize)]
24pub struct AppVersion {
25    pub name: String,
26    pub version: String,
27}
28
29#[derive(Serialize, Deserialize)]
30pub struct AppHealth {
31    pub block_height: u64,
32    pub inscription_height: u64,
33}
34
35pub struct IndexerAPI {
36    pub(crate) scylla: Arc<ScyllaDB>,
37    pub(crate) state: Arc<IndexerState>,
38}
39
40impl IndexerAPI {
41    pub fn new(indexer: Arc<Indexer>) -> Self {
42        Self {
43            scylla: indexer.scylla.clone(),
44            state: indexer.state.clone(),
45        }
46    }
47}
48
49pub async fn version(
50    to: PackObject<()>,
51    State(_): State<Arc<IndexerAPI>>,
52) -> PackObject<AppVersion> {
53    to.with(AppVersion {
54        name: crate::APP_NAME.to_string(),
55        version: crate::APP_VERSION.to_string(),
56    })
57}
58
59pub async fn healthz(
60    to: PackObject<()>,
61    State(app): State<Arc<IndexerAPI>>,
62) -> Result<PackObject<SuccessResponse<AppHealth>>, HTTPError> {
63    let last_accepted_state = app.state.last_accepted.read().await;
64    let (block_height, height) = match *last_accepted_state {
65        Some(ref last_accepted) => (last_accepted.block_height, last_accepted.height),
66        None => (0, 0),
67    };
68    Ok(to.with(SuccessResponse::new(AppHealth {
69        block_height,
70        inscription_height: height,
71    })))
72}
73
74#[derive(Debug, Deserialize, Validate)]
75pub struct QueryName {
76    #[validate(custom = "validate_name")]
77    pub name: String,
78    #[validate(range(min = 0))]
79    pub sequence: Option<i64>,
80    #[validate(range(min = 0))]
81    pub code: Option<i64>,
82}
83
84#[derive(Debug, Deserialize, Validate)]
85pub struct QueryHeight {
86    #[validate(range(min = 0))]
87    pub height: i64,
88}
89
90#[derive(Debug, Deserialize, Validate)]
91pub struct QueryNamePagination {
92    #[validate(custom = "validate_name")]
93    pub name: String,
94    pub page_token: Option<i64>,
95    #[validate(range(min = 2, max = 1000))]
96    pub page_size: Option<u16>,
97}
98
99#[derive(Debug, Deserialize, Validate)]
100pub struct QueryPubkey {
101    pub pubkey: String,
102}
103
104#[derive(Debug, Deserialize, Validate)]
105pub struct QueryAddress {
106    pub address: String,
107}
108
109fn validate_name(name: &str) -> Result<(), ValidationError> {
110    if !ns::valid_name(name) {
111        return Err(ValidationError::new("invalid name"));
112    }
113
114    Ok(())
115}