Skip to main content

webex_message_handler/
device_manager.rs

1//! WDM device registration, refresh, and unregistration.
2
3use crate::errors::{Result, WebexError};
4use crate::types::DeviceRegistration;
5use serde_json::json;
6use tracing::{debug, error, info};
7
8const WDM_API_BASE: &str = "https://wdm-a.wbx2.com/wdm/api/v1/devices";
9
10fn device_body() -> serde_json::Value {
11    json!({
12        "deviceName": "webex-message-handler",
13        "deviceType": "DESKTOP",
14        "localizedModel": "rust",
15        "model": "rust",
16        "name": "webex-message-handler",
17        "systemName": "webex-message-handler",
18        "systemVersion": "1.0.0"
19    })
20}
21
22/// Manages WDM device registration lifecycle.
23pub struct DeviceManager {
24    device_url: Option<String>,
25    client: reqwest::Client,
26}
27
28impl DeviceManager {
29    pub fn new(client: reqwest::Client) -> Self {
30        Self {
31            device_url: None,
32            client,
33        }
34    }
35
36    /// Register a new device with WDM.
37    pub async fn register(&mut self, token: &str) -> Result<DeviceRegistration> {
38        debug!("Registering device with WDM");
39
40        let response = self
41            .client
42            .post(WDM_API_BASE)
43            .header("Authorization", format!("Bearer {}", token))
44            .header("Content-Type", "application/json")
45            .json(&device_body())
46            .send()
47            .await
48            .map_err(|e| WebexError::device_registration(format!("Failed to register device: {e}"), None))?;
49
50        let status = response.status().as_u16();
51
52        if status == 401 {
53            error!("Device registration failed: Unauthorized");
54            return Err(WebexError::auth("Unauthorized to register device"));
55        }
56
57        if !response.status().is_success() {
58            error!("Device registration failed with status {status}");
59            return Err(WebexError::device_registration("Failed to register device", Some(status)));
60        }
61
62        let mut reg: DeviceRegistration = response
63            .json()
64            .await
65            .map_err(|e| WebexError::device_registration(format!("Failed to parse response: {e}"), None))?;
66
67        reg.encryption_service_url = reg.services.get("encryptionServiceUrl").cloned().unwrap_or_default();
68        self.device_url = Some(reg.device_url.clone());
69
70        info!("Device registered successfully");
71        Ok(reg)
72    }
73
74    /// Refresh an existing device registration.
75    pub async fn refresh(&self, token: &str) -> Result<DeviceRegistration> {
76        let device_url = self.device_url.as_deref().ok_or_else(|| {
77            WebexError::device_registration("Device not registered. Call register() first.", None)
78        })?;
79
80        debug!("Refreshing device registration");
81
82        let response = self
83            .client
84            .put(device_url)
85            .header("Authorization", format!("Bearer {}", token))
86            .header("Content-Type", "application/json")
87            .json(&device_body())
88            .send()
89            .await
90            .map_err(|e| WebexError::device_registration(format!("Failed to refresh device: {e}"), None))?;
91
92        let status = response.status().as_u16();
93
94        if status == 401 {
95            error!("Device refresh failed: Unauthorized");
96            return Err(WebexError::auth("Unauthorized to refresh device"));
97        }
98
99        if !response.status().is_success() {
100            error!("Device refresh failed with status {status}");
101            return Err(WebexError::device_registration("Failed to refresh device", Some(status)));
102        }
103
104        let mut reg: DeviceRegistration = response
105            .json()
106            .await
107            .map_err(|e| WebexError::device_registration(format!("Failed to parse response: {e}"), None))?;
108
109        reg.encryption_service_url = reg.services.get("encryptionServiceUrl").cloned().unwrap_or_default();
110
111        info!("Device refreshed successfully");
112        Ok(reg)
113    }
114
115    /// Unregister the device from WDM.
116    pub async fn unregister(&mut self, token: &str) -> Result<()> {
117        let device_url = self.device_url.as_deref().ok_or_else(|| {
118            WebexError::device_registration("Device not registered. Call register() first.", None)
119        })?;
120
121        debug!("Unregistering device");
122
123        let response = self
124            .client
125            .delete(device_url)
126            .header("Authorization", format!("Bearer {}", token))
127            .header("Content-Type", "application/json")
128            .send()
129            .await
130            .map_err(|e| WebexError::device_registration(format!("Failed to unregister device: {e}"), None))?;
131
132        let status = response.status().as_u16();
133
134        if status == 401 {
135            error!("Device unregistration failed: Unauthorized");
136            return Err(WebexError::auth("Unauthorized to unregister device"));
137        }
138
139        if !response.status().is_success() && status != 404 {
140            error!("Device unregistration failed with status {status}");
141            return Err(WebexError::device_registration("Failed to unregister device", Some(status)));
142        }
143
144        self.device_url = None;
145        info!("Device unregistered successfully");
146        Ok(())
147    }
148}