helix_metrics/
lib.rs

1pub mod events;
2
3use std::{env::consts::OS, fs, path::Path, sync::LazyLock};
4
5pub static METRICS_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(reqwest::Client::new);
6pub static HELIX_USER_ID: LazyLock<String> = LazyLock::new(|| {
7    // read from credentials file
8    let home_dir = std::env::var("HOME").unwrap_or("~/".to_string());
9    let config_path = &format!("{home_dir}/.helix/credentials");
10    let config_path = Path::new(config_path);
11    let user_id = match fs::read_to_string(config_path) {
12        Ok(config) => {
13            for line in config.lines() {
14                if let Some((key, value)) = line.split_once("=") {
15                    if key.to_lowercase() == "helix_user_id" {
16                        return value.to_string();
17                    }
18                }
19            }
20            "".to_string()
21        }
22        Err(_) => "".to_string(),
23    };
24    user_id
25});
26
27pub const METRICS_URL: &str = "https://logs.helix-db.com";
28
29pub struct HelixMetricsClient {}
30
31impl HelixMetricsClient {
32    pub fn new() -> Self {
33        Self {}
34    }
35
36    pub fn get_client(&self) -> &'static LazyLock<reqwest::Client> {
37        &METRICS_CLIENT
38    }
39
40    pub fn send_event(
41        &self,
42        event_type: events::EventType,
43        event_data: events::EventData,
44    ) -> Result<(), MetricError> {
45        // get OS
46        let os = OS.to_string();
47
48        // get user id
49        let user_id = Some(HELIX_USER_ID.as_str().to_string());
50
51        let _ = self
52            .get_client()
53            .post(METRICS_URL)
54            .body(sonic_rs::to_vec(&events::RawEvent {
55                ip_hash: None,
56                os,
57                user_id,
58                event_type,
59                event_data,
60            })?)
61            .send();
62        Ok(())
63    }
64}
65
66#[derive(Debug)]
67pub struct MetricError(String);
68
69impl std::fmt::Display for MetricError {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        write!(f, "{}", self.0)
72    }
73}
74
75impl std::error::Error for MetricError {}
76
77impl From<sonic_rs::Error> for MetricError {
78    fn from(e: sonic_rs::Error) -> Self {
79        MetricError(e.to_string())
80    }
81}
82
83impl From<reqwest::Error> for MetricError {
84    fn from(e: reqwest::Error) -> Self {
85        MetricError(e.to_string())
86    }
87}