1use std::borrow::Cow;
6
7use axum::{Json, extract::State};
8use iota_sdk2::types::CheckpointDigest;
9use tap::Pipe;
10
11use crate::{
12 RestService, Result,
13 openapi::{ApiEndpoint, OperationBuilder, ResponseBuilder, RouteHandler},
14};
15
16pub struct GetNodeInfo;
18
19impl ApiEndpoint<RestService> for GetNodeInfo {
20 fn method(&self) -> axum::http::Method {
21 axum::http::Method::GET
22 }
23
24 fn path(&self) -> &'static str {
25 "/"
26 }
27
28 fn stable(&self) -> bool {
29 true
30 }
31
32 fn operation(
33 &self,
34 generator: &mut schemars::gen::SchemaGenerator,
35 ) -> openapiv3::v3_1::Operation {
36 OperationBuilder::new()
37 .tag("General")
38 .operation_id("Get NodeInfo")
39 .response(
40 200,
41 ResponseBuilder::new()
42 .json_content::<NodeInfo>(generator)
43 .build(),
44 )
45 .response(500, ResponseBuilder::new().build())
46 .build()
47 }
48
49 fn handler(&self) -> crate::openapi::RouteHandler<RestService> {
50 RouteHandler::new(self.method(), get_node_info)
51 }
52}
53
54async fn get_node_info(State(state): State<RestService>) -> Result<Json<NodeInfo>> {
55 let latest_checkpoint = state.reader.inner().get_latest_checkpoint()?;
56 let lowest_available_checkpoint = state
57 .reader
58 .inner()
59 .get_lowest_available_checkpoint()?
60 .pipe(Some);
61 let lowest_available_checkpoint_objects = state
62 .reader
63 .inner()
64 .get_lowest_available_checkpoint_objects()?
65 .pipe(Some);
66
67 NodeInfo {
68 checkpoint_height: latest_checkpoint.sequence_number,
69 lowest_available_checkpoint,
70 lowest_available_checkpoint_objects,
71 timestamp_ms: latest_checkpoint.timestamp_ms,
72 epoch: latest_checkpoint.epoch(),
73 chain_id: CheckpointDigest::new(state.chain_id().as_bytes().to_owned()),
74 chain: state.chain_id().chain().as_str().into(),
75 software_version: state.software_version().into(),
76 }
77 .pipe(Json)
78 .pipe(Ok)
79}
80
81#[serde_with::serde_as]
83#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
84pub struct NodeInfo {
85 pub chain_id: CheckpointDigest,
87
88 pub chain: Cow<'static, str>,
90
91 #[serde_as(as = "iota_types::iota_serde::BigInt<u64>")]
93 #[schemars(with = "crate::_schemars::U64")]
94 pub epoch: u64,
95
96 #[serde_as(as = "iota_types::iota_serde::BigInt<u64>")]
98 #[schemars(with = "crate::_schemars::U64")]
99 pub checkpoint_height: u64,
100
101 #[serde_as(as = "iota_types::iota_serde::BigInt<u64>")]
103 #[schemars(with = "crate::_schemars::U64")]
104 pub timestamp_ms: u64,
105
106 #[serde_as(as = "Option<iota_types::iota_serde::BigInt<u64>>")]
109 #[schemars(with = "Option<crate::_schemars::U64>")]
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub lowest_available_checkpoint: Option<u64>,
112
113 #[serde_as(as = "Option<iota_types::iota_serde::BigInt<u64>>")]
115 #[schemars(with = "Option<crate::_schemars::U64>")]
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub lowest_available_checkpoint_objects: Option<u64>,
118 pub software_version: Cow<'static, str>,
119 }