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}