plc_control/crates/app_operation_system/src/handler/runtime.rs

101 lines
2.9 KiB
Rust

//! Runtime read endpoints (design doc §9.3).
use axum::{
extract::{Path, State},
response::IntoResponse,
Json,
};
use serde_json::json;
use uuid::Uuid;
use plc_platform_core::util::response::ApiErr;
use crate::{
service::{segment as segment_service, station as station_service},
AppState,
};
pub async fn get_overview(State(state): State<AppState>) -> Result<impl IntoResponse, ApiErr> {
let segments = segment_service::list_segments(&state.platform.pool, None).await?;
let runtimes = state.segment_runtime.get_all().await;
let segment_payload: Vec<_> = segments
.into_iter()
.map(|seg| {
let runtime = runtimes.get(&seg.id).cloned();
json!({
"segment": seg,
"runtime": runtime,
})
})
.collect();
let resource_snapshot = state.resource_registry.snapshot().await;
let resources: Vec<_> = resource_snapshot
.into_iter()
.map(|(key, lease)| {
json!({
"resource_key": key,
"owner_segment_id": lease.owner_segment_id,
"acquired_at": lease.acquired_at,
"heartbeat_at": lease.heartbeat_at,
})
})
.collect();
Ok(Json(json!({
"segments": segment_payload,
"resources": resources,
})))
}
pub async fn get_segment_runtime(
State(state): State<AppState>,
Path(segment_id): Path<Uuid>,
) -> Result<impl IntoResponse, ApiErr> {
let segment = segment_service::get_segment_by_id(&state.platform.pool, segment_id)
.await?
.ok_or_else(|| ApiErr::NotFound("Segment not found".to_string(), None))?;
let runtime = state.segment_runtime.get_or_init(segment_id).await;
Ok(Json(json!({
"segment": segment,
"runtime": runtime,
})))
}
pub async fn get_station_runtime(
State(state): State<AppState>,
Path(station_id): Path<Uuid>,
) -> Result<impl IntoResponse, ApiErr> {
let station = station_service::get_station_by_id(&state.platform.pool, station_id)
.await?
.ok_or_else(|| ApiErr::NotFound("Station not found".to_string(), None))?;
let signals = station_service::list_station_signals(&state.platform.pool, station_id).await?;
// Attach the latest monitor sample for each bound point.
let monitor_guard = state
.platform
.connection_manager
.get_point_monitor_data_read_guard()
.await;
let signal_payload: Vec<_> = signals
.iter()
.map(|sig| {
let monitor = sig
.point_id
.and_then(|pid| monitor_guard.get(&pid).cloned());
json!({
"signal": sig,
"point_monitor": monitor,
})
})
.collect();
drop(monitor_guard);
Ok(Json(json!({
"station": station,
"signals": signal_payload,
})))
}