refactor: structure code to allow expanding cli functionality
ci/woodpecker/push/clippy Pipeline was successful Details
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/build Pipeline was successful Details

export-backup
Jef Roosens 2023-06-23 15:51:17 +02:00
parent d5cea49c8b
commit 1cfe13674d
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 144 additions and 107 deletions

12
src/cli/backup.rs 100644
View File

@ -0,0 +1,12 @@
use clap::{Args, Subcommand};
#[derive(Subcommand)]
pub enum BackupCommands {
List,
}
#[derive(Args)]
pub struct BackupArgs {
#[command(subcommand)]
pub command: BackupCommands,
}

View File

@ -1,8 +1,23 @@
mod backup;
mod run;
pub use backup::{BackupArgs, BackupCommands};
pub use run::RunArgs;
use crate::backup::ManagerConfig; use crate::backup::ManagerConfig;
use crate::server::ServerType; use crate::server::ServerType;
use clap::{Args, Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::io;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Subcommand)]
pub enum Commands {
/// Run the server
Run(RunArgs),
/// Interact with the backup system without starting a server
Backup(BackupArgs),
}
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
pub struct Cli { pub struct Cli {
@ -36,7 +51,7 @@ pub struct Cli {
)] )]
pub backup: PathBuf, pub backup: PathBuf,
/// What backup layers to employ, provided as a list of tuples name,frequency,chain_len,chains /// What backup layers to employ, provided as a list of tuples name,frequency,chains,chain_len
/// delimited by semicolons (;). /// delimited by semicolons (;).
#[arg(long, env = "ALEX_LAYERS", global = true, value_delimiter = ';')] #[arg(long, env = "ALEX_LAYERS", global = true, value_delimiter = ';')]
pub layers: Vec<ManagerConfig>, pub layers: Vec<ManagerConfig>,
@ -49,42 +64,11 @@ pub struct Cli {
pub server_version: String, pub server_version: String,
} }
#[derive(Subcommand)] impl Cli {
pub enum Commands { pub fn run(&self) -> io::Result<()> {
/// Run the server match &self.command {
Run(RunArgs), Commands::Run(args) => args.run(self),
/// Create a new backup of the server. This command should only be used when the server is not Commands::Backup(_) => Ok(()),
/// running. }
Backup(BackupArgs),
} }
#[derive(Args)]
pub struct RunArgs {
/// Server jar to execute
#[arg(
long,
value_name = "JAR_PATH",
default_value = "server.jar",
env = "ALEX_JAR"
)]
pub jar: PathBuf,
/// Java command to run the server jar with
#[arg(long, value_name = "JAVA_CMD", default_value_t = String::from("java"), env = "ALEX_JAVA")]
pub java: String,
/// XMS value in megabytes for the server instance
#[arg(long, default_value_t = 1024, env = "ALEX_XMS")]
pub xms: u64,
/// XMX value in megabytes for the server instance
#[arg(long, default_value_t = 2048, env = "ALEX_XMX")]
pub xmx: 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)]
pub dry: bool,
} }
#[derive(Args)]
pub struct BackupArgs {}

94
src/cli/run.rs 100644
View File

@ -0,0 +1,94 @@
use crate::cli::Cli;
use crate::server;
use crate::signals;
use crate::stdin;
use clap::Args;
use std::io;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
#[derive(Args)]
pub struct RunArgs {
/// Server jar to execute
#[arg(
long,
value_name = "JAR_PATH",
default_value = "server.jar",
env = "ALEX_JAR"
)]
pub jar: PathBuf,
/// Java command to run the server jar with
#[arg(long, value_name = "JAVA_CMD", default_value_t = String::from("java"), env = "ALEX_JAVA")]
pub java: String,
/// XMS value in megabytes for the server instance
#[arg(long, default_value_t = 1024, env = "ALEX_XMS")]
pub xms: u64,
/// XMX value in megabytes for the server instance
#[arg(long, default_value_t = 2048, env = "ALEX_XMX")]
pub xmx: 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)]
pub dry: bool,
}
fn backups_thread(counter: Arc<Mutex<server::ServerProcess>>) {
loop {
let next_scheduled_time = {
let server = counter.lock().unwrap();
server.backups.next_scheduled_time().unwrap()
};
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();
}
}
}
impl RunArgs {
pub fn run(&self, cli: &Cli) -> io::Result<()> {
let (_, mut signals) = signals::install_signal_handlers()?;
let mut cmd = server::ServerCommand::new(cli.server, &cli.server_version)
.java(&self.java)
.jar(self.jar.clone())
.config(cli.config.clone())
.world(cli.world.clone())
.backup(cli.backup.clone())
.managers(cli.layers.clone())
.xms(self.xms)
.xmx(self.xmx);
cmd.canonicalize()?;
if self.dry {
print!("{}", cmd);
return Ok(());
}
let counter = Arc::new(Mutex::new(cmd.spawn()?));
if !cli.layers.is_empty() {
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)
}
}

View File

@ -4,84 +4,31 @@ mod server;
mod signals; mod signals;
mod stdin; mod stdin;
use crate::cli::Cli;
use clap::Parser; use clap::Parser;
use cli::{Cli, Commands, RunArgs};
use std::io; use std::io;
use std::sync::{Arc, Mutex};
fn backups_thread(counter: Arc<Mutex<server::ServerProcess>>) { // fn commands_backup(cli: &Cli, args: &BackupArgs) -> io::Result<()> {
loop {
let next_scheduled_time = {
let server = counter.lock().unwrap();
server.backups.next_scheduled_time().unwrap()
};
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())
.managers(cli.layers.clone())
.xms(args.xms)
.xmx(args.xmx);
cmd.canonicalize()?;
if args.dry {
print!("{}", cmd);
return Ok(());
}
let counter = Arc::new(Mutex::new(cmd.spawn()?));
if !cli.layers.is_empty() {
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 { // let metadata = server::Metadata {
// server_type: cli.server, // server_type: cli.server,
// server_version: cli.server_version.clone(), // server_version: cli.server_version.clone(),
// }; // };
// let mut meta = MetaManager::new(cli.backup, cli.config, cli.world, metadata); // let dirs = vec![
// (PathBuf::from("config"), cli.config.clone()),
// (PathBuf::from("worlds"), cli.world.clone()),
// ];
// let mut meta = MetaManager::new(cli.backup.clone(), dirs, metadata);
// meta.add_all(&cli.layers)?; // meta.add_all(&cli.layers)?;
// manager.create_backup()?; // match &args.command {
// manager.remove_old_backups() // BackupCommands::List => ()
// }
// // manager.create_backup()?;
// // manager.remove_old_backups()
// } // }
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
cli.run()
match &cli.command {
Commands::Run(args) => command_run(&cli, args),
Commands::Backup(_) => Ok(()),
}
} }