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}