1use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11use crate::amalgamation;
12use crate::common::ApiState;
13use crate::common::{ApiError, ApiResult, Json, State};
14
15#[allow(non_snake_case)] #[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
21pub struct FatigueInfo {
22 pub fatigue_index: Option<u8>,
24 pub fatigue_active: Option<bool>,
26 pub regular_neuron_util: Option<u8>,
28 pub memory_neuron_util: Option<u8>,
30 pub synapse_util: Option<u8>,
32}
33
34#[allow(non_snake_case)] #[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
36pub struct HealthCheckResponse {
37 pub burst_engine: bool,
38 pub connected_agents: Option<i32>,
39 pub influxdb_availability: bool,
40 pub neuron_count_max: i64,
41 pub synapse_count_max: i64,
42 pub latest_changes_saved_externally: bool,
43 pub genome_availability: bool,
44 pub genome_validity: Option<bool>,
45 pub brain_readiness: bool,
46 pub genome_loading: bool,
48 pub genome_state: String,
50 pub feagi_session: Option<i64>,
51 pub fitness: Option<f64>,
52 pub cortical_area_count: Option<i32>,
53 pub neuron_count: Option<i64>,
54 pub memory_neuron_count: Option<i64>,
55 pub regular_neuron_count: Option<i64>,
56 pub synapse_count: Option<i64>,
57 pub estimated_brain_size_in_MB: Option<f64>,
58 pub genome_num: Option<i32>,
59 pub genome_timestamp: Option<i64>,
60 pub simulation_timestep: Option<f64>,
61 pub memory_area_stats: Option<HashMap<String, HashMap<String, serde_json::Value>>>,
62 pub amalgamation_pending: Option<HashMap<String, serde_json::Value>>,
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub brain_regions_hash: Option<u64>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub cortical_areas_hash: Option<u64>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub brain_geometry_hash: Option<u64>,
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub morphologies_hash: Option<u64>,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub cortical_mappings_hash: Option<u64>,
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub agent_data_hash: Option<u64>,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub brain_regions_root: Option<String>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub fatigue: Option<FatigueInfo>,
87}
88
89#[utoipa::path(
95 get,
96 path = "/v1/system/health_check",
97 responses(
98 (status = 200, description = "System health retrieved successfully", body = HealthCheckResponse),
99 (status = 500, description = "Internal server error")
100 ),
101 tag = "system"
102)]
103pub async fn get_health_check(
104 State(state): State<ApiState>,
105) -> ApiResult<Json<HealthCheckResponse>> {
106 let analytics_service = state.analytics_service.as_ref();
107
108 let health = analytics_service
110 .get_system_health()
111 .await
112 .map_err(|e| ApiError::internal(format!("Failed to get system health: {}", e)))?;
113
114 let runtime_status = state.runtime_service.get_status().await.ok();
116 let burst_engine_active = runtime_status
117 .as_ref()
118 .map(|status| status.is_running)
119 .unwrap_or(false);
120
121 let _burst_count = state.runtime_service.get_burst_count().await.ok();
122
123 let connected_agents = if let Some(agent_service) = state.agent_service.as_ref() {
125 agent_service
126 .list_agents()
127 .await
128 .ok()
129 .map(|agents| agents.len() as i32)
130 } else {
131 None
132 };
133
134 let synapse_count = analytics_service
136 .get_total_synapse_count()
137 .await
138 .ok()
139 .map(|count| count as i64);
140
141 let regular_neuron_count = analytics_service
143 .get_regular_neuron_count()
144 .await
145 .ok()
146 .map(|count| count as i64);
147
148 let memory_neuron_count = analytics_service
149 .get_memory_neuron_count()
150 .await
151 .ok()
152 .map(|count| count as i64);
153
154 let genome_info = state.genome_service.get_genome_info().await.ok();
156
157 let runtime_timestep = runtime_status.as_ref().map(|status| {
159 if status.frequency_hz > 0.0 {
160 1.0 / status.frequency_hz
161 } else {
162 0.0
163 }
164 });
165 let simulation_timestep =
166 runtime_timestep.or_else(|| genome_info.as_ref().map(|info| info.simulation_timestep));
167 let genome_num = genome_info.as_ref().and_then(|info| info.genome_num);
168 let genome_timestamp = genome_info.as_ref().and_then(|info| info.genome_timestamp);
169
170 #[allow(non_snake_case)] let estimated_brain_size_in_MB = {
174 let neuron_bytes = health.neuron_count * 64;
175 let synapse_bytes = synapse_count.unwrap_or(0) as usize * 16;
176 let metadata_bytes = health.cortical_area_count * 512; let total_bytes = neuron_bytes + synapse_bytes + metadata_bytes;
178 Some((total_bytes as f64) / (1024.0 * 1024.0))
179 };
180
181 let neuron_count_max = health.neuron_capacity as i64;
183 let synapse_count_max = health.synapse_capacity as i64;
184
185 let influxdb_availability = false; let latest_changes_saved_externally = false; let genome_availability = health.cortical_area_count > 0;
189 let genome_validity = Some(health.brain_readiness);
190
191 let feagi_session = Some(state.feagi_session_timestamp);
193
194 let fitness = None; let (memory_area_stats, memory_neuron_count_from_cache) = state
203 .memory_stats_cache
204 .as_ref()
205 .map(|cache| {
206 let snapshot = feagi_npu_plasticity::memory_stats_cache::get_stats_snapshot(cache);
207 let total = snapshot
208 .values()
209 .map(|s| s.neuron_count as i64)
210 .sum::<i64>();
211 let per_area = snapshot
212 .into_iter()
213 .map(|(name, stats)| {
214 let mut inner_map = HashMap::new();
215 inner_map.insert(
216 "neuron_count".to_string(),
217 serde_json::json!(stats.neuron_count),
218 );
219 inner_map.insert(
220 "created_total".to_string(),
221 serde_json::json!(stats.created_total),
222 );
223 inner_map.insert(
224 "deleted_total".to_string(),
225 serde_json::json!(stats.deleted_total),
226 );
227 inner_map.insert(
228 "last_updated".to_string(),
229 serde_json::json!(stats.last_updated),
230 );
231 (name, inner_map)
232 })
233 .collect::<HashMap<String, HashMap<String, serde_json::Value>>>();
234 (Some(per_area), Some(total))
235 })
236 .unwrap_or((None, None));
237
238 let memory_neuron_count = memory_neuron_count_from_cache.or(memory_neuron_count);
240
241 let amalgamation_pending = state.amalgamation_state.read().pending.as_ref().map(|p| {
246 let v = amalgamation::pending_summary_to_health_json(&p.summary);
247 v.as_object()
248 .cloned()
249 .unwrap_or_default()
250 .into_iter()
251 .collect::<HashMap<String, serde_json::Value>>()
252 });
253
254 #[cfg(feature = "services")]
256 let brain_regions_root = feagi_brain_development::ConnectomeManager::instance()
257 .read()
258 .get_root_region_id();
259 #[cfg(not(feature = "services"))]
260 let brain_regions_root = None; #[cfg(feature = "services")]
265 let fatigue = {
266 use feagi_state_manager::StateManager;
267 match StateManager::instance().try_read() {
269 Some(state_manager) => {
270 let core_state = state_manager.get_core_state();
271 Some(FatigueInfo {
272 fatigue_index: Some(core_state.get_fatigue_index()),
273 fatigue_active: Some(core_state.is_fatigue_active()),
274 regular_neuron_util: Some(core_state.get_regular_neuron_util()),
275 memory_neuron_util: Some(core_state.get_memory_neuron_util()),
276 synapse_util: Some(core_state.get_synapse_util()),
277 })
278 }
279 None => {
280 tracing::warn!(target: "feagi-api", "StateManager is locked, cannot read fatigue data");
282 None
283 }
284 }
285 };
286 #[cfg(not(feature = "services"))]
287 let fatigue = {
288 tracing::debug!(target: "feagi-api", "Services feature not enabled, fatigue data unavailable");
289 None
290 };
291
292 let (
293 brain_regions_hash,
294 cortical_areas_hash,
295 brain_geometry_hash,
296 morphologies_hash,
297 cortical_mappings_hash,
298 agent_data_hash,
299 genome_loading,
300 genome_state,
301 ) = {
302 use feagi_state_manager::GenomeState;
303 let state_manager = feagi_state_manager::StateManager::instance();
304 let state_manager = state_manager.read();
305 let gs = state_manager.get_genome_state();
306 let genome_state = match gs {
307 GenomeState::Missing => "missing",
308 GenomeState::Loading => "loading",
309 GenomeState::Loaded => "loaded",
310 GenomeState::Saving => "saving",
311 GenomeState::Error => "error",
312 }
313 .to_string();
314 let genome_loading = gs == GenomeState::Loading;
315 (
316 Some(state_manager.get_brain_regions_hash()),
317 Some(state_manager.get_cortical_areas_hash()),
318 Some(state_manager.get_brain_geometry_hash()),
319 Some(state_manager.get_morphologies_hash()),
320 Some(state_manager.get_cortical_mappings_hash()),
321 Some(state_manager.get_agent_data_hash()),
322 genome_loading,
323 genome_state,
324 )
325 };
326
327 Ok(Json(HealthCheckResponse {
328 burst_engine: burst_engine_active,
329 connected_agents,
330 influxdb_availability,
331 neuron_count_max,
332 synapse_count_max,
333 latest_changes_saved_externally,
334 genome_availability,
335 genome_validity,
336 brain_readiness: health.brain_readiness,
337 genome_loading,
338 genome_state,
339 feagi_session,
340 fitness,
341 cortical_area_count: Some(health.cortical_area_count as i32),
342 neuron_count: Some(health.neuron_count as i64),
343 memory_neuron_count,
344 regular_neuron_count,
345 synapse_count,
346 estimated_brain_size_in_MB,
347 genome_num,
348 genome_timestamp,
349 simulation_timestep,
350 memory_area_stats,
351 amalgamation_pending,
352 brain_regions_hash,
353 cortical_areas_hash,
354 brain_geometry_hash,
355 morphologies_hash,
356 cortical_mappings_hash,
357 agent_data_hash,
358 brain_regions_root, fatigue,
360 }))
361}
362
363#[utoipa::path(
365 get,
366 path = "/v1/system/cortical_area_visualization_skip_rate",
367 responses(
368 (status = 200, description = "Skip rate retrieved successfully", body = i32),
369 (status = 500, description = "Internal server error")
370 ),
371 tag = "system"
372)]
373pub async fn get_cortical_area_visualization_skip_rate(
374 State(_state): State<ApiState>,
375) -> ApiResult<Json<i32>> {
376 Ok(Json(1))
379}
380
381#[utoipa::path(
383 put,
384 path = "/v1/system/cortical_area_visualization_skip_rate",
385 request_body = i32,
386 responses(
387 (status = 200, description = "Skip rate updated successfully"),
388 (status = 500, description = "Internal server error")
389 ),
390 tag = "system"
391)]
392pub async fn set_cortical_area_visualization_skip_rate(
393 State(_state): State<ApiState>,
394 Json(skip_rate): Json<i32>,
395) -> ApiResult<Json<serde_json::Value>> {
396 Ok(Json(serde_json::json!({
398 "message": format!("Skip rate set to {}", skip_rate)
399 })))
400}
401
402#[utoipa::path(
404 get,
405 path = "/v1/system/cortical_area_visualization_suppression_threshold",
406 responses(
407 (status = 200, description = "Threshold retrieved successfully", body = i32),
408 (status = 500, description = "Internal server error")
409 ),
410 tag = "system"
411)]
412pub async fn get_cortical_area_visualization_suppression_threshold(
413 State(_state): State<ApiState>,
414) -> ApiResult<Json<i32>> {
415 Ok(Json(0))
418}
419
420#[utoipa::path(
422 put,
423 path = "/v1/system/cortical_area_visualization_suppression_threshold",
424 request_body = i32,
425 responses(
426 (status = 200, description = "Threshold updated successfully"),
427 (status = 500, description = "Internal server error")
428 ),
429 tag = "system"
430)]
431pub async fn set_cortical_area_visualization_suppression_threshold(
432 State(_state): State<ApiState>,
433 Json(threshold): Json<i32>,
434) -> ApiResult<Json<serde_json::Value>> {
435 Ok(Json(serde_json::json!({
437 "message": format!("Suppression threshold set to {}", threshold)
438 })))
439}
440
441#[utoipa::path(
447 get,
448 path = "/v1/system/version",
449 tag = "system",
450 responses(
451 (status = 200, description = "Version string", body = String)
452 )
453)]
454pub async fn get_version(State(_state): State<ApiState>) -> ApiResult<Json<String>> {
455 Ok(Json(env!("CARGO_PKG_VERSION").to_string()))
456}
457
458#[utoipa::path(
460 get,
461 path = "/v1/system/versions",
462 tag = "system",
463 responses(
464 (status = 200, description = "Version information", body = HashMap<String, String>)
465 )
466)]
467pub async fn get_versions(
468 State(state): State<ApiState>,
469) -> ApiResult<Json<HashMap<String, String>>> {
470 match state.system_service.get_version().await {
473 Ok(version_info) => {
474 let mut versions = version_info.crates.clone();
475
476 versions.insert("rust".to_string(), version_info.rust_version);
478 versions.insert("build_timestamp".to_string(), version_info.build_timestamp);
479
480 Ok(Json(versions))
481 }
482 Err(e) => {
483 tracing::warn!(
485 "Failed to get version from system service: {}, using fallback",
486 e
487 );
488 let mut versions = HashMap::new();
489 versions.insert(
490 "error".to_string(),
491 "system service unavailable".to_string(),
492 );
493 Ok(Json(versions))
494 }
495 }
496}
497
498#[utoipa::path(
500 get,
501 path = "/v1/system/configuration",
502 tag = "system",
503 responses(
504 (status = 200, description = "System configuration", body = HashMap<String, serde_json::Value>)
505 )
506)]
507pub async fn get_configuration(
508 State(state): State<ApiState>,
509) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
510 let health = state
512 .analytics_service
513 .get_system_health()
514 .await
515 .map_err(|e| ApiError::internal(format!("Failed to get system health: {}", e)))?;
516
517 let mut config = HashMap::new();
518 config.insert("api_host".to_string(), serde_json::json!("0.0.0.0"));
519 config.insert("api_port".to_string(), serde_json::json!(8000));
520 config.insert(
522 "max_neurons".to_string(),
523 serde_json::json!(health.neuron_capacity),
524 );
525 config.insert(
526 "max_synapses".to_string(),
527 serde_json::json!(health.synapse_capacity),
528 );
529
530 Ok(Json(config))
531}
532
533#[utoipa::path(
535 get,
536 path = "/v1/system/user_preferences",
537 tag = "system",
538 responses(
539 (status = 200, description = "User preferences", body = HashMap<String, serde_json::Value>)
540 )
541)]
542pub async fn get_user_preferences(
543 State(_state): State<ApiState>,
544) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
545 let mut prefs = HashMap::new();
546 prefs.insert("adv_mode".to_string(), serde_json::json!(false));
547 prefs.insert("ui_magnification".to_string(), serde_json::json!(1.0));
548 prefs.insert(
549 "auto_pns_area_creation".to_string(),
550 serde_json::json!(true),
551 );
552
553 Ok(Json(prefs))
554}
555
556#[utoipa::path(
558 put,
559 path = "/v1/system/user_preferences",
560 tag = "system",
561 responses(
562 (status = 200, description = "Preferences updated", body = HashMap<String, String>)
563 )
564)]
565pub async fn put_user_preferences(
566 State(_state): State<ApiState>,
567 Json(_prefs): Json<HashMap<String, serde_json::Value>>,
568) -> ApiResult<Json<HashMap<String, String>>> {
569 Ok(Json(HashMap::from([(
570 "message".to_string(),
571 "User preferences updated successfully".to_string(),
572 )])))
573}
574
575#[utoipa::path(
577 get,
578 path = "/v1/system/cortical_area_types",
579 tag = "system",
580 responses(
581 (status = 200, description = "Cortical area types", body = Vec<String>)
582 )
583)]
584pub async fn get_cortical_area_types_list(
585 State(_state): State<ApiState>,
586) -> ApiResult<Json<Vec<String>>> {
587 Ok(Json(vec![
588 "Sensory".to_string(),
589 "Motor".to_string(),
590 "Custom".to_string(),
591 "Memory".to_string(),
592 "Core".to_string(),
593 ]))
594}
595
596#[utoipa::path(
598 post,
599 path = "/v1/system/enable_visualization_fq_sampler",
600 tag = "system",
601 responses(
602 (status = 200, description = "FQ sampler enabled", body = HashMap<String, String>)
603 )
604)]
605pub async fn post_enable_visualization_fq_sampler(
606 State(state): State<ApiState>,
607) -> ApiResult<Json<HashMap<String, String>>> {
608 let runtime_service = state.runtime_service.as_ref();
609
610 runtime_service
611 .set_fcl_sampler_config(None, Some(1))
612 .await
613 .map_err(|e| ApiError::internal(format!("Failed to enable FQ sampler: {}", e)))?;
614
615 Ok(Json(HashMap::from([(
616 "message".to_string(),
617 "Visualization FQ sampler enabled".to_string(),
618 )])))
619}
620
621#[utoipa::path(
623 post,
624 path = "/v1/system/disable_visualization_fq_sampler",
625 tag = "system",
626 responses(
627 (status = 200, description = "FQ sampler disabled", body = HashMap<String, String>)
628 )
629)]
630pub async fn post_disable_visualization_fq_sampler(
631 State(state): State<ApiState>,
632) -> ApiResult<Json<HashMap<String, String>>> {
633 let runtime_service = state.runtime_service.as_ref();
634
635 runtime_service
636 .set_fcl_sampler_config(None, Some(0))
637 .await
638 .map_err(|e| ApiError::internal(format!("Failed to disable FQ sampler: {}", e)))?;
639
640 Ok(Json(HashMap::from([(
641 "message".to_string(),
642 "Visualization FQ sampler disabled".to_string(),
643 )])))
644}
645
646#[utoipa::path(
648 get,
649 path = "/v1/system/fcl_status",
650 tag = "system",
651 responses(
652 (status = 200, description = "FCL status", body = HashMap<String, serde_json::Value>)
653 )
654)]
655pub async fn get_fcl_status_system(
656 State(state): State<ApiState>,
657) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
658 let runtime_service = state.runtime_service.as_ref();
659
660 let (frequency, consumer) = runtime_service
661 .get_fcl_sampler_config()
662 .await
663 .map_err(|e| ApiError::internal(format!("Failed to get FCL status: {}", e)))?;
664
665 let mut response = HashMap::new();
666 response.insert("available".to_string(), serde_json::json!(true));
667 response.insert("frequency".to_string(), serde_json::json!(frequency));
668 response.insert("consumer".to_string(), serde_json::json!(consumer));
669 response.insert("enabled".to_string(), serde_json::json!(consumer > 0));
670
671 Ok(Json(response))
672}
673
674#[utoipa::path(
676 post,
677 path = "/v1/system/fcl_reset",
678 tag = "system",
679 responses(
680 (status = 200, description = "FCL reset", body = HashMap<String, String>)
681 )
682)]
683pub async fn post_fcl_reset_system(
684 State(_state): State<ApiState>,
685) -> ApiResult<Json<HashMap<String, String>>> {
686 tracing::info!(target: "feagi-api", "FCL reset requested");
687
688 Ok(Json(HashMap::from([(
689 "message".to_string(),
690 "FCL reset successfully".to_string(),
691 )])))
692}
693
694#[utoipa::path(
696 get,
697 path = "/v1/system/processes",
698 tag = "system",
699 responses(
700 (status = 200, description = "Active processes", body = HashMap<String, serde_json::Value>)
701 )
702)]
703pub async fn get_processes(
704 State(state): State<ApiState>,
705) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
706 let runtime_service = state.runtime_service.as_ref();
707
708 let status = runtime_service
709 .get_status()
710 .await
711 .map_err(|e| ApiError::internal(format!("Failed to get processes: {}", e)))?;
712
713 let mut processes = HashMap::new();
714 processes.insert(
715 "burst_engine".to_string(),
716 serde_json::json!({
717 "active": status.is_running,
718 "paused": status.is_paused
719 }),
720 );
721 processes.insert(
722 "api_server".to_string(),
723 serde_json::json!({"active": true}),
724 );
725
726 Ok(Json(processes))
727}
728
729#[utoipa::path(
731 get,
732 path = "/v1/system/unique_logs",
733 tag = "system",
734 responses(
735 (status = 200, description = "Unique logs", body = HashMap<String, Vec<String>>)
736 )
737)]
738pub async fn get_unique_logs(
739 State(_state): State<ApiState>,
740) -> ApiResult<Json<HashMap<String, Vec<String>>>> {
741 let mut response = HashMap::new();
742 response.insert("logs".to_string(), Vec::new());
743
744 Ok(Json(response))
745}
746
747#[utoipa::path(
749 post,
750 path = "/v1/system/logs",
751 tag = "system",
752 responses(
753 (status = 200, description = "Log config updated", body = HashMap<String, String>)
754 )
755)]
756pub async fn post_logs(
757 State(_state): State<ApiState>,
758 Json(_config): Json<HashMap<String, serde_json::Value>>,
759) -> ApiResult<Json<HashMap<String, String>>> {
760 Ok(Json(HashMap::from([(
761 "message".to_string(),
762 "Log configuration updated".to_string(),
763 )])))
764}
765
766#[utoipa::path(
768 get,
769 path = "/v1/system/beacon/subscribers",
770 tag = "system",
771 responses(
772 (status = 200, description = "Beacon subscribers", body = Vec<String>)
773 )
774)]
775pub async fn get_beacon_subscribers(
776 State(_state): State<ApiState>,
777) -> ApiResult<Json<Vec<String>>> {
778 Ok(Json(Vec::new()))
779}
780
781#[utoipa::path(
783 post,
784 path = "/v1/system/beacon/subscribe",
785 tag = "system",
786 responses(
787 (status = 200, description = "Subscribed", body = HashMap<String, String>)
788 )
789)]
790pub async fn post_beacon_subscribe(
791 State(_state): State<ApiState>,
792 Json(_request): Json<HashMap<String, String>>,
793) -> ApiResult<Json<HashMap<String, String>>> {
794 Ok(Json(HashMap::from([(
795 "message".to_string(),
796 "Subscribed to beacon".to_string(),
797 )])))
798}
799
800#[utoipa::path(
802 delete,
803 path = "/v1/system/beacon/unsubscribe",
804 tag = "system",
805 responses(
806 (status = 200, description = "Unsubscribed", body = HashMap<String, String>)
807 )
808)]
809pub async fn delete_beacon_unsubscribe(
810 State(_state): State<ApiState>,
811 Json(_request): Json<HashMap<String, String>>,
812) -> ApiResult<Json<HashMap<String, String>>> {
813 Ok(Json(HashMap::from([(
814 "message".to_string(),
815 "Unsubscribed from beacon".to_string(),
816 )])))
817}
818
819#[utoipa::path(
821 get,
822 path = "/v1/system/global_activity_visualization",
823 tag = "system",
824 responses(
825 (status = 200, description = "Global activity viz status", body = HashMap<String, serde_json::Value>)
826 )
827)]
828pub async fn get_global_activity_visualization(
829 State(_state): State<ApiState>,
830) -> ApiResult<Json<HashMap<String, serde_json::Value>>> {
831 let mut response = HashMap::new();
832 response.insert("enabled".to_string(), serde_json::json!(false));
833 response.insert("frequency_hz".to_string(), serde_json::json!(30.0));
834
835 Ok(Json(response))
836}
837
838#[utoipa::path(
840 put,
841 path = "/v1/system/global_activity_visualization",
842 tag = "system",
843 responses(
844 (status = 200, description = "Configured", body = HashMap<String, String>)
845 )
846)]
847pub async fn put_global_activity_visualization(
848 State(_state): State<ApiState>,
849 Json(_config): Json<HashMap<String, serde_json::Value>>,
850) -> ApiResult<Json<HashMap<String, String>>> {
851 Ok(Json(HashMap::from([(
852 "message".to_string(),
853 "Global activity visualization configured".to_string(),
854 )])))
855}
856
857#[utoipa::path(
859 post,
860 path = "/v1/system/circuit_library_path",
861 tag = "system",
862 responses(
863 (status = 200, description = "Path set", body = HashMap<String, String>)
864 )
865)]
866pub async fn post_circuit_library_path(
867 State(_state): State<ApiState>,
868 Json(_request): Json<HashMap<String, String>>,
869) -> ApiResult<Json<HashMap<String, String>>> {
870 Ok(Json(HashMap::from([(
871 "message".to_string(),
872 "Circuit library path updated".to_string(),
873 )])))
874}
875
876#[utoipa::path(
878 get,
879 path = "/v1/system/db/influxdb/test",
880 tag = "system",
881 responses(
882 (status = 200, description = "Test result", body = HashMap<String, bool>)
883 )
884)]
885pub async fn get_influxdb_test(
886 State(_state): State<ApiState>,
887) -> ApiResult<Json<HashMap<String, bool>>> {
888 let mut response = HashMap::new();
889 response.insert("connected".to_string(), false);
890 response.insert("available".to_string(), false);
891
892 Ok(Json(response))
893}
894
895#[utoipa::path(
897 post,
898 path = "/v1/system/register",
899 tag = "system",
900 responses(
901 (status = 200, description = "Registered", body = HashMap<String, String>)
902 )
903)]
904pub async fn post_register_system(
905 State(_state): State<ApiState>,
906 Json(_request): Json<HashMap<String, serde_json::Value>>,
907) -> ApiResult<Json<HashMap<String, String>>> {
908 Ok(Json(HashMap::from([(
909 "message".to_string(),
910 "System component registered".to_string(),
911 )])))
912}