edgehog_device_runtime/telemetry/
event.rs1use std::time::Duration;
22
23use astarte_device_sdk::{
24 event::FromEventError, types::TypeError, AstarteData, DeviceEvent, FromEvent,
25};
26use tracing::warn;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct TelemetryEvent {
30 pub interface: String,
31 pub config: TelemetryConfig,
32}
33
34impl FromEvent for TelemetryEvent {
35 type Err = FromEventError;
36
37 fn from_event(event: DeviceEvent) -> Result<Self, Self::Err> {
38 let interface = TelemetryConfig::interface_from_path(&event.path).ok_or_else(|| {
39 FromEventError::Path {
40 interface: "io.edgehog.devicemanager.config.Telemetry",
41 base_path: event.path.clone(),
42 }
43 })?;
44
45 TelemetryConfig::from_event(event).map(|config| TelemetryEvent { interface, config })
46 }
47}
48
49#[derive(Debug, Clone, FromEvent, PartialEq, Eq)]
50#[from_event(
51 interface = "io.edgehog.devicemanager.config.Telemetry",
52 interface_type = "properties",
53 aggregation = "individual"
54)]
55pub enum TelemetryConfig {
56 #[mapping(endpoint = "/request/%{interface_name}/enable", allow_unset = true)]
57 Enable(Option<bool>),
58 #[mapping(
59 endpoint = "/request/%{interface_name}/periodSeconds",
60 allow_unset = true
61 )]
62 Period(Option<TelemetryPeriod>),
63}
64
65impl TelemetryConfig {
66 fn interface_from_path(path: &str) -> Option<String> {
67 path.strip_prefix('/')
68 .and_then(|path| path.split('/').nth(1))
69 .map(str::to_string)
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct TelemetryPeriod(pub Duration);
75
76impl TryFrom<AstarteData> for TelemetryPeriod {
77 type Error = TypeError;
78
79 fn try_from(value: AstarteData) -> Result<Self, Self::Error> {
80 let secs = i64::try_from(value)?;
81 let secs = u64::try_from(secs).unwrap_or_else(|_| {
82 warn!("Telemetry period seconds value too big {secs}, capping to u64::MAX");
83
84 u64::MAX
85 });
86
87 Ok(Self(Duration::from_secs(secs)))
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use astarte_device_sdk::Value;
94
95 use crate::controller::event::RuntimeEvent;
96
97 use super::*;
98
99 #[test]
100 fn should_convert_telemetry_from_event() {
101 let event = DeviceEvent {
102 interface: "io.edgehog.devicemanager.config.Telemetry".to_string(),
103 path: "/request/foo/enable".to_string(),
104 data: Value::Property(Some(true.into())),
105 };
106
107 let res = RuntimeEvent::from_event(event).unwrap();
108
109 assert_eq!(
110 res,
111 RuntimeEvent::Telemetry(TelemetryEvent {
112 interface: "foo".to_string(),
113 config: TelemetryConfig::Enable(Some(true))
114 })
115 );
116
117 let event = DeviceEvent {
118 interface: "io.edgehog.devicemanager.config.Telemetry".to_string(),
119 path: "/request/foo/periodSeconds".to_string(),
120 data: Value::Property(Some(AstarteData::LongInteger(42))),
121 };
122
123 let res = RuntimeEvent::from_event(event).unwrap();
124
125 assert_eq!(
126 res,
127 RuntimeEvent::Telemetry(TelemetryEvent {
128 interface: "foo".to_string(),
129 config: TelemetryConfig::Period(Some(TelemetryPeriod(Duration::from_secs(42))))
130 })
131 );
132 }
133}