feat: core tests, bug fixes, API docs rewrite, HTTP compat routes
- Fix state_machine reset_state_progress: reset sequence index before validation to prevent out-of-bounds error on state transitions - Fix video transformer test: use ±1 tolerance for OpenCV interpolation - Add core integration tests (service_manager, dependencies, messages) - Add HTTP compat routes (/index.html, POST /api/wifi/scan, hotspot aliases) - Rewrite clients/docs/API.md to match actual implementation - Fix BLE unused imports warning - CEO task planning for next round (ConfigReload, playlist snapshot) cargo check: 0 warnings, cargo test: 22/22 passed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -97,16 +97,24 @@ fn root_route() -> impl Filter<Extract = impl Reply, Error = warp::Rejection> +
|
||||
warp::path::end()
|
||||
.and(warp::get())
|
||||
.map(|| warp::reply::html(WEB_UI_HTML))
|
||||
.or(
|
||||
warp::path("index.html")
|
||||
.and(warp::path::end())
|
||||
.and(warp::get())
|
||||
.map(|| warp::reply::html(WEB_UI_HTML)),
|
||||
)
|
||||
}
|
||||
|
||||
fn ws_route(
|
||||
state: Arc<HttpState>,
|
||||
) -> impl Filter<Extract = impl Reply, Error = warp::Rejection> + Clone {
|
||||
warp::path("ws").and(warp::ws()).and(with_state(state)).map(
|
||||
|ws: warp::ws::Ws, state: Arc<HttpState>| {
|
||||
warp::path("ws")
|
||||
.and(warp::path::end())
|
||||
.and(warp::ws())
|
||||
.and(with_state(state))
|
||||
.map(|ws: warp::ws::Ws, state: Arc<HttpState>| {
|
||||
ws.on_upgrade(move |socket| websocket_session(socket, state))
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn status_route(
|
||||
@@ -343,11 +351,21 @@ fn wifi_scan_route(
|
||||
tx: mpsc::Sender<Envelope>,
|
||||
state: Arc<HttpState>,
|
||||
) -> impl Filter<Extract = impl Reply, Error = warp::Rejection> + Clone {
|
||||
let tx_for_post = tx.clone();
|
||||
let state_for_post = Arc::clone(&state);
|
||||
|
||||
warp::path!("api" / "wifi" / "scan")
|
||||
.and(warp::get())
|
||||
.and(with_tx(tx))
|
||||
.and(with_state(state))
|
||||
.and(with_state(Arc::clone(&state)))
|
||||
.and_then(handle_wifi_scan)
|
||||
.or(
|
||||
warp::path!("api" / "wifi" / "scan")
|
||||
.and(warp::post())
|
||||
.and(with_tx(tx_for_post))
|
||||
.and(with_state(state_for_post))
|
||||
.and_then(handle_wifi_scan),
|
||||
)
|
||||
}
|
||||
|
||||
fn wifi_connect_route(
|
||||
@@ -383,11 +401,14 @@ fn wifi_ap_start_route(
|
||||
tx: mpsc::Sender<Envelope>,
|
||||
state: Arc<HttpState>,
|
||||
) -> impl Filter<Extract = impl Reply, Error = warp::Rejection> + Clone {
|
||||
let tx_for_hotspot = tx.clone();
|
||||
let state_for_hotspot = Arc::clone(&state);
|
||||
|
||||
warp::path!("api" / "wifi" / "ap" / "start")
|
||||
.and(warp::post())
|
||||
.and(warp::body::bytes())
|
||||
.and(with_tx(tx))
|
||||
.and(with_state(state))
|
||||
.and(with_state(Arc::clone(&state)))
|
||||
.and_then(|body: bytes::Bytes, tx, state| async move {
|
||||
let req: WifiApStartRequest = match parse_optional_json(&body) {
|
||||
Ok(req) => req,
|
||||
@@ -404,22 +425,60 @@ fn wifi_ap_start_route(
|
||||
)
|
||||
.await
|
||||
})
|
||||
.or(
|
||||
warp::path!("api" / "wifi" / "hotspot" / "start")
|
||||
.and(warp::post())
|
||||
.and(warp::body::bytes())
|
||||
.and(with_tx(tx_for_hotspot))
|
||||
.and(with_state(state_for_hotspot))
|
||||
.and_then(|body: bytes::Bytes, tx, state| async move {
|
||||
let req: WifiApStartRequest = match parse_optional_json(&body) {
|
||||
Ok(req) => req,
|
||||
Err(reply) => return Ok::<_, Infallible>(*reply),
|
||||
};
|
||||
let ssid = req.ssid.unwrap_or_else(|| "showen".to_string());
|
||||
let password = req.password.unwrap_or_else(|| "12345678".to_string());
|
||||
let success_ssid = ssid.clone();
|
||||
wifi_action_reply(
|
||||
tx,
|
||||
state,
|
||||
WifiCommand::ApStart { ssid, password },
|
||||
move |_| format!("AP 热点已启动: SSID={success_ssid}"),
|
||||
)
|
||||
.await
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn wifi_ap_stop_route(
|
||||
tx: mpsc::Sender<Envelope>,
|
||||
state: Arc<HttpState>,
|
||||
) -> impl Filter<Extract = impl Reply, Error = warp::Rejection> + Clone {
|
||||
let tx_for_hotspot = tx.clone();
|
||||
let state_for_hotspot = Arc::clone(&state);
|
||||
|
||||
warp::path!("api" / "wifi" / "ap" / "stop")
|
||||
.and(warp::post())
|
||||
.and(with_tx(tx))
|
||||
.and(with_state(state))
|
||||
.and(with_state(Arc::clone(&state)))
|
||||
.and_then(|tx, state| async move {
|
||||
wifi_action_reply(tx, state, WifiCommand::ApStop, |_| {
|
||||
"AP 热点已关闭".to_string()
|
||||
})
|
||||
.await
|
||||
})
|
||||
.or(
|
||||
warp::path!("api" / "wifi" / "hotspot" / "stop")
|
||||
.and(warp::post())
|
||||
.and(with_tx(tx_for_hotspot))
|
||||
.and(with_state(state_for_hotspot))
|
||||
.and_then(|tx, state| async move {
|
||||
wifi_action_reply(tx, state, WifiCommand::ApStop, |_| {
|
||||
"AP 热点已关闭".to_string()
|
||||
})
|
||||
.await
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn ble_start_route(
|
||||
@@ -784,6 +843,7 @@ async fn wifi_request(
|
||||
|
||||
async fn websocket_session(ws: warp::ws::WebSocket, state: Arc<HttpState>) {
|
||||
let (mut sender, mut receiver) = ws.split();
|
||||
let mut events = state.ws_subscribe();
|
||||
|
||||
for payload in state.ws_snapshots() {
|
||||
if sender.send(warp::ws::Message::text(payload)).await.is_err() {
|
||||
@@ -791,8 +851,6 @@ async fn websocket_session(ws: warp::ws::WebSocket, state: Arc<HttpState>) {
|
||||
}
|
||||
}
|
||||
|
||||
let mut events = state.ws_subscribe();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
event = events.recv() => {
|
||||
|
||||
Reference in New Issue
Block a user