use crate::server::BackupManager; use crate::server::ServerType; use flate2::write::GzEncoder; use flate2::Compression; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::Child; pub struct ServerProcess { type_: ServerType, version: String, config_dir: PathBuf, world_dir: PathBuf, backup_dir: PathBuf, max_backups: u64, child: Child, backups: BackupManager, } impl ServerProcess { pub fn new( type_: ServerType, version: String, config_dir: PathBuf, world_dir: PathBuf, backup_dir: PathBuf, max_backups: u64, child: Child, ) -> ServerProcess { let backup_manager = BackupManager::open( backup_dir.clone(), config_dir.clone(), world_dir.clone(), max_backups, ); ServerProcess { type_, version, config_dir, world_dir, backup_dir, max_backups, child, backups: backup_manager, } } pub fn send_command(&mut self, cmd: &str) -> std::io::Result<()> { match cmd.trim() { "stop" | "exit" => self.stop()?, "backup" => self.backup()?, s => self.custom(s)?, } Ok(()) } fn custom(&mut self, cmd: &str) -> std::io::Result<()> { let mut stdin = self.child.stdin.as_ref().unwrap(); stdin.write_all(format!("{}\n", cmd.trim()).as_bytes())?; stdin.flush()?; Ok(()) } pub fn stop(&mut self) -> std::io::Result<()> { self.custom("stop")?; self.child.wait()?; Ok(()) } pub fn kill(&mut self) -> std::io::Result<()> { self.child.kill() } /// Perform a backup by disabling the server's save feature and flushing its data, before /// creating an archive file. pub fn backup(&mut self) -> std::io::Result<()> { self.custom("say backing up server")?; // Make sure the server isn't modifying the files during the backup self.custom("save-off")?; self.custom("save-all")?; // TODO implement a better mechanism // We wait some time to (hopefully) ensure the save-all call has completed std::thread::sleep(std::time::Duration::from_secs(10)); let start_time = chrono::offset::Local::now(); let res = self.backups.create_archive(); if res.is_ok() { self.backups.remove_old_backups()?; } // The server's save feature needs to be enabled again even if the archive failed to create self.custom("save-on")?; let duration = chrono::offset::Local::now() - start_time; let duration_str = format!( "{}m{}s", duration.num_seconds() / 60, duration.num_seconds() % 60 ); if res.is_ok() { self.custom(&format!("say server backed up in {}", duration_str))?; } else { self.custom(&format!( "an error occured after {} while backing up the server", duration_str ))?; } res } }