dahua_camera_server/handlers/
control.rs1use crate::AppState;
5use axum::extract::{Path, State};
6use axum::http::{header, StatusCode};
7use axum::response::IntoResponse;
8use axum::Json;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Deserialize)]
13pub struct ControlRequest {
14 pub action: String,
16 pub value: String,
18}
19
20#[derive(Debug, Clone, Serialize)]
22pub struct ControlResponse {
23 pub status: &'static str,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub output: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub message: Option<String>,
31}
32
33pub async fn control_camera(
39 State(state): State<AppState>,
40 Path(id): Path<String>,
41 Json(request): Json<ControlRequest>,
42) -> Result<Json<ControlResponse>, StatusCode> {
43 let camera = state.get(&id).ok_or(StatusCode::NOT_FOUND)?;
44 let control = camera.control();
45
46 let result = match request.action.as_str() {
47 "day_night" => control.set_day_night(&request.value).await,
48 "ir_mode" => control.set_ir_mode(&request.value).await,
49 "ptz" => control.ptz_move(&request.value).await,
50 _ => return Err(StatusCode::BAD_REQUEST),
51 };
52
53 Ok(Json(match result {
54 Ok(output) => ControlResponse { status: "ok", output: Some(output), message: None },
55 Err(e) => {
56 tracing::warn!(camera = %id, action = %request.action, error = %e, "control failed");
57 ControlResponse { status: "error", output: None, message: Some(e.to_string()) }
58 }
59 }))
60}
61
62pub async fn cgi_snapshot(
67 State(state): State<AppState>,
68 Path(id): Path<String>,
69) -> axum::response::Response {
70 let Some(camera) = state.get(&id) else {
71 return (StatusCode::NOT_FOUND, format!("no camera '{id}'")).into_response();
72 };
73
74 match camera.control().snapshot().await {
75 Ok(jpeg) => ([(header::CONTENT_TYPE, "image/jpeg")], jpeg).into_response(),
76 Err(e) => {
77 tracing::warn!(camera = %id, error = %e, "cgi snapshot failed");
78 (StatusCode::BAD_GATEWAY, e.to_string()).into_response()
79 }
80 }
81}