1use std::sync::Arc;
2
3use axum::{extract::State, http::status::StatusCode, response::IntoResponse};
4use hopr_lib::api::{
5 network::Health,
6 node::{HoprNodeNetworkOperations, HoprNodeOperations, state::HoprState},
7};
8
9use crate::AppState;
10
11#[utoipa::path(
21 get,
22 path = "/startedz",
23 description="Check whether the node is started",
24 responses(
25 (status = 200, description = "The node is started and running"),
26 (status = 412, description = "The node is not started and running"),
27 ),
28 tag = "Checks"
29 )]
30pub(super) async fn startedz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
31 eval_precondition(is_running(state)) }
33
34#[utoipa::path(
50 get,
51 path = "/readyz",
52 description="Check whether the node is ready to accept connections",
53 responses(
54 (status = 200, description = "The node is ready to accept connections"),
55 (status = 412, description = "The node is not ready to accept connections"),
56 ),
57 tag = "Checks"
58 )]
59pub(super) async fn readyz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
60 eval_precondition(is_running(state.clone()) && is_minimally_connected(state).await)
61}
62
63#[utoipa::path(
81 get,
82 path = "/healthyz",
83 description="Check whether the node is healthy",
84 responses(
85 (status = 200, description = "The node is healthy"),
86 (status = 412, description = "The node is not healthy"),
87 ),
88 tag = "Checks"
89 )]
90pub(super) async fn healthyz(State(state): State<Arc<AppState>>) -> impl IntoResponse {
91 eval_precondition(is_running(state.clone()) && is_minimally_connected(state).await)
92}
93
94#[inline]
99async fn is_minimally_connected(state: Arc<AppState>) -> bool {
100 matches!(
101 state.hopr.network_health().await,
102 Health::Orange | Health::Yellow | Health::Green
103 )
104}
105
106#[inline]
111fn is_running(state: Arc<AppState>) -> bool {
112 matches!(state.hopr.status(), HoprState::Running)
113}
114
115#[inline]
120fn eval_precondition(precondition: bool) -> impl IntoResponse {
121 if precondition {
122 (StatusCode::OK, "").into_response()
123 } else {
124 (StatusCode::PRECONDITION_FAILED, "").into_response()
125 }
126}
127
128#[utoipa::path(
130 get,
131 path = "/eligiblez",
132 description="Check whether the node is eligible in the network",
133 responses(
134 (status = 200, description = "The node is allowed in the network"),
135 (status = 412, description = "The node is not allowed in the network"),
136 (status = 500, description = "Internal server error"),
137 ),
138 tag = "Checks"
139 )]
140pub(super) async fn eligiblez(State(_state): State<Arc<AppState>>) -> impl IntoResponse {
141 (StatusCode::OK, "").into_response()
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
150 fn test_eval_precondition_true_returns_ok() {
151 let response = eval_precondition(true);
152 let (parts, _) = response.into_response().into_parts();
153 assert_eq!(parts.status, StatusCode::OK);
154 }
155
156 #[test]
158 fn test_eval_precondition_false_returns_precondition_failed() {
159 let response = eval_precondition(false);
160 let (parts, _) = response.into_response().into_parts();
161 assert_eq!(parts.status, StatusCode::PRECONDITION_FAILED);
162 }
163}