71 lines
2.0 KiB
Rust
71 lines
2.0 KiB
Rust
//! 设备服务节点管理 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<AppState>,
|
|
Json(req): Json<NodeRegisterRequest>,
|
|
) -> Result<Json<Value>, 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<AppState>,
|
|
Path(node_id): Path<String>,
|
|
) -> Result<Json<Value>, 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<AppState>,
|
|
Path(node_id): Path<String>,
|
|
) -> Result<Json<Value>, 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<AppState>,
|
|
) -> Result<Json<Value>, AppError> {
|
|
let nodes = state.nodes.list().await;
|
|
let list: Vec<Value> = 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()})))
|
|
}
|