algocline_app/service/
status.rs1use algocline_engine::PendingFilter;
2
3use super::AppService;
4
5impl AppService {
6 pub async fn status(
23 &self,
24 session_id: Option<&str>,
25 pending_filter: Option<serde_json::Value>,
26 include_history: bool,
27 ) -> Result<String, String> {
28 let filter = self.resolve_pending_filter(pending_filter)?;
29 let snapshots = self
30 .registry
31 .list_snapshots(filter.as_ref(), include_history)
32 .await;
33
34 if let Some(sid) = session_id {
36 if let Some(snapshot) = snapshots.get(sid) {
37 let mut result = snapshot.clone();
38 if let Ok(strategies) = self.session_strategies.lock() {
40 if let Some(name) = strategies.get(sid) {
41 result["strategy"] = serde_json::json!(name);
42 }
43 }
44 result["session_id"] = serde_json::json!(sid);
45 return serde_json::to_string_pretty(&result).map_err(|e| e.to_string());
46 }
47 let pool_reg = self.pool_registry.read().await;
53 if let Some(entry) = pool_reg.find(sid) {
54 let result = serde_json::json!({
55 "status": "needs_response",
56 "session_id": sid,
57 "pool": true,
58 "pid": entry.pid,
59 "sock": entry.sock.to_string_lossy(),
60 "version": entry.version,
61 "created_at": entry.created_at,
62 });
63 return serde_json::to_string_pretty(&result).map_err(|e| e.to_string());
64 }
65 return Err(format!("session '{sid}' not found (may have completed)"));
66 }
67
68 if snapshots.is_empty() {
70 return Ok(serde_json::json!({
71 "active_sessions": 0,
72 "sessions": [],
73 })
74 .to_string());
75 }
76
77 let strategies = self.session_strategies.lock().ok();
78 let sessions: Vec<serde_json::Value> = snapshots
79 .into_iter()
80 .map(|(id, mut snapshot)| {
81 if let Some(ref strats) = strategies {
82 if let Some(name) = strats.get(&id) {
83 snapshot["strategy"] = serde_json::json!(name);
84 }
85 }
86 snapshot["session_id"] = serde_json::json!(id);
87 snapshot
88 })
89 .collect();
90
91 let result = serde_json::json!({
92 "active_sessions": sessions.len(),
93 "sessions": sessions,
94 });
95
96 serde_json::to_string_pretty(&result).map_err(|e| e.to_string())
97 }
98
99 fn resolve_pending_filter(
104 &self,
105 raw: Option<serde_json::Value>,
106 ) -> Result<Option<PendingFilter>, String> {
107 let Some(value) = raw else {
108 return Ok(None);
109 };
110 match value {
111 serde_json::Value::String(name) => PendingFilter::from_preset_with(
112 &name,
113 self.log_config.prompt_preview_chars,
114 )
115 .map(Some)
116 .ok_or_else(|| {
117 format!(
118 "unknown pending_filter preset '{name}' (valid: \"meta\" | \"preview\" | \"full\")"
119 )
120 }),
121 serde_json::Value::Object(_) => serde_json::from_value::<PendingFilter>(value)
122 .map(Some)
123 .map_err(|e| format!("invalid pending_filter object: {e}")),
124 other => Err(format!(
125 "pending_filter must be a preset name (string) or filter object, got {}",
126 match other {
127 serde_json::Value::Null => "null",
128 serde_json::Value::Bool(_) => "bool",
129 serde_json::Value::Number(_) => "number",
130 serde_json::Value::Array(_) => "array",
131 _ => "unknown",
132 }
133 )),
134 }
135 }
136}