From 87835a3f53002feb0a92f71436c3c91f8234eca8 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Thu, 27 Jun 2024 18:22:28 -0700 Subject: [PATCH] start/stop all, restore commands added --- .maid/build.toml | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- Maidfile.toml | 2 +- src/cli/args.rs | 15 ++++++++ src/cli/internal.rs | 69 ++++++++++++++++++++++++++++------- src/cli/mod.rs | 82 ++++++++++++++++++++++++++++++++++-------- src/config/mod.rs | 2 +- src/config/structs.rs | 2 +- src/daemon/api/mod.rs | 23 +++++++----- src/daemon/mod.rs | 2 +- src/main.rs | 24 ++++++++++++- src/process/mod.rs | 5 +++ src/webui/package.json | 2 +- 14 files changed, 190 insertions(+), 44 deletions(-) diff --git a/.maid/build.toml b/.maid/build.toml index 2851e92..fff6db2 100644 --- a/.maid/build.toml +++ b/.maid/build.toml @@ -1,5 +1,5 @@ [env] -VERSION='1.7.1' +VERSION='1.8.0' [tasks.build_all] info = "build all" diff --git a/Cargo.lock b/Cargo.lock index 53811a6..67a0718 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1697,7 +1697,7 @@ dependencies = [ [[package]] name = "pmc" -version = "1.7.1" +version = "1.8.0" dependencies = [ "anyhow", "bytes", diff --git a/Cargo.toml b/Cargo.toml index fa63262..ec1e79e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pmc" -version = "1.7.1" +version = "1.8.0" edition = "2021" license = "MIT" repository = "https://lab.themackabu.dev/self/pmc" diff --git a/Maidfile.toml b/Maidfile.toml index 7667f8b..905e2c8 100644 --- a/Maidfile.toml +++ b/Maidfile.toml @@ -2,7 +2,7 @@ import = [".maid/build.toml", ".maid/server.toml"] [project] name = "pmc" -version = "1.7.1" +version = "1.8.0" [tasks] clean = { script = ["rm -rf bin", "mkdir bin"] } diff --git a/src/cli/args.rs b/src/cli/args.rs index a5a04fa..797f702 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -1,6 +1,7 @@ pub trait Validatable { fn from_id(id: usize) -> Self; fn from_string(s: String) -> Self; + fn get_string(&self) -> Option<&str>; } #[derive(Clone)] @@ -18,11 +19,25 @@ pub enum Item { impl Validatable for Args { fn from_id(id: usize) -> Self { Args::Id(id) } fn from_string(s: String) -> Self { Args::Script(s) } + + fn get_string(&self) -> Option<&str> { + match self { + Args::Id(_) => None, + Args::Script(s) => Some(s), + } + } } impl Validatable for Item { fn from_id(id: usize) -> Self { Item::Id(id) } fn from_string(s: String) -> Self { Item::Name(s) } + + fn get_string(&self) -> Option<&str> { + match self { + Item::Id(_) => None, + Item::Name(s) => Some(s), + } + } } pub fn validate(s: &str) -> Result { diff --git a/src/cli/internal.rs b/src/cli/internal.rs index 681dc93..3f5a6e3 100644 --- a/src/cli/internal.rs +++ b/src/cli/internal.rs @@ -1,5 +1,5 @@ use colored::Colorize; -use macros_rs::{crashln, string, ternary}; +use macros_rs::{crashln, string, ternary, then}; use psutil::process::{MemoryInfo, Process}; use regex::Regex; use serde::Serialize; @@ -62,11 +62,11 @@ impl<'i> Internal<'i> { } println!("{} Creating {}process with ({name})", *helpers::SUCCESS, self.kind); - println!("{} {}created ({name}) ✓", *helpers::SUCCESS, self.kind); + println!("{} {}Created ({name}) ✓", *helpers::SUCCESS, self.kind); } - pub fn restart(self, name: &Option, watch: &Option) { - println!("{} Applying {}action restartProcess on ({})", *helpers::SUCCESS, self.kind, self.id); + pub fn restart(mut self, name: &Option, watch: &Option, silent: bool) -> Runner { + then!(!silent, println!("{} Applying {}action restartProcess on ({})", *helpers::SUCCESS, self.kind, self.id)); if matches!(self.server_name, "internal" | "local") { let mut item = self.runner.get(self.id); @@ -79,7 +79,7 @@ impl<'i> Internal<'i> { name.as_ref().map(|n| item.rename(n.trim().replace("\n", ""))); item.restart(); - log!("process started (id={})", self.id); + self.runner = item.get_runner().clone(); } else { let Some(servers) = config::servers().servers else { crashln!("{} Failed to read servers", *helpers::FAIL) @@ -100,11 +100,16 @@ impl<'i> Internal<'i> { }; } - println!("{} restarted {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); + if !silent { + println!("{} Restarted {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); + log!("process started (id={})", self.id); + } + + return self.runner; } - pub fn stop(mut self) { - println!("{} Applying {}action stopProcess on ({})", *helpers::SUCCESS, self.kind, self.id); + pub fn stop(mut self, silent: bool) -> Runner { + then!(!silent, println!("{} Applying {}action stopProcess on ({})", *helpers::SUCCESS, self.kind, self.id)); if !matches!(self.server_name, "internal" | "local") { let Some(servers) = config::servers().servers else { @@ -121,9 +126,16 @@ impl<'i> Internal<'i> { }; } - self.runner.get(self.id).stop(); - println!("{} stopped {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); - log!("process stopped {}(id={})", self.kind, self.id); + let mut item = self.runner.get(self.id); + item.stop(); + self.runner = item.get_runner().clone(); + + if !silent { + println!("{} Stopped {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); + log!("process stopped {}(id={})", self.kind, self.id); + } + + return self.runner; } pub fn remove(mut self) { @@ -145,7 +157,7 @@ impl<'i> Internal<'i> { } self.runner.remove(self.id); - println!("{} removed {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); + println!("{} Removed {}({}) ✓", *helpers::SUCCESS, self.kind, self.id); log!("process removed (id={})", self.id); } @@ -418,6 +430,39 @@ impl<'i> Internal<'i> { item.env.iter().for_each(|(key, value)| println!("{}: {}", key, value.green())); } + pub fn save(server_name: &String) { + if !matches!(&**server_name, "internal" | "local") { + crashln!("{} Cannot force save on remote servers", *helpers::FAIL) + } + + println!("{} Saved current processes to dumpfile", *helpers::SUCCESS); + Runner::new().save(); + } + + pub fn restore(server_name: &String) { + let mut runner = Runner::new(); + let (kind, list_name) = super::format(server_name); + + if !matches!(&**server_name, "internal" | "local") { + crashln!("{} Cannot restore on remote servers", *helpers::FAIL) + } + + Runner::new().list().for_each(|(id, p)| { + if p.running == true { + runner = Internal { + id: *id, + server_name, + kind: kind.clone(), + runner: runner.clone(), + } + .restart(&None, &None, true); + } + }); + + println!("{} Restored process statuses from dumpfile", *helpers::SUCCESS); + Internal::list(&string!("default"), &list_name); + } + pub fn list(format: &String, server_name: &String) { let render_list = |runner: &mut Runner, internal: bool| { let mut processes: Vec = Vec::new(); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ca89bdb..7b91bab 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -25,30 +25,84 @@ pub fn get_version(short: bool) -> String { } pub fn start(name: &Option, args: &Args, watch: &Option, server_name: &String) { - let runner = Runner::new(); + let mut runner = Runner::new(); let (kind, list_name) = format(server_name); - match args { - Args::Id(id) => Internal { id: *id, runner, server_name, kind }.restart(name, watch), - Args::Script(script) => match runner.find(&script, server_name) { - Some(id) => Internal { id, runner, server_name, kind }.restart(name, watch), - None => Internal { id: 0, runner, server_name, kind }.create(script, name, watch), - }, + let arg = match args.get_string() { + Some(arg) => arg, + None => "", + }; + + if arg == "all" { + println!("{} Applying {kind}action startAllProcess", *helpers::SUCCESS); + + let largest = runner.size(); + match largest { + Some(largest) => (0..*largest + 1).for_each(|id| { + runner = Internal { + id, + server_name, + kind: kind.clone(), + runner: runner.clone(), + } + .restart(&None, &None, true); + }), + None => println!("{} Cannot start all, no processes found", *helpers::FAIL), + } + } else { + match args { + Args::Id(id) => { + Internal { id: *id, runner, server_name, kind }.restart(name, watch, false); + } + Args::Script(script) => match runner.find(&script, server_name) { + Some(id) => { + Internal { id, runner, server_name, kind }.restart(name, watch, false); + } + None => Internal { id: 0, runner, server_name, kind }.create(script, name, watch), + }, + } } Internal::list(&string!("default"), &list_name); } pub fn stop(item: &Item, server_name: &String) { - let runner: Runner = Runner::new(); + let mut runner: Runner = Runner::new(); let (kind, list_name) = format(server_name); - match item { - Item::Id(id) => Internal { id: *id, runner, server_name, kind }.stop(), - Item::Name(name) => match runner.find(&name, server_name) { - Some(id) => Internal { id, runner, server_name, kind }.stop(), - None => crashln!("{} Process ({name}) not found", *helpers::FAIL), - }, + let arg = match item.get_string() { + Some(arg) => arg, + None => "", + }; + + if arg == "all" { + println!("{} Applying {kind}action stopAllProcess", *helpers::SUCCESS); + + let largest = runner.size(); + match largest { + Some(largest) => (0..*largest + 1).for_each(|id| { + runner = Internal { + id, + server_name, + kind: kind.clone(), + runner: runner.clone(), + } + .stop(true); + }), + None => println!("{} Cannot stop all, no processes found", *helpers::FAIL), + } + } else { + match item { + Item::Id(id) => { + Internal { id: *id, runner, server_name, kind }.stop(false); + } + Item::Name(name) => match runner.find(&name, server_name) { + Some(id) => { + Internal { id, runner, server_name, kind }.stop(false); + } + None => crashln!("{} Process ({name}) not found", *helpers::FAIL), + }, + } } Internal::list(&string!("default"), &list_name); diff --git a/src/config/mod.rs b/src/config/mod.rs index ecc3d13..eb3af49 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -54,7 +54,7 @@ pub fn read() -> Config { address: string!("0.0.0.0"), path: None, port: 5630, - secure: Secure { enabled: false, token: string!("") }, + secure: Some(Secure { enabled: false, token: string!("") }), }, }, }; diff --git a/src/config/structs.rs b/src/config/structs.rs index 879990f..1cd8bc2 100644 --- a/src/config/structs.rs +++ b/src/config/structs.rs @@ -30,7 +30,7 @@ pub struct Web { pub api: bool, pub address: String, pub port: u64, - pub secure: Secure, + pub secure: Option, pub path: Option, } diff --git a/src/daemon/api/mod.rs b/src/daemon/api/mod.rs index 44c7a17..5f5ea56 100644 --- a/src/daemon/api/mod.rs +++ b/src/daemon/api/mod.rs @@ -144,17 +144,22 @@ impl<'r> FromRequest<'r> for routes::Token { async fn from_request(request: &'r rocket::Request<'_>) -> rocket::request::Outcome { let config = config::read().daemon.web; - if !config.secure.enabled { - return Outcome::Success(routes::Token); - } - - if let Some(header_value) = request.headers().get_one("token") { - if header_value == config.secure.token { - return Outcome::Success(routes::Token); + match config.secure { + Some(val) => { + if !val.enabled { + return Outcome::Success(routes::Token); + } + + if let Some(header_value) = request.headers().get_one("token") { + if header_value == val.token { + return Outcome::Success(routes::Token); + } + } + + Outcome::Error((rocket::http::Status::Unauthorized, ())) } + None => return Outcome::Success(routes::Token), } - - Outcome::Error((rocket::http::Status::Unauthorized, ())) } } diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index c2e74ae..819d644 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -300,7 +300,7 @@ pub fn restart(api: &bool, webui: &bool, verbose: bool) { pub fn reset() { let mut runner = Runner::new(); - let largest = runner.list().map(|(key, _)| *key).max(); + let largest = runner.size(); match largest { Some(id) => runner.set_id(Id::from(str!(id.to_string()))), diff --git a/src/main.rs b/src/main.rs index c9a5f9b..4e15c09 100644 --- a/src/main.rs +++ b/src/main.rs @@ -154,6 +154,22 @@ enum Commands { server: Option, }, + /// Restore all processes + #[command(visible_alias = "resurrect")] + Restore { + /// Server + #[arg(short, long)] + server: Option, + }, + + /// Save all processes to dumpfile + #[command(visible_alias = "store")] + Save { + /// Server + #[arg(short, long)] + server: Option, + }, + /// Get logs from a process Logs { #[clap(value_parser = cli::validate::)] @@ -197,6 +213,8 @@ fn main() { Commands::Start { name, args, watch, server } => cli::start(name, args, watch, &defaults(server)), Commands::Stop { item, server } => cli::stop(item, &defaults(server)), Commands::Remove { item, server } => cli::remove(item, &defaults(server)), + Commands::Restore { server } => Internal::restore(&defaults(server)), + Commands::Save { server } => Internal::save(&defaults(server)), Commands::Env { item, server } => cli::env(item, &defaults(server)), Commands::Details { item, format, server } => cli::info(item, format, &defaults(server)), Commands::List { format, server } => Internal::list(format, &defaults(server)), @@ -217,7 +235,11 @@ fn main() { }, }; - if !matches!(&cli.command, Commands::Daemon { .. }) && !matches!(&cli.command, Commands::Server { .. }) { + if !matches!(&cli.command, Commands::Daemon { .. }) + && !matches!(&cli.command, Commands::Server { .. }) + && !matches!(&cli.command, Commands::Save { .. }) + && !matches!(&cli.command, Commands::Env { .. }) + { then!(!daemon::pid::exists(), daemon::restart(&false, &false, false)); } } diff --git a/src/process/mod.rs b/src/process/mod.rs index 6ea086a..8a80cbc 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -348,6 +348,8 @@ impl Runner { pub fn info(&self, id: usize) -> Option<&Process> { self.list.get(&id) } + pub fn size(&self) -> Option<&usize> { self.list.iter().map(|(k, _)| k).max() } + pub fn list<'l>(&'l mut self) -> impl Iterator { self.list.iter_mut().map(|(k, v)| (k, v)) } pub fn process(&mut self, id: usize) -> &mut Process { self.list.get_mut(&id).unwrap_or_else(|| crashln!("{} Process ({id}) not found", *helpers::FAIL)) } @@ -525,6 +527,9 @@ impl ProcessWrapper { /// Set the process item as crashed pub fn crashed(&mut self) { lock!(self.runner).restart(self.id, true).save(); } + /// Get the borrowed runner reference (lives till program end) + pub fn get_runner(&mut self) -> &Runner { Box::leak(Box::new(lock!(self.runner))) } + /// Get a json dump of the process item pub fn fetch(&self) -> ItemSingle { let mut runner = lock!(self.runner); diff --git a/src/webui/package.json b/src/webui/package.json index 9be0293..dd121b3 100644 --- a/src/webui/package.json +++ b/src/webui/package.json @@ -2,7 +2,7 @@ "name": "pmc-webui", "type": "module", "license": "MIT", - "version": "1.6.0", + "version": "1.8.0", "scripts": { "astro": "astro", "dev": "astro dev", -- GitLab