mod server; mod signals; mod stdin; use clap::Parser; use server::ServerType; use std::io; use std::path::PathBuf; use std::sync::{Arc, Mutex}; #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Cli { /// Type of server type_: ServerType, /// Version string for the server, e.g. 1.19.4-545 #[arg(env = "ALEX_SERVER_VERSION")] server_version: String, /// Server jar to execute #[arg( long, value_name = "JAR_PATH", default_value = "server.jar", env = "ALEX_JAR" )] jar: PathBuf, /// Directory where configs are stored, and where the server will run #[arg( long, value_name = "CONFIG_DIR", default_value = ".", env = "ALEX_CONFIG_DIR" )] config: PathBuf, /// Directory where world files will be saved #[arg( long, value_name = "WORLD_DIR", default_value = "../worlds", env = "ALEX_WORLD_DIR" )] world: PathBuf, /// Directory where backups will be stored #[arg( long, value_name = "BACKUP_DIR", default_value = "../backups", env = "ALEX_WORLD_DIR" )] backup: PathBuf, /// Java command to run the server jar with #[arg(long, value_name = "JAVA_CMD", default_value_t = String::from("java"), env = "ALEX_JAVA")] java: String, /// XMS value in megabytes for the server instance #[arg(long, default_value_t = 1024, env = "ALEX_XMS")] xms: u64, /// XMX value in megabytes for the server instance #[arg(long, default_value_t = 2048, env = "ALEX_XMX")] xmx: u64, /// How many backups to keep #[arg(short = 'n', long, default_value_t = 7, env = "ALEX_MAX_BACKUPS")] max_backups: u64, /// How frequently to perform a backup, in minutes; 0 to disable. #[arg(short = 't', long, default_value_t = 0, env = "ALEX_FREQUENCY")] frequency: u64, } fn backups_thread(counter: Arc>, frequency: u64) { loop { std::thread::sleep(std::time::Duration::from_secs(frequency * 60)); { let mut server = counter.lock().unwrap(); // We explicitely ignore the error here, as we don't want the thread to fail let _ = server.backup(); } } } fn main() -> io::Result<()> { let (_, mut signals) = signals::install_signal_handlers()?; let cli = Cli::parse(); let cmd = server::ServerCommand::new(cli.type_, &cli.server_version) .java(&cli.java) .jar(cli.jar) .config(cli.config) .world(cli.world) .backup(cli.backup) .xms(cli.xms) .xmx(cli.xmx) .max_backups(cli.max_backups); let counter = Arc::new(Mutex::new(cmd.spawn()?)); if cli.frequency > 0 { let clone = Arc::clone(&counter); std::thread::spawn(move || backups_thread(clone, cli.frequency)); } // Spawn thread that handles the main stdin loop let clone = Arc::clone(&counter); std::thread::spawn(move || stdin::handle_stdin(clone)); // Signal handler loop exits the process when necessary signals::handle_signals(&mut signals, counter) }