Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions nym-node-status-api/nym-node-status-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[package]
name = "nym-node-status-api"
version = "3.0.0"
version = "3.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
Expand All @@ -28,7 +28,7 @@ moka = { workspace = true, features = ["future"] }
# Nym API: revert after Cheddar is out
nym-contracts-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
nym-mixnet-contract-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
nym-bin-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
nym-bin-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar", features = ["openapi"]}
nym-node-status-client = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
nym-crypto = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
nym-http-api-client = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" }
Expand Down
4 changes: 3 additions & 1 deletion nym-node-status-api/nym-node-status-api/src/http/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub(crate) mod metrics;
pub(crate) mod mixnodes;
pub(crate) mod nym_nodes;
pub(crate) mod services;
pub(crate) mod status;
pub(crate) mod summary;
pub(crate) mod testruns;

Expand All @@ -39,7 +40,8 @@ impl RouterBuilder {
.nest("/mixnodes", mixnodes::routes())
.nest("/services", services::routes())
.nest("/summary", summary::routes())
.nest("/metrics", metrics::routes()),
.nest("/metrics", metrics::routes())
.nest("/status", status::routes()),
)
.nest(
"/explorer/v3",
Expand Down
46 changes: 46 additions & 0 deletions nym-node-status-api/nym-node-status-api/src/http/api/status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use axum::{extract::State, Json, Router};
use nym_validator_client::models::BinaryBuildInformationOwned;
use tracing::instrument;

use crate::http::{
error::HttpResult,
state::{AppState, HealthInfo},
};

pub(crate) fn routes() -> Router<AppState> {
Router::new()
.route("/build_information", axum::routing::get(build_information))
.route("/health", axum::routing::get(health))
}

#[utoipa::path(
tag = "Status",
get,
path = "/build_information",
context_path = "/v2/status",
responses(
(status = 200, body = BinaryBuildInformationOwned)
)
)]
#[instrument(level = tracing::Level::INFO, skip_all)]
async fn build_information(
State(state): State<AppState>,
) -> HttpResult<Json<BinaryBuildInformationOwned>> {
let build_info = state.build_information().to_owned();

Ok(Json(build_info))
}

#[utoipa::path(
tag = "Status",
get,
path = "/health",
context_path = "/v2/status",
responses(
(status = 200, body = HealthInfo)
)
)]
#[instrument(level = tracing::Level::INFO, skip_all)]
async fn health(State(state): State<AppState>) -> HttpResult<Json<HealthInfo>> {
Ok(Json(state.health()))
}
38 changes: 37 additions & 1 deletion nym-node-status-api/nym-node-status-api/src/http/state.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use cosmwasm_std::Decimal;
use itertools::Itertools;
use moka::{future::Cache, Entry};
use nym_bin_common::bin_info_owned;
use nym_contracts_common::NaiveFloat;
use nym_crypto::asymmetric::ed25519::PublicKey;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nym_api::SkimmedNode;
use semver::Version;
use serde::Serialize;
use std::{collections::HashMap, sync::Arc, time::Duration};
use time::UtcDateTime;
use tokio::sync::RwLock;
use tracing::{error, instrument, warn};
use utoipa::ToSchema;

use super::models::SessionStats;
use crate::{
db::{queries, DbPool},
http::models::{
Expand All @@ -18,7 +23,7 @@ use crate::{
monitor::{DelegationsCache, NodeGeoCache},
};

use super::models::SessionStats;
pub(crate) use nym_validator_client::models::BinaryBuildInformationOwned;

#[derive(Debug, Clone)]
pub(crate) struct AppState {
Expand All @@ -28,6 +33,7 @@ pub(crate) struct AppState {
agent_max_count: i64,
node_geocache: NodeGeoCache,
node_delegations: Arc<RwLock<DelegationsCache>>,
bin_info: BinaryInfo,
}

impl AppState {
Expand All @@ -46,6 +52,7 @@ impl AppState {
agent_max_count,
node_geocache,
node_delegations,
bin_info: BinaryInfo::new(),
}
}

Expand Down Expand Up @@ -78,6 +85,15 @@ impl AppState {
.await
.delegations_owned(node_id)
}

pub(crate) fn health(&self) -> HealthInfo {
let uptime = (UtcDateTime::now() - self.bin_info.startup_time).whole_seconds();
HealthInfo { uptime }
}

pub(crate) fn build_information(&self) -> &BinaryBuildInformationOwned {
&self.bin_info.build_info
}
}

static GATEWAYS_LIST_KEY: &str = "gateways";
Expand Down Expand Up @@ -631,3 +647,23 @@ async fn aggregate_node_info_from_db(

Ok(parsed_nym_nodes)
}

#[derive(Debug, Clone)]
pub(crate) struct BinaryInfo {
startup_time: UtcDateTime,
build_info: BinaryBuildInformationOwned,
}

impl BinaryInfo {
fn new() -> Self {
Self {
startup_time: UtcDateTime::now(),
build_info: bin_info_owned!(),
}
}
}

#[derive(Serialize, ToSchema)]
pub(crate) struct HealthInfo {
uptime: i64,
}
Loading