telemetrydeck_wasm/
client_native.rs

1use crate::core::{Signal, TelemetryDeck};
2use std::collections::HashMap;
3
4impl TelemetryDeck {
5    /// Send a telemetry signal (fire-and-forget)
6    ///
7    /// This method spawns an async task using `tokio::spawn` and never returns errors.
8    /// The signal is sent in the background without blocking. Use [`send_sync`](Self::send_sync)
9    /// if you need error handling.
10    ///
11    /// # Parameters
12    ///
13    /// * `signal_type` - The type/name of the signal (e.g., "userLogin", "buttonClick")
14    /// * `client_user` - Optional user identifier. Will be SHA-256 hashed automatically.
15    ///   If `None`, defaults to "rust".
16    /// * `payload` - Optional key-value parameters to attach to the signal
17    /// * `is_test_mode` - Whether to mark this as a test signal. Defaults to `false` if `None`.
18    /// * `float_value` - Optional floating-point value (useful for metrics like revenue, duration, etc.)
19    ///
20    /// # Examples
21    ///
22    /// ```no_run
23    /// use telemetrydeck_wasm::TelemetryDeck;
24    ///
25    /// let client = TelemetryDeck::new("YOUR-APP-ID");
26    ///
27    /// // Simple signal
28    /// client.send("buttonClick", None, None, None, None);
29    ///
30    /// // With user
31    /// client.send("userLogin", Some("user@example.com"), None, None, None);
32    ///
33    /// // With float value for revenue tracking
34    /// client.send("purchase", Some("user123"), None, None, Some(49.99));
35    /// ```
36    ///
37    /// ```no_run
38    /// use telemetrydeck_wasm::TelemetryDeck;
39    /// use std::collections::HashMap;
40    ///
41    /// let client = TelemetryDeck::new("YOUR-APP-ID");
42    ///
43    /// let mut params = HashMap::new();
44    /// params.insert("screen".to_string(), "settings".to_string());
45    /// params.insert("action".to_string(), "toggle".to_string());
46    ///
47    /// client.send("userAction", Some("user"), Some(params), None, None);
48    /// ```
49    ///
50    /// # Platform Note
51    ///
52    /// On native platforms, this requires a tokio runtime to be running.
53    pub fn send(
54        &self,
55        signal_type: &str,
56        client_user: Option<&str>,
57        payload: Option<HashMap<String, String>>,
58        is_test_mode: Option<bool>,
59        float_value: Option<f64>,
60    ) {
61        let signal =
62            self.create_signal(signal_type, client_user, payload, is_test_mode, float_value);
63        self.send_one(signal);
64    }
65
66    /// Send a telemetry signal and return errors if any occur
67    ///
68    /// This method waits for the HTTP request to complete and returns a `Result`.
69    /// Use this when you need to know if the signal was sent successfully.
70    ///
71    /// # Parameters
72    ///
73    /// * `signal_type` - The type/name of the signal (e.g., "userLogin", "buttonClick")
74    /// * `client_user` - Optional user identifier. Will be SHA-256 hashed automatically.
75    ///   If `None`, defaults to "rust".
76    /// * `payload` - Optional key-value parameters to attach to the signal
77    /// * `is_test_mode` - Whether to mark this as a test signal. Defaults to `false` if `None`.
78    /// * `float_value` - Optional floating-point value (useful for metrics like revenue, duration, etc.)
79    ///
80    /// # Returns
81    ///
82    /// * `Ok(())` if the signal was sent successfully (HTTP 2xx status)
83    /// * `Err(...)` if sending failed (network error, HTTP error, serialization error, etc.)
84    ///
85    /// # Examples
86    ///
87    /// ```no_run
88    /// use telemetrydeck_wasm::TelemetryDeck;
89    ///
90    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
91    /// let client = TelemetryDeck::new("YOUR-APP-ID");
92    ///
93    /// // Handle errors explicitly
94    /// match client.send_sync("criticalEvent", Some("user"), None, None, None).await {
95    ///     Ok(()) => println!("Signal sent successfully"),
96    ///     Err(e) => eprintln!("Failed to send: {}", e),
97    /// }
98    ///
99    /// // Or use ? operator
100    /// client.send_sync("anotherEvent", None, None, None, None).await?;
101    /// # Ok(())
102    /// # }
103    /// ```
104    pub async fn send_sync(
105        &self,
106        signal_type: &str,
107        client_user: Option<&str>,
108        payload: Option<HashMap<String, String>>,
109        is_test_mode: Option<bool>,
110        float_value: Option<f64>,
111    ) -> Result<(), Box<dyn std::error::Error>> {
112        let signal =
113            self.create_signal(signal_type, client_user, payload, is_test_mode, float_value);
114        self.send_many_sync(vec![signal]).await
115    }
116
117    fn send_one(&self, signal: Signal) {
118        self.send_many(vec![signal])
119    }
120
121    fn send_many(&self, signals: Vec<Signal>) {
122        let url = self.build_url();
123        tokio::spawn(async move {
124            let client = reqwest::Client::new();
125            let body = serde_json::to_string(&signals).unwrap();
126            let _resp = client
127                .post(&url)
128                .body(body)
129                .header("Content-Type", "application/json")
130                .send()
131                .await;
132        });
133    }
134
135    async fn send_many_sync(&self, signals: Vec<Signal>) -> Result<(), Box<dyn std::error::Error>> {
136        let url = self.build_url();
137        let client = reqwest::Client::new();
138        let body = serde_json::to_string(&signals)?;
139        let resp = client
140            .post(&url)
141            .body(body)
142            .header("Content-Type", "application/json")
143            .send()
144            .await?;
145
146        if resp.status().is_success() {
147            Ok(())
148        } else {
149            Err(format!("HTTP error: {}", resp.status()).into())
150        }
151    }
152}