hypercall_admin/monitoring/
engine.rs1use axum::{extract::State, http::StatusCode, response::IntoResponse};
4use serde::Serialize;
5use sonic_rs::json;
6
7use crate::state::AdminState;
8use hypercall_runtime_api::sonic_json::SonicJson;
9
10#[utoipa::path(
18 get,
19 path = "/monitoring/engine-state-digest",
20 responses(
21 (status = 200, description = "Engine state digest", body = hypercall_runtime_api::boundary::engine::EngineStateDigest),
22 (status = 401, description = "Invalid or missing X-Admin-Key header")
23 ),
24 tag = "Monitoring",
25 security(("admin_key" = []))
26)]
27pub async fn engine_state_digest(State(app_state): State<AdminState>) -> impl IntoResponse {
28 SonicJson(app_state.engine_state_digest_provider.engine_state_digest())
29}
30
31#[derive(Debug, Serialize, utoipa::ToSchema)]
32pub struct BalanceLedgerSnapshotEntry {
33 #[schema(value_type = String)]
34 pub wallet: hypercall_types::WalletAddress,
35 pub balance: String,
36}
37
38#[derive(Debug, Serialize, utoipa::ToSchema)]
39pub struct BalanceLedgerSyncResponse {
40 pub balance_update_seq: u64,
41 pub balance_update_stream_required: bool,
42 pub latest_acked_balance_stream_sequence: Option<u64>,
43 pub latest_acked_balance_update_seq: Option<u64>,
44 pub balance_count: usize,
45 pub balances: Vec<BalanceLedgerSnapshotEntry>,
46}
47
48#[utoipa::path(
50 get,
51 path = "/monitoring/engine/balance-ledger/snapshot",
52 responses(
53 (status = 200, description = "Engine balance ledger sync snapshot", body = BalanceLedgerSyncResponse),
54 (status = 401, description = "Invalid or missing X-Admin-Key header"),
55 (status = 503, description = "Balance update stream has not acknowledged current balance updates")
56 ),
57 tag = "Monitoring",
58 security(("admin_key" = []))
59)]
60pub async fn balance_ledger_sync_snapshot(
61 State(app_state): State<AdminState>,
62) -> impl IntoResponse {
63 let snapshot = app_state
64 .balance_snapshot_provider
65 .balance_ledger_sync_snapshot();
66 if snapshot.balance_update_stream_required
67 && snapshot.balance_update_seq > 0
68 && snapshot
69 .latest_acked_balance_update_seq
70 .map(|acked_seq| acked_seq < snapshot.balance_update_seq)
71 .unwrap_or(true)
72 {
73 return (
74 StatusCode::SERVICE_UNAVAILABLE,
75 SonicJson(json!({
76 "error": "balance update stream has not acknowledged current balance updates",
77 "balance_update_seq": snapshot.balance_update_seq,
78 "balance_update_stream_required": snapshot.balance_update_stream_required,
79 "latest_acked_balance_stream_sequence": snapshot.latest_acked_balance_stream_sequence,
80 "latest_acked_balance_update_seq": snapshot.latest_acked_balance_update_seq,
81 })),
82 )
83 .into_response();
84 }
85
86 let mut balances: Vec<_> = snapshot
87 .balances
88 .into_iter()
89 .map(|(wallet, balance)| BalanceLedgerSnapshotEntry {
90 wallet,
91 balance: balance.to_string(),
92 })
93 .collect();
94 balances.sort_by_key(|entry| entry.wallet);
95
96 (
97 StatusCode::OK,
98 SonicJson(BalanceLedgerSyncResponse {
99 balance_update_seq: snapshot.balance_update_seq,
100 balance_update_stream_required: snapshot.balance_update_stream_required,
101 latest_acked_balance_stream_sequence: snapshot.latest_acked_balance_stream_sequence,
102 latest_acked_balance_update_seq: snapshot.latest_acked_balance_update_seq,
103 balance_count: balances.len(),
104 balances,
105 }),
106 )
107 .into_response()
108}