diff --git a/.cargo/config.toml b/.cargo/config.toml index 09b7896..ed8b85c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,3 @@ [alias] -runs = "run -- run paper 1.19.4-550 --config data/config --backup data/backups --world data/worlds --jar paper-1.19.4-550.jar" +runs = "run -- run --config data/config --backup data/backups --world data/worlds --jar paper-1.19.4-550.jar --frequency 2" runrs = "run --release -- paper 1.19.4-545 --config data/config --backup data/backups --world data/worlds --jar data/paper-1.19.4-525.jar" diff --git a/src/backup/manager.rs b/src/backup/manager.rs index 5d2f1a3..cc6dd0c 100644 --- a/src/backup/manager.rs +++ b/src/backup/manager.rs @@ -1,4 +1,5 @@ use super::Backup; +use chrono::Utc; use serde::Deserialize; use serde::Serialize; use std::fs::File; @@ -15,6 +16,7 @@ where default_metadata: T, chain_len: u64, chains_to_keep: u64, + frequency: chrono::Duration, chains: Vec>>, } @@ -32,6 +34,7 @@ where metadata: T, chain_len: u64, chains_to_keep: u64, + frequency: chrono::Duration, ) -> Self { Self { backup_dir: backup_dir.into(), @@ -40,6 +43,7 @@ where default_metadata: metadata, chain_len, chains_to_keep, + frequency, chains: Vec::new(), } } @@ -137,4 +141,16 @@ where Ok(()) } + + /// Calculate the next time a backup should be created. If no backup has been created yet, it + /// will return now. + pub fn next_scheduled_time(&self) -> chrono::DateTime { + if let Some(last_chain) = self.chains.last() { + if let Some(last_backup) = last_chain.last() { + return last_backup.start_time + self.frequency; + } + } + + chrono::offset::Utc::now() + } } diff --git a/src/cli.rs b/src/cli.rs index 166fa82..d9ea9a9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -53,11 +53,22 @@ pub struct Cli { global = true )] pub chains: u64, + + /// How frequently to perform a backup, in minutes; 0 to disable. + #[arg( + short = 't', + long, + default_value_t = 0, + env = "ALEX_FREQUENCY", + global = true + )] + pub frequency: u32, + /// Type of server - #[arg(long, default_value = "unknown", env = "ALEX_SERVER")] + #[arg(long, default_value = "unknown", env = "ALEX_SERVER", global = true)] pub server: ServerType, /// Version string for the server, e.g. 1.19.4-545 - #[arg(long, default_value = "", env = "ALEX_SERVER_VERSION")] + #[arg(long, default_value = "", env = "ALEX_SERVER_VERSION", global = true)] pub server_version: String, } @@ -92,10 +103,6 @@ pub struct RunArgs { #[arg(long, default_value_t = 2048, env = "ALEX_XMX")] pub xmx: u64, - /// How frequently to perform a backup, in minutes; 0 to disable. - #[arg(short = 't', long, default_value_t = 0, env = "ALEX_FREQUENCY")] - pub frequency: u64, - /// Don't actually run the server, but simply output the server configuration that would have /// been ran #[arg(short, long, default_value_t = false)] diff --git a/src/main.rs b/src/main.rs index ffb0c93..f4b9ef2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,17 @@ use cli::{BackupArgs, Cli, Commands, RunArgs}; use std::io; use std::sync::{Arc, Mutex}; -fn backups_thread(counter: Arc>, frequency: u64) { +fn backups_thread(counter: Arc>) { loop { - std::thread::sleep(std::time::Duration::from_secs(frequency * 60)); + 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(); @@ -34,7 +42,8 @@ fn command_run(cli: &Cli, args: &RunArgs) -> io::Result<()> { .xms(args.xms) .xmx(args.xmx) .chain_len(cli.chain_len) - .chains_to_keep(cli.chains); + .chains_to_keep(cli.chains) + .frequency(cli.frequency); cmd.canonicalize()?; if args.dry { @@ -45,10 +54,9 @@ fn command_run(cli: &Cli, args: &RunArgs) -> io::Result<()> { let counter = Arc::new(Mutex::new(cmd.spawn()?)); - if args.frequency > 0 { + if cli.frequency > 0 { let clone = Arc::clone(&counter); - let frequency = args.frequency; - std::thread::spawn(move || backups_thread(clone, frequency)); + std::thread::spawn(move || backups_thread(clone)); } // Spawn thread that handles the main stdin loop @@ -72,6 +80,7 @@ fn commands_backup(cli: &Cli, _args: &BackupArgs) -> io::Result<()> { metadata, cli.chain_len, cli.chains, + chrono::Duration::minutes(cli.frequency.into()), ); manager.load()?; diff --git a/src/server/command.rs b/src/server/command.rs index d06f8bc..1ce5ce0 100644 --- a/src/server/command.rs +++ b/src/server/command.rs @@ -47,6 +47,7 @@ pub struct ServerCommand { xmx: u64, chain_len: u64, chains_to_keep: u64, + frequency: u32, } impl ServerCommand { @@ -63,6 +64,7 @@ impl ServerCommand { xmx: 2048, chain_len: 4, chains_to_keep: 7, + frequency: 0, } } @@ -113,6 +115,11 @@ impl ServerCommand { self } + pub fn frequency(mut self, v: u32) -> Self { + self.frequency = v; + self + } + fn accept_eula(&self) -> std::io::Result<()> { let mut eula_path = self.config_dir.clone(); eula_path.push("eula.txt"); @@ -207,6 +214,7 @@ impl ServerCommand { metadata, self.chain_len, self.chains_to_keep, + chrono::Duration::minutes(self.frequency.into()), ); manager.load()?; diff --git a/src/server/process.rs b/src/server/process.rs index 0a09ab0..17b86b1 100644 --- a/src/server/process.rs +++ b/src/server/process.rs @@ -5,7 +5,7 @@ use std::process::Child; pub struct ServerProcess { child: Child, - backups: BackupManager, + pub backups: BackupManager, } impl ServerProcess {