Complete private authentication, server integrations and activity reporting

Add Fabric/Forge version builds and Paper integration, preserve permanent player identities across renames, harden session authorization, and surface privacy-conscious launcher/server activity in the panel.
This commit is contained in:
SCOPEDD committed 2026-09-28 13:31:17 -04:00
commit a1f19e86c6
74 files changed
+2108 -95

No files matched your search

+23 -14
View File
@@ -7,7 +7,7 @@ use scopenet_core::install::{self, InstallSpec};
use scopenet_core::launch::{self, LaunchOptions};
use scopenet_core::progress::{Event, Reporter, Stage};
use scopenet_core::{options, servers_dat, sync};
use scopenet_shared::{InstanceManifest, LaunchEvent};
use scopenet_shared::InstanceManifest;
use serde::Serialize;
use std::collections::VecDeque;
use std::path::PathBuf;
@@ -79,6 +79,10 @@ fn reporter(app: &AppHandle) -> Reporter {
pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -> Result<()> {
let state = app.state::<AppState>();
let report = reporter(&app);
let activity = crate::telemetry::capture(&state);
if let Some(recorder) = &activity {
recorder.background(if deep { "repair_start" } else { "install_start" }, &instance_id);
}
emit_state(&app, &instance_id, "preparing", None);
let account = state.accounts.read().unwrap().active().cloned();
@@ -127,6 +131,9 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
options::apply_keybinds(&game_dir, &settings.keybinds).ok();
}
if let Some(recorder) = &activity {
recorder.background(if deep { "repair_complete" } else { "install_complete" }, &instance_id);
}
if !start {
emit_state(&app, &instance_id, "idle", Some("Instance is up to date".into()));
return Ok(());
@@ -183,20 +190,11 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
tracing::info!("launching: {} {}", cmd.java.display(), launch::redact(&cmd.args, &auth.access_token).join(" "));
let close_after = settings.after_launch == "close";
let mut child = launch::spawn(&cmd, installed.java_major, !close_after).context("couldn't start Java")?;
if settings.send_stats && !panel.is_empty() {
let http = state.http.clone();
let token = accounts::panel_token(&state);
let ev = LaunchEvent { instance_id: instance_id.clone(), kind: "launch".into(), username: Some(auth.username.clone()) };
tokio::spawn(async move {
let mut req = http.post(format!("{panel}/api/v1/launcher/events")).json(&ev);
if let Some(t) = token {
req = req.bearer_auth(t);
}
req.send().await.ok();
});
// Register the authenticated launch before Quick Play can reach the server.
if let Some(recorder) = &activity {
recorder.send("launch", &instance_id).await?;
}
let mut child = launch::spawn(&cmd, installed.java_major, !close_after).context("couldn't start Java")?;
if close_after {
tokio::time::sleep(Duration::from_millis(1500)).await;
@@ -288,6 +286,17 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
let crashed = !killed && code.is_some_and(|c| c != 0);
let crash_report = if crashed { newest_crash_report(&app2, &id2) } else { None };
let st = app2.state::<AppState>();
crate::telemetry::background(
&st,
if killed {
"game_killed"
} else if crashed {
"game_crash"
} else {
"game_exit"
},
&id2,
);
*st.game.lock().unwrap() = None;
if let Some(w) = app2.get_webview_window("main") {
w.show().ok();