offline_intelligence/api/
admin_api.rs1use axum::{
7 extract::State,
8 http::StatusCode,
9 response::IntoResponse,
10 Json,
11};
12use std::sync::{Arc, atomic::Ordering};
13use serde::{Deserialize, Serialize};
14
15use crate::shared_state::SharedState;
16
17#[derive(Debug, Serialize)]
19pub struct HealthResponse {
20 pub status: String,
21 pub version: String,
22 pub uptime_seconds: u64,
23}
24
25#[derive(Debug, Serialize)]
27pub struct DbStatsResponse {
28 pub total_sessions: usize,
29 pub total_messages: usize,
30 pub total_summaries: usize,
31 pub database_size_bytes: u64,
32}
33
34#[derive(Debug, Deserialize)]
36pub struct MaintenanceRequest {
37 pub operation: String,
38 pub parameters: Option<serde_json::Value>,
39}
40
41
42static START_TIME: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
44
45fn init_start_time() {
46 let now: u64 = std::time::SystemTime::now()
47 .duration_since(std::time::UNIX_EPOCH)
48 .unwrap_or_else(|_| std::time::Duration::from_secs(0))
49 .as_secs();
50 START_TIME.store(now, Ordering::SeqCst);
51}
52
53fn get_uptime_seconds() -> u64 {
54 let start = START_TIME.load(Ordering::SeqCst);
55 if start == 0 {
56 init_start_time();
58 return 0;
59 }
60
61 let now = std::time::SystemTime::now()
62 .duration_since(std::time::UNIX_EPOCH)
63 .unwrap_or_else(|_| std::time::Duration::from_secs(0))
64 .as_secs();
65
66 now.saturating_sub(start)
67}
68
69pub async fn health(
71 State(_shared_state): State<Arc<SharedState>>,
72) -> Result<impl IntoResponse, StatusCode> {
73 if START_TIME.load(Ordering::SeqCst) == 0 {
75 init_start_time();
76 }
77
78 Ok((
79 StatusCode::OK,
80 Json(HealthResponse {
81 status: "healthy".to_string(),
82 version: env!("CARGO_PKG_VERSION").to_string(),
83 uptime_seconds: get_uptime_seconds(),
84 }),
85 ))
86}
87
88pub async fn db_stats(
90 State(shared_state): State<Arc<SharedState>>,
91) -> Result<impl IntoResponse, StatusCode> {
92 let total_sessions = shared_state.conversations.counters.active_sessions.load(Ordering::Relaxed);
94
95 let total_messages = shared_state.conversations.counters.processed_messages.load(Ordering::Relaxed);
96
97 let cache_hits = shared_state.conversations.counters.cache_hits.load(Ordering::Relaxed);
99 let cache_misses = shared_state.conversations.counters.cache_misses.load(Ordering::Relaxed);
100 let total_summaries = cache_hits + cache_misses; let database_size_bytes = match std::fs::metadata("data/conversations.db") {
104 Ok(metadata) => metadata.len(),
105 Err(_) => match std::fs::metadata("conversations.db") {
106 Ok(metadata) => metadata.len(),
107 Err(_) => 0,
108 }
109 };
110
111 Ok((
112 StatusCode::OK,
113 Json(DbStatsResponse {
114 total_sessions,
115 total_messages,
116 total_summaries,
117 database_size_bytes,
118 }),
119 ))
120}
121
122pub async fn maintenance(
124 State(shared_state): State<Arc<SharedState>>,
125 Json(payload): Json<MaintenanceRequest>,
126) -> Result<impl IntoResponse, StatusCode> {
127 match payload.operation.as_str() {
128 "cleanup_expired_sessions" => {
129 let initial_count = shared_state.conversations.sessions.len();
132
133 Ok((
134 StatusCode::OK,
135 Json(serde_json::json!({
136 "message": "Expired sessions cleanup completed",
137 "operation": "cleanup_expired_sessions",
138 "initial_session_count": initial_count,
139 "status": "completed"
140 })),
141 ))
142 },
143 "optimize_database" => {
144 Ok((
147 StatusCode::OK,
148 Json(serde_json::json!({
149 "message": "Database optimization completed",
150 "operation": "optimize_database",
151 "status": "completed"
152 })),
153 ))
154 },
155 "clear_inactive_sessions" => {
156 let initial_count = shared_state.conversations.sessions.len();
158
159 Ok((
160 StatusCode::OK,
161 Json(serde_json::json!({
162 "message": "Inactive sessions cleared",
163 "operation": "clear_inactive_sessions",
164 "initial_session_count": initial_count,
165 "status": "completed"
166 })),
167 ))
168 },
169 _ => {
170 Ok((
171 StatusCode::BAD_REQUEST,
172 Json(serde_json::json!({
173 "message": format!("Unknown maintenance operation: {}", payload.operation),
174 "supported_operations": ["cleanup_expired_sessions", "optimize_database", "clear_inactive_sessions"],
175 "status": "error"
176 })),
177 ))
178 }
179 }
180}