refactor: structure code to allow expanding cli functionality
parent
d5cea49c8b
commit
1cfe13674d
|
@ -0,0 +1,12 @@
|
|||
use clap::{Args, Subcommand};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum BackupCommands {
|
||||
List,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct BackupArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: BackupCommands,
|
||||
}
|
|
@ -1,8 +1,23 @@
|
|||
mod backup;
|
||||
mod run;
|
||||
|
||||
pub use backup::{BackupArgs, BackupCommands};
|
||||
pub use run::RunArgs;
|
||||
|
||||
use crate::backup::ManagerConfig;
|
||||
use crate::server::ServerType;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::io;
|
||||
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)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
|
@ -36,7 +51,7 @@ pub struct Cli {
|
|||
)]
|
||||
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 (;).
|
||||
#[arg(long, env = "ALEX_LAYERS", global = true, value_delimiter = ';')]
|
||||
pub layers: Vec<ManagerConfig>,
|
||||
|
@ -49,42 +64,11 @@ pub struct Cli {
|
|||
pub server_version: String,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// Run the server
|
||||
Run(RunArgs),
|
||||
/// Create a new backup of the server. This command should only be used when the server is not
|
||||
/// running.
|
||||
Backup(BackupArgs),
|
||||
impl Cli {
|
||||
pub fn run(&self) -> io::Result<()> {
|
||||
match &self.command {
|
||||
Commands::Run(args) => args.run(self),
|
||||
Commands::Backup(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {}
|
|
@ -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)
|
||||
}
|
||||
}
|
81
src/main.rs
81
src/main.rs
|
@ -4,84 +4,31 @@ mod server;
|
|||
mod signals;
|
||||
mod stdin;
|
||||
|
||||
use crate::cli::Cli;
|
||||
use clap::Parser;
|
||||
use cli::{Cli, Commands, RunArgs};
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<()> {
|
||||
// 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 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)?;
|
||||
|
||||
// manager.create_backup()?;
|
||||
// manager.remove_old_backups()
|
||||
// match &args.command {
|
||||
// BackupCommands::List => ()
|
||||
// }
|
||||
|
||||
// // 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(_) => Ok(()),
|
||||
}
|
||||
cli.run()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue