mod backup; mod cli; mod server; mod signals; mod stdin; use clap::Parser; use cli::{BackupArgs, Cli, Commands, RunArgs}; use std::io; use std::sync::{Arc, Mutex}; fn backups_thread(counter: Arc>) { loop { let next_scheduled_time = { let server = counter.lock().unwrap(); server.backups.next_scheduled_time() }; let now = chrono::offset::Utc::now(); if next_scheduled_time > now { std::thread::sleep((next_scheduled_time - now).to_std().unwrap()); } { 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 command_run(cli: &Cli, args: &RunArgs) -> io::Result<()> { let (_, mut signals) = signals::install_signal_handlers()?; let mut cmd = server::ServerCommand::new(cli.server, &cli.server_version) .java(&args.java) .jar(args.jar.clone()) .config(cli.config.clone()) .world(cli.world.clone()) .backup(cli.backup.clone()) .xms(args.xms) .xmx(args.xmx) .chain_len(cli.chain_len) .chains_to_keep(cli.chains) .frequency(cli.frequency); cmd.canonicalize()?; if args.dry { print!("{}", cmd); return Ok(()); } let counter = Arc::new(Mutex::new(cmd.spawn()?)); if cli.frequency > 0 { let clone = Arc::clone(&counter); std::thread::spawn(move || backups_thread(clone)); } // 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) } fn commands_backup(cli: &Cli, _args: &BackupArgs) -> io::Result<()> { let metadata = server::Metadata { server_type: cli.server, server_version: cli.server_version.clone(), }; let mut manager = backup::Manager::new( cli.backup.clone(), cli.config.clone(), cli.world.clone(), metadata, cli.chain_len, cli.chains, chrono::Duration::minutes(cli.frequency.into()), ); manager.load()?; manager.create_backup()?; manager.remove_old_backups() } fn main() -> io::Result<()> { let cli = Cli::parse(); match &cli.command { Commands::Run(args) => command_run(&cli, args), Commands::Backup(args) => commands_backup(&cli, args), } }