96 lines
3.1 KiB
Markdown
96 lines
3.1 KiB
Markdown
# 任务017:重构审查问题修复
|
||
|
||
## 目标
|
||
|
||
修复TCP服务重构审查发现的P0/P1问题。
|
||
|
||
## 修复清单
|
||
|
||
### P0:Redis类型冲突
|
||
|
||
**位置:** `device-server/src/main.rs`
|
||
|
||
**问题:** `register_node`用`SET`(string类型),`heartbeat`用`HSET`(hash类型),同一key操作触发`WRONGTYPE`错误。
|
||
|
||
**修复:** 统一用HSET:
|
||
```rust
|
||
// 节点注册
|
||
async fn register_node(redis: &Redis, node_id: &str, ip: &str, tcp_port: u16) {
|
||
redis.hset(&format!("node:{}", node_id), &[
|
||
("ip", ip),
|
||
("tcp_port", &tcp_port.to_string()),
|
||
("status", "online"),
|
||
("last_heartbeat", &Instant::now().elapsed().as_secs().to_string()),
|
||
]).await;
|
||
redis.expire(&format!("node:{}", node_id), 300).await;
|
||
}
|
||
|
||
// 节点心跳
|
||
async fn heartbeat(redis: &Redis, node_id: &str) {
|
||
redis.hset(&format!("node:{}", node_id), &[
|
||
("last_heartbeat", &Instant::now().elapsed().as_secs().to_string()),
|
||
]).await;
|
||
redis.expire(&format!("node:{}", node_id), 300).await;
|
||
}
|
||
```
|
||
|
||
### P1:节点管理双轨制
|
||
|
||
**问题:** API服务维护内存`NodeRegistry`,设备服务直接写Redis,两者不关联。
|
||
|
||
**修复方案A(推荐):** API服务从Redis读取节点信息
|
||
```rust
|
||
// API服务节点列表
|
||
async fn list_nodes(redis: &Redis) -> Result<Json<Vec<NodeInfo>>> {
|
||
let keys = redis.keys("node:*").await?;
|
||
let mut nodes = Vec::new();
|
||
for key in keys {
|
||
let node_id = key.strip_prefix("node:").unwrap();
|
||
let info: HashMap<String, String> = redis.hgetall(&key).await?;
|
||
nodes.push(NodeInfo {
|
||
id: node_id.to_string(),
|
||
ip: info.get("ip").cloned().unwrap_or_default(),
|
||
tcp_port: info.get("tcp_port").and_then(|p| p.parse().ok()).unwrap_or(0),
|
||
status: info.get("status").cloned().unwrap_or_default(),
|
||
last_heartbeat: info.get("last_heartbeat").cloned().unwrap_or_default(),
|
||
});
|
||
}
|
||
Ok(Json(nodes))
|
||
}
|
||
```
|
||
|
||
**修复方案B:** 设备服务通过HTTP注册到API服务
|
||
- 设备服务启动时POST到`/api/nodes/register`
|
||
- API服务存内存
|
||
- 心跳POST到`/api/nodes/:id/heartbeat`
|
||
- 注销POST到`/api/nodes/:id/deregister`
|
||
|
||
### P2:配置系统
|
||
|
||
**问题:** 代码用`dotenvy`读环境变量,config.toml形同虚设。
|
||
|
||
**修复:** 二选一
|
||
- 方案A:用`toml` crate读config.toml
|
||
- 方案B:删除config.toml,只用.env
|
||
|
||
### P3:协议结构体重复
|
||
|
||
**问题:** `DeviceMessage`等结构体在两个服务中重复定义。
|
||
|
||
**修复:** 暂不处理,后续提取shared crate时统一。
|
||
|
||
### P4:限流器同步Mutex
|
||
|
||
**问题:** 限流器用`std::sync::Mutex`,不符合异步规范。
|
||
|
||
**修复:** 改用`tokio::sync::Mutex`或`RwLock`。
|
||
|
||
## 质量约束
|
||
|
||
1. 完成代码后执行 `cargo check` + `cargo clippy`,零报错零警告
|
||
2. 分层拆分,单函数≤80行,命名语义化,完整注释
|
||
3. 所有外部IO/网络请求异常捕获,禁止裸panic
|
||
4. 分支逻辑全覆盖,不遗漏兜底分支
|
||
5. 常量抽离,不使用废弃API
|
||
6. Rust内存安全,合理管理所有权,禁用unsafe无合理理由
|