dvrip_rs/commands/
alarm.rs1use crate::error::Result;
2use async_trait::async_trait;
3use serde_json::Value;
4
5use crate::constants::{OK_CODES, QCODES};
6use crate::dvrip::DVRIPCam;
7use std::sync::atomic::Ordering;
8
9pub type AlarmCallback = Box<dyn Fn(Value, u32) + Send + Sync>;
10
11#[async_trait]
12pub trait Alarm: Send + Sync {
13 fn set_alarm_callback(&mut self, callback: Option<AlarmCallback>);
15
16 fn clear_alarm_callback(&mut self);
18
19 async fn start_alarm_monitoring(&mut self) -> Result<()>;
21
22 async fn stop_alarm_monitoring(&mut self) -> Result<()>;
24
25 async fn set_remote_alarm(&mut self, state: bool) -> Result<bool>;
27
28 fn is_alarm_monitoring(&self) -> bool;
30}
31
32#[async_trait]
33impl Alarm for DVRIPCam {
34 fn set_alarm_callback(&mut self, callback: Option<AlarmCallback>) {
35 let alarm_cb = self.alarm_callback.clone();
36 if let Ok(handle) = tokio::runtime::Handle::try_current() {
37 handle.spawn(async move {
38 *alarm_cb.lock().await = callback;
39 });
40 } else {
41 tokio::spawn(async move {
43 *alarm_cb.lock().await = callback;
44 });
45 }
46 }
47
48 fn clear_alarm_callback(&mut self) {
49 let alarm_cb = self.alarm_callback.clone();
50 if let Ok(handle) = tokio::runtime::Handle::try_current() {
51 handle.spawn(async move {
52 *alarm_cb.lock().await = None;
53 });
54 } else {
55 tokio::spawn(async move {
56 *alarm_cb.lock().await = None;
57 });
58 }
59 }
60
61 async fn start_alarm_monitoring(&mut self) -> Result<()> {
62 let reply = self
63 .get_command(
64 "",
65 Some(QCODES.get("AlarmSet").copied().unwrap_or(1500) as u32),
66 )
67 .await?;
68
69 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64())
70 && !OK_CODES.contains(&(ret as u32))
71 {
72 return Err(crate::error::DVRIPError::ProtocolError(
73 "Failed to start alarm monitoring".to_string(),
74 ));
75 }
76
77 self.alarm_monitoring.store(true, Ordering::Release);
78 self.start_alarm_worker().await;
79
80 Ok(())
81 }
82
83 async fn stop_alarm_monitoring(&mut self) -> Result<()> {
84 self.alarm_monitoring.store(false, Ordering::Release);
85
86 if let Some(handle) = self.alarm_handle.lock().await.take() {
87 handle.abort();
88 }
89
90 Ok(())
91 }
92
93 async fn set_remote_alarm(&mut self, state: bool) -> Result<bool> {
94 let data = serde_json::json!({
95 "Event": 0,
96 "State": state,
97 });
98
99 let reply = self.set_command("OPNetAlarm", data, None).await?;
100 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
101 return Ok(OK_CODES.contains(&(ret as u32)));
102 }
103 Ok(false)
104 }
105
106 fn is_alarm_monitoring(&self) -> bool {
107 self.alarm_monitoring.load(Ordering::Acquire)
108 }
109}