unifly_api/convert/
event.rs1use chrono::Utc;
2
3use crate::model::common::DataSource;
4use crate::model::entity_id::{EntityId, MacAddress};
5use crate::model::event::{Alarm, Event, EventCategory, EventSeverity};
6use crate::session::models::{SessionAlarm, SessionEvent};
7use crate::websocket::UnifiEvent;
8
9use super::helpers::{parse_datetime, resolve_event_templates};
10
11fn map_event_category(subsystem: Option<&String>) -> EventCategory {
12 match subsystem.map(String::as_str) {
13 Some("wlan" | "lan" | "wan") => EventCategory::Network,
14 Some("device") => EventCategory::Device,
15 Some("client") => EventCategory::Client,
16 Some("system") => EventCategory::System,
17 Some("admin") => EventCategory::Admin,
18 Some("firewall") => EventCategory::Firewall,
19 Some("vpn") => EventCategory::Vpn,
20 _ => EventCategory::Unknown,
21 }
22}
23
24impl From<SessionEvent> for Event {
25 fn from(e: SessionEvent) -> Self {
26 Event {
27 id: Some(EntityId::from(e.id)),
28 timestamp: parse_datetime(e.datetime.as_ref()).unwrap_or_else(Utc::now),
29 category: map_event_category(e.subsystem.as_ref()),
30 severity: EventSeverity::Info,
31 event_type: e.key.clone().unwrap_or_default(),
32 message: resolve_event_templates(
33 &e.msg.unwrap_or_default(),
34 &serde_json::Value::Object(e.extra),
35 ),
36 device_mac: None,
37 client_mac: None,
38 site_id: e.site_id.map(EntityId::from),
39 raw_key: e.key,
40 source: DataSource::SessionApi,
41 }
42 }
43}
44
45impl From<SessionAlarm> for Event {
48 fn from(a: SessionAlarm) -> Self {
49 Event {
50 id: Some(EntityId::from(a.id)),
51 timestamp: parse_datetime(a.datetime.as_ref()).unwrap_or_else(Utc::now),
52 category: EventCategory::System,
53 severity: EventSeverity::Warning,
54 event_type: a.key.clone().unwrap_or_default(),
55 message: a.msg.unwrap_or_default(),
56 device_mac: None,
57 client_mac: None,
58 site_id: None,
59 raw_key: a.key,
60 source: DataSource::SessionApi,
61 }
62 }
63}
64
65impl From<SessionAlarm> for Alarm {
66 fn from(a: SessionAlarm) -> Self {
67 Alarm {
68 id: EntityId::from(a.id),
69 timestamp: parse_datetime(a.datetime.as_ref()).unwrap_or_else(Utc::now),
70 category: EventCategory::System,
71 severity: EventSeverity::Warning,
72 message: a.msg.unwrap_or_default(),
73 archived: a.archived.unwrap_or(false),
74 device_mac: None,
75 site_id: None,
76 }
77 }
78}
79
80fn infer_ws_severity(key: &str) -> EventSeverity {
83 let upper = key.to_uppercase();
84 if upper.contains("ERROR") || upper.contains("FAIL") {
85 EventSeverity::Error
86 } else if upper.contains("DISCONNECT") || upper.contains("LOST") || upper.contains("DOWN") {
87 EventSeverity::Warning
88 } else {
89 EventSeverity::Info
90 }
91}
92
93impl From<UnifiEvent> for Event {
94 fn from(e: UnifiEvent) -> Self {
95 let category = map_event_category(Some(&e.subsystem));
96 let severity = infer_ws_severity(&e.key);
97
98 let device_mac = e
99 .extra
100 .get("mac")
101 .or_else(|| e.extra.get("sw"))
102 .or_else(|| e.extra.get("ap"))
103 .and_then(|v| v.as_str())
104 .map(MacAddress::new);
105
106 let client_mac = e
107 .extra
108 .get("user")
109 .or_else(|| e.extra.get("sta"))
110 .and_then(|v| v.as_str())
111 .map(MacAddress::new);
112
113 let site_id = if e.site_id.is_empty() {
114 None
115 } else {
116 Some(EntityId::Legacy(e.site_id))
117 };
118
119 Event {
120 id: None,
121 timestamp: parse_datetime(e.datetime.as_ref()).unwrap_or_else(Utc::now),
122 category,
123 severity,
124 event_type: e.key.clone(),
125 message: resolve_event_templates(&e.message.unwrap_or_default(), &e.extra),
126 device_mac,
127 client_mac,
128 site_id,
129 raw_key: Some(e.key),
130 source: DataSource::SessionApi,
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn event_category_mapping() {
141 assert_eq!(
142 map_event_category(Some(&"wlan".into())),
143 EventCategory::Network
144 );
145 assert_eq!(
146 map_event_category(Some(&"device".into())),
147 EventCategory::Device
148 );
149 assert_eq!(
150 map_event_category(Some(&"admin".into())),
151 EventCategory::Admin
152 );
153 assert_eq!(map_event_category(None), EventCategory::Unknown);
154 }
155}