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 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 let os = OS.to_string();
47
48 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}