hoprd_api/
checks.rs

1use std::sync::Arc;
2
3use axum::{extract::State, http::status::StatusCode, response::IntoResponse};
4use hopr_lib::HoprState;
5
6use crate::AppState;
7
8/// Check whether the node is started.
9#[utoipa::path(
10        get,
11        path = "/startedz",
12        description="Check whether the node is started",
13        responses(
14            (status = 200, description = "The node is started and running"),
15            (status = 412, description = "The node is not started and running"),
16        ),
17        tag = "Checks"
18    )]
19pub(super) async fn startedz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
20    is_running(state) // FIXME: improve this once node state granularity is improved
21}
22
23/// Check whether the node is ready to accept connections.
24#[utoipa::path(
25        get,
26        path = "/readyz",
27        description="Check whether the node is ready to accept connections",
28        responses(
29            (status = 200, description = "The node is ready to accept connections"),
30            (status = 412, description = "The node is not ready to accept connections"),
31        ),
32        tag = "Checks"
33    )]
34pub(super) async fn readyz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
35    is_running(state) // FIXME: improve this once node state granularity is improved
36}
37
38/// Check whether the node is healthy.
39#[utoipa::path(
40        get,
41        path = "/healthyz",
42        description="Check whether the node is healthy",
43        responses(
44            (status = 200, description = "The node is healthy"),
45            (status = 412, description = "The node is not healthy"),
46        ),
47        tag = "Checks"
48    )]
49pub(super) async fn healthyz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
50    is_running(state) // FIXME: improve this once node state granularity is improved
51}
52
53fn is_running(state: Arc<AppState>) -> impl IntoResponse {
54    match state.hopr.status() {
55        HoprState::Running => (StatusCode::OK, "").into_response(),
56        _ => (StatusCode::PRECONDITION_FAILED, "").into_response(),
57    }
58}
59/// Check whether the node is eligible in the network.
60#[utoipa::path(
61        get,
62        path = "/eligiblez",
63        description="Check whether the node is eligible in the network",
64        responses(
65            (status = 200, description = "The node is allowed in the network"),
66            (status = 412, description = "The node is not allowed in the network"),
67            (status = 500, description = "Internal server error"),
68        ),
69        tag = "Checks"
70    )]
71pub(super) async fn eligiblez(State(state): State<Arc<AppState>>) -> impl IntoResponse {
72    let hopr = state.hopr.clone();
73
74    match hopr.get_eligibility_status().await {
75        Ok(true) => (StatusCode::OK, "").into_response(),
76        Ok(false) => (StatusCode::PRECONDITION_FAILED, "Node not eligible").into_response(),
77        Err(hopr_lib::errors::HoprLibError::ChainApi(e)) => {
78            // The "division by zero" error is caused by the self-registration,
79            // which is forbidden to the public and thus returns false
80            // therefore the eligibility check should be ignored
81            let err_str = e.to_string();
82            if err_str.to_lowercase().contains("division or modulo by zero") {
83                (StatusCode::PRECONDITION_FAILED, "Node not eligible").into_response()
84            } else {
85                (StatusCode::INTERNAL_SERVER_ERROR, err_str).into_response()
86            }
87        }
88        Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
89    }
90}