diff --git a/Cargo.lock b/Cargo.lock index 5b49a28518..cbff9a432e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7233,7 +7233,7 @@ dependencies = [ [[package]] name = "nyx-chain-watcher" -version = "0.1.13" +version = "0.1.14" dependencies = [ "anyhow", "async-trait", diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index af830109c4..3f161750a1 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1185,6 +1185,7 @@ name = "nym-pemstore" version = "0.3.0" dependencies = [ "pem", + "tracing", ] [[package]] @@ -1251,6 +1252,12 @@ dependencies = [ "regex", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "pkcs8" version = "0.9.0" @@ -1840,6 +1847,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.18.0" diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 1ad18262e2..4def467deb 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -4783,9 +4783,9 @@ dependencies = [ [[package]] name = "rs_merkle" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b241d2e59b74ef9e98d94c78c47623d04c8392abaf82014dfd372a16041128f" +checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" dependencies = [ "sha2 0.10.8", ] @@ -6114,9 +6114,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", "bytes", diff --git a/nyx-chain-watcher/Cargo.toml b/nyx-chain-watcher/Cargo.toml index f17233f96b..50abfa1b39 100644 --- a/nyx-chain-watcher/Cargo.toml +++ b/nyx-chain-watcher/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nyx-chain-watcher" -version = "0.1.13" +version = "0.1.14" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/nyx-chain-watcher/src/http/api/status.rs b/nyx-chain-watcher/src/http/api/status.rs index 846cefa6fc..7ce4a246c9 100644 --- a/nyx-chain-watcher/src/http/api/status.rs +++ b/nyx-chain-watcher/src/http/api/status.rs @@ -2,21 +2,56 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::http::models::status::{ - ActivePaymentWatchersResponse, PaymentListenerFailureDetails, PaymentListenerStatusResponse, - ProcessedPayment, WatcherFailureDetails, WatcherState, + ActivePaymentWatchersResponse, ApiStatus, HealthResponse, PaymentListenerFailureDetails, + PaymentListenerStatusResponse, ProcessedPayment, WatcherFailureDetails, WatcherState, }; -use crate::http::state::{AppState, PaymentListenerState}; +use crate::http::state::{AppState, PaymentListenerState, StatusState}; use axum::extract::State; use axum::routing::get; use axum::{Json, Router}; +use nym_bin_common::build_information::BinaryBuildInformationOwned; use std::ops::Deref; pub(crate) fn routes() -> Router { Router::new() + .route("/health", get(health)) + .route("/build-information", get(build_information)) .route("/active-payment-watchers", get(active_payment_watchers)) .route("/payment-listener", get(payment_listener_status)) } +#[utoipa::path( + tag = "Status", + get, + path = "/build-information", + context_path = "/v1/status", + responses( + (status = 200, body = BinaryBuildInformationOwned) + ) +)] +async fn build_information(State(state): State) -> Json { + Json(state.build_information.to_owned()) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/health", + context_path = "/v1/status", + responses( + (status = 200, body = HealthResponse) + ) +)] +async fn health(State(state): State) -> Json { + let uptime = state.startup_time.elapsed(); + + let health = HealthResponse { + status: ApiStatus::Up, + uptime: uptime.as_secs(), + }; + Json(health) +} + #[utoipa::path( tag = "Status", get, diff --git a/nyx-chain-watcher/src/http/models.rs b/nyx-chain-watcher/src/http/models.rs index 8e7776cf68..ad1761a6bc 100644 --- a/nyx-chain-watcher/src/http/models.rs +++ b/nyx-chain-watcher/src/http/models.rs @@ -12,6 +12,18 @@ pub mod status { use time::OffsetDateTime; use utoipa::ToSchema; + #[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] + #[serde(rename_all = "lowercase")] + pub enum ApiStatus { + Up, + } + + #[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] + pub struct HealthResponse { + pub status: ApiStatus, + pub uptime: u64, + } + #[derive(Debug, Serialize, Deserialize, ToSchema)] pub struct ActivePaymentWatchersResponse { pub watchers: Vec, diff --git a/nyx-chain-watcher/src/http/state.rs b/nyx-chain-watcher/src/http/state.rs index ff230cf242..1dd8556548 100644 --- a/nyx-chain-watcher/src/http/state.rs +++ b/nyx-chain-watcher/src/http/state.rs @@ -3,18 +3,23 @@ use crate::helpers::RingBuffer; use crate::http::models::status::PaymentWatcher; use crate::models::WebhookPayload; use axum::extract::FromRef; +use nym_bin_common::bin_info; +use nym_bin_common::build_information::BinaryBuildInformation; use nym_validator_client::nyxd::Coin; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::ops::Deref; use std::sync::Arc; use time::OffsetDateTime; use tokio::sync::RwLock; +use tokio::time::Instant; #[derive(Debug, Clone)] pub(crate) struct AppState { db_pool: DbPool, pub(crate) registered_payment_watchers: Arc>, pub(crate) payment_listener_state: PaymentListenerState, + pub(crate) status_state: StatusState, } impl AppState { @@ -27,6 +32,7 @@ impl AppState { db_pool, registered_payment_watchers: Arc::new(registered_payment_watchers), payment_listener_state, + status_state: Default::default(), } } @@ -43,6 +49,35 @@ impl AppState { } } +#[derive(Clone, Debug)] +pub(crate) struct StatusState { + inner: Arc, +} + +impl Default for StatusState { + fn default() -> Self { + StatusState { + inner: Arc::new(StatusStateInner { + startup_time: Instant::now(), + build_information: bin_info!(), + }), + } + } +} + +impl Deref for StatusState { + type Target = StatusStateInner; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug)] +pub(crate) struct StatusStateInner { + pub(crate) startup_time: Instant, + pub(crate) build_information: BinaryBuildInformation, +} + #[derive(Debug, Clone)] pub(crate) struct PaymentListenerState { pub(crate) inner: Arc>, @@ -99,12 +134,6 @@ impl PaymentListenerState { } } -impl FromRef for PaymentListenerState { - fn from_ref(input: &AppState) -> Self { - input.payment_listener_state.clone() - } -} - #[derive(Debug)] pub(crate) struct PaymentListenerStateInner { pub(crate) last_checked: OffsetDateTime, @@ -181,3 +210,14 @@ impl WatcherFailureDetails { } } } + +impl FromRef for PaymentListenerState { + fn from_ref(input: &AppState) -> Self { + input.payment_listener_state.clone() + } +} +impl FromRef for StatusState { + fn from_ref(input: &AppState) -> Self { + input.status_state.clone() + } +}