Files
SCOPENET-MC/launcher/src-tauri/src/telemetry.rs
T

73 lines
2.1 KiB
Rust

//! Account-attributed activity only; no passwords, game logs, chat, or local paths.
use crate::{accounts, state::AppState};
use scopenet_shared::LaunchEvent;
use std::time::Duration;
/// Capture the identity when work starts, so switching accounts cannot
/// attribute a running game's exit to the newly selected player.
#[derive(Clone)]
pub struct Recorder {
http: reqwest::Client,
panel: String,
token: Option<String>,
username: Option<String>,
}
pub fn capture(state: &AppState) -> Option<Recorder> {
let panel = state.panel_url()?;
let accounts = state.accounts.read().unwrap();
let active = accounts.active()?;
let token = accounts::panel_token(state);
Some(Recorder {
http: state.http.clone(),
panel,
token,
username: Some(active.username.clone()),
})
}
impl Recorder {
pub async fn send(&self, kind: &str, instance: &str) -> anyhow::Result<()> {
let mut req = self
.http
.post(format!("{}/api/v1/launcher/events", self.panel))
.timeout(Duration::from_secs(5));
if let Some(token) = &self.token {
req = req.bearer_auth(token);
}
req.json(&LaunchEvent {
kind: kind.into(),
instance_id: instance.into(),
username: self.username.clone(),
})
.send()
.await?
.error_for_status()?;
Ok(())
}
pub fn background(&self, kind: &str, instance: &str) {
let recorder = self.clone();
let kind = kind.to_owned();
let instance = instance.to_owned();
tauri::async_runtime::spawn(async move {
if let Err(e) = recorder.send(&kind, &instance).await {
tracing::warn!("activity report failed: {e}");
}
});
}
}
pub async fn send(state: &AppState, kind: &str, instance: &str) -> anyhow::Result<()> {
if let Some(recorder) = capture(state) {
recorder.send(kind, instance).await?;
}
Ok(())
}
pub fn background(state: &AppState, kind: &str, instance: &str) {
if let Some(recorder) = capture(state) {
recorder.background(kind, instance);
}
}