feat: initial OpenFUT Launcher
GUI desktop app (egui/eframe) that manages the openfut-core and openfut-bridge services with a single window. - Dashboard: start/stop each service independently or together; live status indicators; quick-status for cert and hosts - Logs: real-time stdout/stderr from both processes, colour-coded by level, follow mode and manual clear - Setup: add/remove EA hostname redirects in /etc/hosts (pkexec/sudo); install the bridge TLS cert into the system CA store - Config: all binary paths and env vars editable in-app; persisted to ~/.config/openfut-launcher/config.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LauncherConfig {
|
||||
pub core_binary: String,
|
||||
pub bridge_binary: String,
|
||||
pub core_database_url: String,
|
||||
pub core_data_dir: String,
|
||||
pub core_listen_addr: String,
|
||||
pub bridge_listen_addr: String,
|
||||
pub bridge_captures_dir: String,
|
||||
pub bridge_core_url: String,
|
||||
pub bridge_tls_enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for LauncherConfig {
|
||||
fn default() -> Self {
|
||||
let base = dirs::home_dir()
|
||||
.map(|h| h.join("Documents/OpenFUT"))
|
||||
.unwrap_or_default();
|
||||
|
||||
Self {
|
||||
core_binary: base
|
||||
.join("openfut-core/target/release/openfut-core")
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
bridge_binary: base
|
||||
.join("openfut-bridge/target/release/openfut-bridge")
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
core_database_url: "sqlite://openfut.db".into(),
|
||||
core_data_dir: base
|
||||
.join("openfut-core/data")
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
core_listen_addr: "127.0.0.1:8080".into(),
|
||||
bridge_listen_addr: "0.0.0.0:8765".into(),
|
||||
bridge_captures_dir: base
|
||||
.join("openfut-bridge/captures")
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
bridge_core_url: "http://127.0.0.1:8080".into(),
|
||||
bridge_tls_enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LauncherConfig {
|
||||
pub fn config_path() -> std::path::PathBuf {
|
||||
dirs::config_dir()
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("."))
|
||||
.join("openfut-launcher")
|
||||
.join("config.json")
|
||||
}
|
||||
|
||||
pub fn load() -> Self {
|
||||
let path = Self::config_path();
|
||||
std::fs::read_to_string(&path)
|
||||
.ok()
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
let path = Self::config_path();
|
||||
if let Some(parent) = path.parent() {
|
||||
let _ = std::fs::create_dir_all(parent);
|
||||
}
|
||||
if let Ok(json) = serde_json::to_string_pretty(self) {
|
||||
let _ = std::fs::write(path, json);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn core_env(&self) -> Vec<(String, String)> {
|
||||
vec![
|
||||
("DATABASE_URL".into(), self.core_database_url.clone()),
|
||||
("DATA_DIR".into(), self.core_data_dir.clone()),
|
||||
("LISTEN_ADDR".into(), self.core_listen_addr.clone()),
|
||||
("RUST_LOG".into(), "openfut_core=info,tower_http=info".into()),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn bridge_env(&self) -> Vec<(String, String)> {
|
||||
vec![
|
||||
("CORE_URL".into(), self.bridge_core_url.clone()),
|
||||
("LISTEN_ADDR".into(), self.bridge_listen_addr.clone()),
|
||||
("CAPTURES_DIR".into(), self.bridge_captures_dir.clone()),
|
||||
("TLS_ENABLED".into(), self.bridge_tls_enabled.to_string()),
|
||||
("RUST_LOG".into(), "openfut_bridge=info".into()),
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user