//! 设备服务节点管理 API //! //! 设备服务启动时注册到 API 服务,定期发送心跳。 //! API 服务通过节点健康状况判断设备服务是否在线。 use axum::extract::{Path, State}; use axum::Json; use serde::Deserialize; use serde_json::{json, Value}; use crate::commands::AppState; use crate::error::AppError; /// 节点注册请求体 #[derive(Debug, Deserialize)] pub struct NodeRegisterRequest { pub node_id: String, pub ip: String, pub tcp_port: u16, } /// POST /api/nodes/register — 设备服务注册 pub async fn register_node( State(state): State, Json(req): Json, ) -> Result, AppError> { state.nodes.register(&req.node_id, &req.ip, req.tcp_port).await; tracing::info!("[节点注册] node_id={}", req.node_id); Ok(Json(json!({"suc": 1}))) } /// POST /api/nodes/:node_id/heartbeat — 节点心跳 pub async fn node_heartbeat( State(state): State, Path(node_id): Path, ) -> Result, AppError> { if state.nodes.heartbeat(&node_id).await { Ok(Json(json!({"suc": 1}))) } else { Ok(Json(json!({"suc": 0, "err": "节点未注册"}))) } } /// POST /api/nodes/:node_id/deregister — 节点注销 pub async fn deregister_node( State(state): State, Path(node_id): Path, ) -> Result, AppError> { state.nodes.remove(&node_id).await; tracing::info!("[节点注销] node_id={}", node_id); Ok(Json(json!({"suc": 1}))) } /// GET /api/nodes — 节点列表 pub async fn list_nodes( State(state): State, ) -> Result, AppError> { let nodes = state.nodes.list().await; let list: Vec = nodes .into_iter() .map(|n| { json!({ "node_id": n.node_id, "ip": n.ip, "tcp_port": n.tcp_port, }) }) .collect(); Ok(Json(json!({"nodes": list, "count": list.len()}))) }