Skip to main content

heldar_kernel/services/camera_config/
mod.rs

1//! Camera configuration (HikVision ISAPI) service.
2//!
3//! Wire/response types ([`types`]) and the hand-rolled RFC 2617 HTTP Digest auth ([`digest`]) the
4//! ISAPI calls require, the vendor-agnostic [`CameraConfigProvider`] trait, and its HikVision ISAPI
5//! implementation ([`hikvision`]). Construct a provider for a camera with [`for_camera`].
6
7pub mod digest;
8pub mod hikvision;
9pub mod types;
10
11use async_trait::async_trait;
12
13use crate::error::{AppError, AppResult};
14use crate::models::Camera;
15use types::{
16    DeviceInfo, NtpConfig, OnvifSettings, OnvifUserType, OsdConfig, TimeConfig, VideoConfig,
17};
18
19/// A vendor-agnostic surface for reading and writing a camera's on-device configuration. The kernel
20/// owns the persistence/audit; an implementor only talks the device's native protocol (HikVision
21/// ISAPI today). All methods are best-effort against a live device and surface [`AppError`] on
22/// transport/protocol failure.
23#[async_trait]
24pub trait CameraConfigProvider: Send + Sync {
25    /// Device identity (name/model/firmware/serial).
26    async fn get_device_info(&self) -> AppResult<DeviceInfo>;
27
28    /// Every streaming channel's video-encoding configuration (main + sub + any extras).
29    async fn list_video_configs(&self) -> AppResult<Vec<VideoConfig>>;
30
31    /// One streaming channel's video-encoding configuration (e.g. `101` main, `102` sub).
32    async fn get_video_config(&self, channel: u32) -> AppResult<VideoConfig>;
33
34    /// Write a channel's video-encoding configuration (read-modify-write of the device's XML).
35    async fn put_video_config(&self, channel: u32, cfg: &VideoConfig) -> AppResult<()>;
36
37    /// The device clock configuration (mode/local-time/timezone).
38    async fn get_time_config(&self) -> AppResult<TimeConfig>;
39
40    /// Write the device clock configuration.
41    async fn put_time_config(&self, cfg: &TimeConfig) -> AppResult<()>;
42
43    /// The configured NTP server.
44    async fn get_ntp_config(&self) -> AppResult<NtpConfig>;
45
46    /// Write the NTP server.
47    async fn put_ntp_config(&self, cfg: &NtpConfig) -> AppResult<()>;
48
49    /// Switch the clock to NTP if it is currently in manual mode; returns the resulting clock config.
50    async fn sync_time_now(&self) -> AppResult<TimeConfig>;
51
52    /// The ONVIF/ISAPI integration toggles.
53    async fn get_onvif_settings(&self) -> AppResult<OnvifSettings>;
54
55    /// Write the ONVIF/ISAPI integration toggles.
56    async fn put_onvif_settings(&self, cfg: &OnvifSettings) -> AppResult<()>;
57
58    /// Ensure a dedicated ONVIF user exists (create-if-absent; a duplicate create is treated as Ok).
59    async fn ensure_onvif_user(
60        &self,
61        username: &str,
62        password: &str,
63        user_type: OnvifUserType,
64    ) -> AppResult<()>;
65
66    /// The on-screen-display (timestamp / channel-name) overlay configuration.
67    async fn get_osd_config(&self) -> AppResult<OsdConfig>;
68
69    /// Write the on-screen-display overlay configuration.
70    async fn put_osd_config(&self, cfg: &OsdConfig) -> AppResult<()>;
71
72    /// Reboot the device (DISRUPTIVE).
73    async fn reboot(&self) -> AppResult<()>;
74}
75
76/// Build a [`CameraConfigProvider`] for `cam`, dispatching on its vendor. Only HikVision (ISAPI) is
77/// supported today; ONVIF-generic configuration is a future implementation.
78pub fn for_camera(
79    cam: &Camera,
80    http: &reqwest::Client,
81    timeout_ms: u64,
82) -> AppResult<Box<dyn CameraConfigProvider>> {
83    match cam.vendor.as_str() {
84        "hikvision" => Ok(Box::new(hikvision::HikVisionIsapiClient::for_camera(
85            cam, http, timeout_ms,
86        )?)),
87        _ => Err(AppError::BadRequest(
88            "camera config only supported for hikvision; ONVIF-generic is a future impl".into(),
89        )),
90    }
91}