diff --git a/crates/app_feeder_distributor/src/handler/control.rs b/crates/app_feeder_distributor/src/handler/control.rs index 8c03d95..dee91f5 100644 --- a/crates/app_feeder_distributor/src/handler/control.rs +++ b/crates/app_feeder_distributor/src/handler/control.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use axum::{ extract::{Path, Query, State}, http::StatusCode, @@ -10,12 +12,20 @@ use uuid::Uuid; use validator::Validate; use crate::{ + control::runtime::{UnitRuntime, UnitRuntimeState}, control::validator::{validate_manual_control, ControlAction}, + event::AppEvent, AppState, }; -use plc_platform_core::util::{ - pagination::{PaginatedResponse, PaginationParams}, - response::ApiErr, +use plc_platform_core::{ + handler::equipment::SignalRolePoint, + model::{ControlUnit, Equipment, Point}, + service, + telemetry::PointMonitorInfo, + util::{ + pagination::{PaginatedResponse, PaginationParams}, + response::ApiErr, + }, }; fn validate_unit_timing_order(run_time_sec: i32, acc_time_sec: i32) -> Result<(), ApiErr> { @@ -32,7 +42,7 @@ fn validate_unit_timing_order(run_time_sec: i32, acc_time_sec: i32) -> Result<() Ok(()) } -fn auto_control_start_blocked(runtime: &crate::control::runtime::UnitRuntime) -> bool { +fn auto_control_start_blocked(runtime: &UnitRuntime) -> bool { runtime.fault_locked || runtime.comm_locked || runtime.manual_ack_required || runtime.rem_local } @@ -47,15 +57,15 @@ pub struct GetUnitListQuery { #[derive(serde::Serialize)] pub struct UnitEquipmentItem { #[serde(flatten)] - pub equipment: plc_platform_core::model::Equipment, - pub role_points: Vec, + pub equipment: Equipment, + pub role_points: Vec, } #[derive(serde::Serialize)] pub struct UnitWithRuntime { #[serde(flatten)] - pub unit: plc_platform_core::model::ControlUnit, - pub runtime: Option, + pub unit: ControlUnit, + pub runtime: Option, pub equipments: Vec, } @@ -66,9 +76,9 @@ pub async fn get_unit_list( query.validate()?; let total = - plc_platform_core::service::get_units_count(&state.platform.pool, query.keyword.as_deref()) + service::get_units_count(&state.platform.pool, query.keyword.as_deref()) .await?; - let units = plc_platform_core::service::get_units_paginated( + let units = service::get_units_paginated( &state.platform.pool, query.keyword.as_deref(), query.pagination.page_size, @@ -80,12 +90,12 @@ pub async fn get_unit_list( let unit_ids: Vec = units.iter().map(|u| u.id).collect(); let all_equipments = - plc_platform_core::service::get_equipment_by_unit_ids(&state.platform.pool, &unit_ids) + service::get_equipment_by_unit_ids(&state.platform.pool, &unit_ids) .await?; let eq_ids: Vec = all_equipments.iter().map(|e| e.id).collect(); let role_point_rows = - plc_platform_core::service::get_signal_role_points_batch(&state.platform.pool, &eq_ids) + service::get_signal_role_points_batch(&state.platform.pool, &eq_ids) .await?; let monitor_guard = state @@ -94,13 +104,13 @@ pub async fn get_unit_list( .get_point_monitor_data_read_guard() .await; - let mut role_points_map: std::collections::HashMap< + let mut role_points_map: HashMap< Uuid, - Vec, - > = std::collections::HashMap::new(); + Vec, + > = HashMap::new(); for rp in role_point_rows { role_points_map.entry(rp.equipment_id).or_default().push( - plc_platform_core::handler::equipment::SignalRolePoint { + SignalRolePoint { point_id: rp.point_id, signal_role: rp.signal_role, point_monitor: monitor_guard.get(&rp.point_id).cloned(), @@ -109,8 +119,8 @@ pub async fn get_unit_list( } drop(monitor_guard); - let mut equipments_by_unit: std::collections::HashMap> = - std::collections::HashMap::new(); + let mut equipments_by_unit: HashMap> = + HashMap::new(); for eq in all_equipments { let role_points = role_points_map.remove(&eq.id).unwrap_or_default(); if let Some(unit_id) = eq.unit_id { @@ -177,12 +187,12 @@ async fn send_equipment_command( .map_err(|e| ApiErr::Internal(e, None))?; let event = match action { - ControlAction::Start => crate::event::AppEvent::EquipmentStartCommandSent { + ControlAction::Start => AppEvent::EquipmentStartCommandSent { equipment_id, unit_id: context.unit_id, point_id: context.command_point.point_id, }, - ControlAction::Stop => crate::event::AppEvent::EquipmentStopCommandSent { + ControlAction::Stop => AppEvent::EquipmentStopCommandSent { equipment_id, unit_id: context.unit_id, point_id: context.command_point.point_id, @@ -204,29 +214,29 @@ pub async fn get_unit( State(state): State, Path(unit_id): Path, ) -> Result { - let unit = plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + let unit = service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; let runtime = state.control_runtime.get(unit_id).await; let all_equipments = - plc_platform_core::service::get_equipment_by_unit_id(&state.platform.pool, unit_id).await?; + service::get_equipment_by_unit_id(&state.platform.pool, unit_id).await?; let eq_ids: Vec = all_equipments.iter().map(|e| e.id).collect(); let role_point_rows = - plc_platform_core::service::get_signal_role_points_batch(&state.platform.pool, &eq_ids) + service::get_signal_role_points_batch(&state.platform.pool, &eq_ids) .await?; let monitor_guard = state .platform .connection_manager .get_point_monitor_data_read_guard() .await; - let mut role_points_map: std::collections::HashMap< + let mut role_points_map: HashMap< Uuid, - Vec, - > = std::collections::HashMap::new(); + Vec, + > = HashMap::new(); for rp in role_point_rows { role_points_map.entry(rp.equipment_id).or_default().push( - plc_platform_core::handler::equipment::SignalRolePoint { + SignalRolePoint { point_id: rp.point_id, signal_role: rp.signal_role, point_monitor: monitor_guard.get(&rp.point_id).cloned(), @@ -256,22 +266,22 @@ pub async fn get_unit( #[derive(serde::Serialize)] pub struct PointDetail { #[serde(flatten)] - pub point: plc_platform_core::model::Point, - pub point_monitor: Option, + pub point: Point, + pub point_monitor: Option, } #[derive(serde::Serialize)] pub struct EquipmentDetail { #[serde(flatten)] - pub equipment: plc_platform_core::model::Equipment, + pub equipment: Equipment, pub points: Vec, } #[derive(serde::Serialize)] pub struct UnitDetail { #[serde(flatten)] - pub unit: plc_platform_core::model::ControlUnit, - pub runtime: Option, + pub unit: ControlUnit, + pub runtime: Option, pub equipments: Vec, } @@ -279,16 +289,16 @@ pub async fn get_unit_detail( State(state): State, Path(unit_id): Path, ) -> Result { - let unit = plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + let unit = service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; let runtime = state.control_runtime.get(unit_id).await; let equipments = - plc_platform_core::service::get_equipment_by_unit_id(&state.platform.pool, unit_id).await?; + service::get_equipment_by_unit_id(&state.platform.pool, unit_id).await?; let equipment_ids: Vec = equipments.iter().map(|e| e.id).collect(); - let all_points = plc_platform_core::service::get_points_by_equipment_ids( + let all_points = service::get_points_by_equipment_ids( &state.platform.pool, &equipment_ids, ) @@ -377,7 +387,7 @@ pub async fn create_unit( validate_unit_timing_order(run_time_sec, acc_time_sec)?; - if plc_platform_core::service::get_unit_by_code(&state.platform.pool, &payload.code) + if service::get_unit_by_code(&state.platform.pool, &payload.code) .await? .is_some() { @@ -387,9 +397,9 @@ pub async fn create_unit( )); } - let unit_id = plc_platform_core::service::create_unit( + let unit_id = service::create_unit( &state.platform.pool, - plc_platform_core::service::CreateUnitParams { + service::CreateUnitParams { code: &payload.code, name: &payload.name, description: payload.description.as_deref(), @@ -438,7 +448,7 @@ pub async fn update_unit( ) -> Result { payload.validate()?; - let existing_unit = plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + let existing_unit = service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; @@ -449,7 +459,7 @@ pub async fn update_unit( if let Some(code) = payload.code.as_deref() { let duplicate = - plc_platform_core::service::get_unit_by_code(&state.platform.pool, code).await?; + service::get_unit_by_code(&state.platform.pool, code).await?; if duplicate.as_ref().is_some_and(|item| item.id != unit_id) { return Err(ApiErr::BadRequest( "Unit code already exists".to_string(), @@ -471,10 +481,10 @@ pub async fn update_unit( return Ok(Json(serde_json::json!({"ok_msg": "No fields to update"}))); } - plc_platform_core::service::update_unit( + service::update_unit( &state.platform.pool, unit_id, - plc_platform_core::service::UpdateUnitParams { + service::UpdateUnitParams { code: payload.code.as_deref(), name: payload.name.as_deref(), description: payload.description.as_deref(), @@ -497,7 +507,7 @@ pub async fn delete_unit( State(state): State, Path(unit_id): Path, ) -> Result { - let deleted = plc_platform_core::service::delete_unit(&state.platform.pool, unit_id).await?; + let deleted = service::delete_unit(&state.platform.pool, unit_id).await?; if !deleted { return Err(ApiErr::NotFound("Unit not found".to_string(), None)); } @@ -520,13 +530,13 @@ pub async fn get_event_list( ) -> Result { query.validate()?; - let total = plc_platform_core::service::get_events_count( + let total = service::get_events_count( &state.platform.pool, query.unit_id, query.event_type.as_deref(), ) .await?; - let data = plc_platform_core::service::get_events_paginated( + let data = service::get_events_paginated( &state.platform.pool, query.unit_id, query.event_type.as_deref(), @@ -547,7 +557,7 @@ pub async fn start_auto_unit( State(state): State, Path(unit_id): Path, ) -> Result { - let unit = plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + let unit = service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; @@ -569,13 +579,13 @@ pub async fn start_auto_unit( return Err(ApiErr::BadRequest(message.to_string(), None)); } runtime.auto_enabled = true; - runtime.state = crate::control::runtime::UnitRuntimeState::Stopped; + runtime.state = UnitRuntimeState::Stopped; state.control_runtime.upsert(runtime).await; state.control_runtime.notify_unit(unit_id).await; let _ = state .event_manager - .send(crate::event::AppEvent::AutoControlStarted { unit_id }); + .send(AppEvent::AutoControlStarted { unit_id }); Ok(Json( json!({ "ok_msg": "Auto control started", "unit_id": unit_id }), @@ -586,7 +596,7 @@ pub async fn stop_auto_unit( State(state): State, Path(unit_id): Path, ) -> Result { - plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; @@ -597,7 +607,7 @@ pub async fn stop_auto_unit( let _ = state .event_manager - .send(crate::event::AppEvent::AutoControlStopped { unit_id }); + .send(AppEvent::AutoControlStopped { unit_id }); Ok(Json( json!({ "ok_msg": "Auto control stopped", "unit_id": unit_id }), @@ -605,7 +615,7 @@ pub async fn stop_auto_unit( } pub async fn batch_start_auto(State(state): State) -> Result { - let units = plc_platform_core::service::get_all_enabled_units(&state.platform.pool).await?; + let units = service::get_all_enabled_units(&state.platform.pool).await?; let mut started = Vec::new(); let mut skipped = Vec::new(); @@ -620,12 +630,12 @@ pub async fn batch_start_auto(State(state): State) -> Result) -> Result) -> Result { - let units = plc_platform_core::service::get_all_enabled_units(&state.platform.pool).await?; + let units = service::get_all_enabled_units(&state.platform.pool).await?; let mut stopped = Vec::new(); for unit in units { @@ -646,7 +656,7 @@ pub async fn batch_stop_auto(State(state): State) -> Result, Path(unit_id): Path, ) -> Result { - plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; @@ -678,13 +688,13 @@ pub async fn ack_fault_unit( runtime.fault_locked = false; runtime.manual_ack_required = false; - runtime.state = crate::control::runtime::UnitRuntimeState::Stopped; + runtime.state = UnitRuntimeState::Stopped; state.control_runtime.upsert(runtime).await; state.control_runtime.notify_unit(unit_id).await; let _ = state .event_manager - .send(crate::event::AppEvent::FaultAcked { unit_id }); + .send(AppEvent::FaultAcked { unit_id }); Ok(Json( json!({ "ok_msg": "Fault acknowledged", "unit_id": unit_id }), @@ -695,7 +705,7 @@ pub async fn get_unit_runtime( State(state): State, Path(unit_id): Path, ) -> Result { - plc_platform_core::service::get_unit_by_id(&state.platform.pool, unit_id) + service::get_unit_by_id(&state.platform.pool, unit_id) .await? .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?;