// client/src/main.rs #![forbid(unsafe_code)] use anyhow::Result; use std::{env, fs::OpenOptions, path::Path}; use tracing_appender::non_blocking; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::{filter::EnvFilter, fmt, prelude::*}; use lesavka_client::LesavkaClientApp; fn ensure_runtime_dir() { if env::var_os("XDG_RUNTIME_DIR").is_none() { eprintln!( "Error: $XDG_RUNTIME_DIR is not set. \ Launch the client from a regular desktop session or export it manually, \ e.g. `export XDG_RUNTIME_DIR=/run/user/$(id -u)`." ); std::process::exit(1); } } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { ensure_runtime_dir(); /*------------- common filter & stderr layer ------------------------*/ let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| { EnvFilter::new( "lesavka_client=trace,\ lesavka_server=trace,\ tonic=debug,\ h2=debug,\ tower=debug", ) }); let stderr_layer = fmt::layer() .with_target(true) .with_thread_ids(true) .with_file(true); let dev_mode = env::var("LESAVKA_DEV_MODE").is_ok(); let mut _guard: Option = None; // keep guard alive /*------------- subscriber setup -----------------------------------*/ if dev_mode { let log_path = Path::new("/tmp").join("lesavka-client.log"); // file → non-blocking writer (+ guard) let file = OpenOptions::new() .create(true) .write(true) // .truncate(true) .open(&log_path)?; let (file_writer, guard) = non_blocking(file); _guard = Some(guard); let file_layer = fmt::layer() .with_writer(file_writer) .with_ansi(false) .with_target(true) .with_level(true); tracing_subscriber::registry() .with(env_filter) .with(stderr_layer) .with(file_layer) .init(); tracing::info!("📜 lesavka-client running in DEV mode → {}", log_path.display()); } else { tracing_subscriber::registry() .with(env_filter) .with(stderr_layer) .init(); } /*------------- run the actual application -------------------------*/ let mut app = LesavkaClientApp::new()?; app.run().await }