feat: wire up interactive GUI and CLI subcommands to launcher, cleaner, and region router
This commit is contained in:
parent
2fcc4dd995
commit
66deae64d6
4 changed files with 127 additions and 4 deletions
|
|
@ -16,6 +16,8 @@ pub enum Commands {
|
||||||
place_id: Option<u64>,
|
place_id: Option<u64>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
safe_mode: bool,
|
safe_mode: bool,
|
||||||
|
#[arg(short, long)]
|
||||||
|
region: Option<String>,
|
||||||
},
|
},
|
||||||
/// Check for and download the latest Roblox version
|
/// Check for and download the latest Roblox version
|
||||||
Update,
|
Update,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@ pub mod commands;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use commands::{Cli, Commands};
|
use commands::{Cli, Commands};
|
||||||
use molotov_bootstrap::cdn::CdnClient;
|
use molotov_bootstrap::cdn::CdnClient;
|
||||||
|
use molotov_bootstrap::cleaner::Cleaner;
|
||||||
use molotov_bootstrap::fflags::FastFlagManager;
|
use molotov_bootstrap::fflags::FastFlagManager;
|
||||||
|
use molotov_bootstrap::launcher::{LaunchOptions, Launcher};
|
||||||
|
use molotov_bootstrap::region::ServerRegion;
|
||||||
use molotov_bootstrap::sandbox::SandboxRunner;
|
use molotov_bootstrap::sandbox::SandboxRunner;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn run(args: &[String]) {
|
pub fn run(args: &[String]) {
|
||||||
let mut full_args = vec!["molotov".to_string()];
|
let mut full_args = vec!["molotov".to_string()];
|
||||||
|
|
@ -18,12 +22,45 @@ pub fn run(args: &[String]) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
|
||||||
|
let base_dir = PathBuf::from(&home).join(".local/share/molotov");
|
||||||
|
let downloads_dir = PathBuf::from(&home).join(".cache/molotov/downloads");
|
||||||
|
let versions_dir = base_dir.join("versions");
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Some(Commands::Launch { place_id, safe_mode }) => {
|
Some(Commands::Launch { place_id, safe_mode, region }) => {
|
||||||
println!("🚀 Preparing Molotov launch (Place: {:?}, Safe Mode: {})...", place_id, safe_mode);
|
let s_region = region
|
||||||
|
.as_deref()
|
||||||
|
.map(ServerRegion::from_code)
|
||||||
|
.unwrap_or(ServerRegion::Auto);
|
||||||
|
|
||||||
|
println!("🚀 Preparing Molotov launch...");
|
||||||
|
println!(" • Target Place ID: {:?}", place_id);
|
||||||
|
println!(" • Safe Mode: {}", safe_mode);
|
||||||
|
println!(" • Preferred Server Region: {}", s_region.display_name());
|
||||||
|
|
||||||
if let Err(e) = SandboxRunner::check_bwrap_installed() {
|
if let Err(e) = SandboxRunner::check_bwrap_installed() {
|
||||||
eprintln!("⚠️ Warning: {}", e);
|
eprintln!("⚠️ Warning: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let launcher = Launcher::new(base_dir);
|
||||||
|
let options = LaunchOptions {
|
||||||
|
place_id,
|
||||||
|
safe_mode,
|
||||||
|
region: s_region,
|
||||||
|
instance_id: "default".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match launcher.prepare_launch(options) {
|
||||||
|
Ok(plan) => {
|
||||||
|
println!("✅ Launch plan prepared successfully.");
|
||||||
|
println!(" • FastFlags configured at: {}", plan.fflags_path.display());
|
||||||
|
println!(" • Sandbox isolation: Instance '{}'", plan.sandbox_config.instance_id);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("❌ Failed to prepare launch plan: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(Commands::Update) => {
|
Some(Commands::Update) => {
|
||||||
println!("🔄 Checking Roblox CDN for client updates...");
|
println!("🔄 Checking Roblox CDN for client updates...");
|
||||||
|
|
@ -62,6 +99,18 @@ pub fn run(args: &[String]) {
|
||||||
}
|
}
|
||||||
Some(Commands::Clean) => {
|
Some(Commands::Clean) => {
|
||||||
println!("🧹 Cleaning old versions and temporary cache...");
|
println!("🧹 Cleaning old versions and temporary cache...");
|
||||||
|
let cleaner = Cleaner::new(versions_dir, downloads_dir);
|
||||||
|
match cleaner.clean_stale_data("active") {
|
||||||
|
Ok(report) => {
|
||||||
|
println!("✅ Cleaning complete:");
|
||||||
|
println!(" • Purged old version directories: {}", report.purged_versions.len());
|
||||||
|
println!(" • Purged leftover download fragments: {}", report.purged_parts_count);
|
||||||
|
println!(" • Total disk space reclaimed: {:.2} MB", (report.reclaimed_bytes as f64) / (1024.0 * 1024.0));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("❌ Cleaning failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(Commands::Diagnostics) => {
|
Some(Commands::Diagnostics) => {
|
||||||
println!("🩺 System diagnostics: checking bubblewrap sandbox status...");
|
println!("🩺 System diagnostics: checking bubblewrap sandbox status...");
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ fn test_cli_parse_launch_place() {
|
||||||
assert!(parsed.is_ok());
|
assert!(parsed.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cli_parse_region_flag() {
|
||||||
|
let parsed = Cli::try_parse_from(["molotov", "launch", "--region", "eu"]);
|
||||||
|
assert!(parsed.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cli_parse_clean_command() {
|
fn test_cli_parse_clean_command() {
|
||||||
let parsed = Cli::try_parse_from(["molotov", "clean"]);
|
let parsed = Cli::try_parse_from(["molotov", "clean"]);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
use molotov_bootstrap::cleaner::Cleaner;
|
||||||
|
use molotov_bootstrap::launcher::{LaunchOptions, Launcher};
|
||||||
|
use molotov_bootstrap::region::ServerRegion;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Tab {
|
pub enum Tab {
|
||||||
|
|
@ -16,6 +20,9 @@ pub struct MolotovApp {
|
||||||
pub safe_mode: bool,
|
pub safe_mode: bool,
|
||||||
pub fps_cap: i64,
|
pub fps_cap: i64,
|
||||||
pub vram_skip_mips: bool,
|
pub vram_skip_mips: bool,
|
||||||
|
pub region: ServerRegion,
|
||||||
|
pub discord_rpc: bool,
|
||||||
|
pub status_message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MolotovApp {
|
impl Default for MolotovApp {
|
||||||
|
|
@ -25,6 +32,9 @@ impl Default for MolotovApp {
|
||||||
safe_mode: false,
|
safe_mode: false,
|
||||||
fps_cap: 144,
|
fps_cap: 144,
|
||||||
vram_skip_mips: false,
|
vram_skip_mips: false,
|
||||||
|
region: ServerRegion::Auto,
|
||||||
|
discord_rpc: true,
|
||||||
|
status_message: "Ready to launch".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +50,14 @@ impl MolotovApp {
|
||||||
Tab::Maintenance => "Maintenance",
|
Tab::Maintenance => "Maintenance",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_paths() -> (PathBuf, PathBuf, PathBuf) {
|
||||||
|
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
|
||||||
|
let base_dir = PathBuf::from(&home).join(".local/share/molotov");
|
||||||
|
let downloads_dir = PathBuf::from(&home).join(".cache/molotov/downloads");
|
||||||
|
let versions_dir = base_dir.join("versions");
|
||||||
|
(base_dir, downloads_dir, versions_dir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for MolotovApp {
|
impl eframe::App for MolotovApp {
|
||||||
|
|
@ -58,9 +76,44 @@ impl eframe::App for MolotovApp {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| match self.current_tab {
|
egui::CentralPanel::default().show(ctx, |ui| match self.current_tab {
|
||||||
Tab::Play => {
|
Tab::Play => {
|
||||||
ui.heading("Molotov Roblox Runtime");
|
ui.heading("Molotov Roblox Runtime");
|
||||||
|
ui.label(format!("Status: {}", self.status_message));
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
ui.checkbox(&mut self.safe_mode, "Safe Mode (Minimal Flags)");
|
ui.checkbox(&mut self.safe_mode, "Safe Mode (Minimal Flags)");
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Preferred Server Region:");
|
||||||
|
egui::ComboBox::from_id_salt("region_combo")
|
||||||
|
.selected_text(self.region.display_name())
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::Auto, "Auto / Default");
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::USEast, "US East (Virginia)");
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::USWest, "US West (California)");
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::Europe, "Europe (Frankfurt / London)");
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::Asia, "Asia (Tokyo / Singapore)");
|
||||||
|
ui.selectable_value(&mut self.region, ServerRegion::Australia, "Australia (Sydney)");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.add_space(10.0);
|
||||||
if ui.button("🚀 Launch Roblox").clicked() {
|
if ui.button("🚀 Launch Roblox").clicked() {
|
||||||
println!("Launch clicked!");
|
let (base_dir, _, _) = Self::get_paths();
|
||||||
|
let launcher = Launcher::new(base_dir);
|
||||||
|
let options = LaunchOptions {
|
||||||
|
place_id: None,
|
||||||
|
safe_mode: self.safe_mode,
|
||||||
|
region: self.region,
|
||||||
|
instance_id: "default".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match launcher.prepare_launch(options) {
|
||||||
|
Ok(plan) => {
|
||||||
|
self.status_message = format!("Launch plan prepared! Safe Mode: {}", plan.is_safe_mode);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
self.status_message = format!("Launch preparation failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tab::FastFlags => {
|
Tab::FastFlags => {
|
||||||
|
|
@ -82,8 +135,21 @@ impl eframe::App for MolotovApp {
|
||||||
}
|
}
|
||||||
Tab::Maintenance => {
|
Tab::Maintenance => {
|
||||||
ui.heading("Maintenance & Cleaning");
|
ui.heading("Maintenance & Cleaning");
|
||||||
|
ui.checkbox(&mut self.discord_rpc, "Enable Discord Rich Presence (RPC)");
|
||||||
|
|
||||||
|
ui.add_space(10.0);
|
||||||
if ui.button("Clean Stale Versions").clicked() {
|
if ui.button("Clean Stale Versions").clicked() {
|
||||||
println!("Clean clicked!");
|
let (_, downloads_dir, versions_dir) = Self::get_paths();
|
||||||
|
let cleaner = Cleaner::new(versions_dir, downloads_dir);
|
||||||
|
match cleaner.clean_stale_data("active") {
|
||||||
|
Ok(report) => {
|
||||||
|
let mb = (report.reclaimed_bytes as f64) / (1024.0 * 1024.0);
|
||||||
|
self.status_message = format!("Cleaned {} old versions, reclaimed {:.2} MB", report.purged_versions.len(), mb);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
self.status_message = format!("Clean failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Reference in a new issue