multi-service commands: rss start/stop/restart/enable/disable mc-proxy mc-lobby
supports space-separated service names in start, stop, restart, enable, disable commands. each service result returned on its own line.
This commit is contained in:
parent
f0d334b7dd
commit
672b676020
3 changed files with 111 additions and 74 deletions
10
src/cli.rs
10
src/cli.rs
|
|
@ -14,15 +14,15 @@ pub struct Cli {
|
|||
pub enum Commands {
|
||||
/// Start a service
|
||||
Start {
|
||||
name: String,
|
||||
names: Vec<String>,
|
||||
},
|
||||
/// Stop a service
|
||||
Stop {
|
||||
name: String,
|
||||
names: Vec<String>,
|
||||
},
|
||||
/// Restart a service
|
||||
Restart {
|
||||
name: String,
|
||||
names: Vec<String>,
|
||||
},
|
||||
/// Show service status
|
||||
Status {
|
||||
|
|
@ -38,13 +38,13 @@ pub enum Commands {
|
|||
},
|
||||
/// Enable auto-start for a service
|
||||
Enable {
|
||||
name: String,
|
||||
names: Vec<String>,
|
||||
#[arg(long, help = "Start the service immediately")]
|
||||
now: bool,
|
||||
},
|
||||
/// Disable auto-start for a service
|
||||
Disable {
|
||||
name: String,
|
||||
names: Vec<String>,
|
||||
},
|
||||
/// List all configured services
|
||||
List,
|
||||
|
|
|
|||
113
src/daemon.rs
113
src/daemon.rs
|
|
@ -364,48 +364,60 @@ fn handle_client(
|
|||
|
||||
let response = match line {
|
||||
l if l.starts_with("start ") => {
|
||||
let name = &l[6..];
|
||||
if !config.service.contains_key(name) {
|
||||
format!("error: service '{}' not found", name)
|
||||
} else if procs.contains_key(name) {
|
||||
format!("error: '{}' already running", name)
|
||||
} else {
|
||||
match spawn(name, &config.service[name]) {
|
||||
Some(p) => {
|
||||
let pid = p.pid;
|
||||
procs.insert(name.to_string(), p);
|
||||
format!("ok {}", pid)
|
||||
let names: Vec<&str> = l[6..].split_whitespace().collect();
|
||||
let mut out = Vec::new();
|
||||
for name in &names {
|
||||
if !config.service.contains_key(*name) {
|
||||
out.push(format!("error: service '{}' not found", name));
|
||||
} else if procs.contains_key(*name) {
|
||||
out.push(format!("error: '{}' already running", name));
|
||||
} else {
|
||||
match spawn(name, &config.service[*name]) {
|
||||
Some(p) => {
|
||||
let pid = p.pid;
|
||||
procs.insert(name.to_string(), p);
|
||||
out.push(format!("ok {} pid={}", name, pid));
|
||||
}
|
||||
None => out.push(format!("error: failed to spawn '{}'", name)),
|
||||
}
|
||||
None => format!("error: failed to spawn '{}'", name),
|
||||
}
|
||||
}
|
||||
out.join("\n")
|
||||
}
|
||||
l if l.starts_with("stop ") => {
|
||||
let name = &l[5..];
|
||||
if !procs.contains_key(name) {
|
||||
format!("error: '{}' not running", name)
|
||||
} else {
|
||||
stop(name, procs);
|
||||
"ok".to_string()
|
||||
let names: Vec<&str> = l[5..].split_whitespace().collect();
|
||||
let mut out = Vec::new();
|
||||
for name in &names {
|
||||
if !procs.contains_key(*name) {
|
||||
out.push(format!("error: '{}' not running", name));
|
||||
} else {
|
||||
stop(name, procs);
|
||||
out.push(format!("ok {}", name));
|
||||
}
|
||||
}
|
||||
out.join("\n")
|
||||
}
|
||||
l if l.starts_with("restart ") => {
|
||||
let name = &l[8..];
|
||||
if procs.contains_key(name) {
|
||||
stop(name, procs);
|
||||
}
|
||||
if let Some(cfg) = config.service.get(name) {
|
||||
match spawn(name, cfg) {
|
||||
Some(p) => {
|
||||
let pid = p.pid;
|
||||
procs.insert(name.to_string(), p);
|
||||
format!("ok {}", pid)
|
||||
}
|
||||
None => format!("error: failed to spawn '{}'", name),
|
||||
let names: Vec<&str> = l[8..].split_whitespace().collect();
|
||||
let mut out = Vec::new();
|
||||
for name in &names {
|
||||
if procs.contains_key(*name) {
|
||||
stop(name, procs);
|
||||
}
|
||||
if let Some(cfg) = config.service.get(*name) {
|
||||
match spawn(name, cfg) {
|
||||
Some(p) => {
|
||||
let pid = p.pid;
|
||||
procs.insert(name.to_string(), p);
|
||||
out.push(format!("ok {} pid={}", name, pid));
|
||||
}
|
||||
None => out.push(format!("error: failed to spawn '{}'", name)),
|
||||
}
|
||||
} else {
|
||||
out.push(format!("error: service '{}' not found", name));
|
||||
}
|
||||
} else {
|
||||
format!("error: service '{}' not found", name)
|
||||
}
|
||||
out.join("\n")
|
||||
}
|
||||
"list" | "list " => {
|
||||
let mut out = Vec::new();
|
||||
|
|
@ -446,30 +458,39 @@ fn handle_client(
|
|||
}
|
||||
l if l.starts_with("enable ") => {
|
||||
let rest = &l[7..];
|
||||
let (name, now) = if let Some(n) = rest.strip_suffix(" now") {
|
||||
let (names_str, now) = if let Some(n) = rest.strip_suffix(" now") {
|
||||
(n, true)
|
||||
} else {
|
||||
(rest, false)
|
||||
};
|
||||
if !config.service.contains_key(name) {
|
||||
format!("error: service '{}' not found", name)
|
||||
} else if let Err(e) = crate::state::enable(name) {
|
||||
format!("error: enable '{}': {}", name, e)
|
||||
} else {
|
||||
if now {
|
||||
if !procs.contains_key(name) {
|
||||
if let Some(p) = spawn(name, &config.service[name]) {
|
||||
procs.insert(name.to_string(), p);
|
||||
let names: Vec<&str> = names_str.split_whitespace().collect();
|
||||
let mut out = Vec::new();
|
||||
for name in &names {
|
||||
if !config.service.contains_key(*name) {
|
||||
out.push(format!("error: service '{}' not found", name));
|
||||
} else if let Err(e) = crate::state::enable(name) {
|
||||
out.push(format!("error: enable '{}': {}", name, e));
|
||||
} else {
|
||||
if now {
|
||||
if !procs.contains_key(*name) {
|
||||
if let Some(p) = spawn(name, &config.service[*name]) {
|
||||
procs.insert(name.to_string(), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push(format!("ok {}", name));
|
||||
}
|
||||
"ok".to_string()
|
||||
}
|
||||
out.join("\n")
|
||||
}
|
||||
l if l.starts_with("disable ") => {
|
||||
let name = &l[8..];
|
||||
crate::state::disable(name);
|
||||
"ok".to_string()
|
||||
let names: Vec<&str> = l[8..].split_whitespace().collect();
|
||||
let mut out = Vec::new();
|
||||
for name in &names {
|
||||
crate::state::disable(name);
|
||||
out.push(format!("ok {}", name));
|
||||
}
|
||||
out.join("\n")
|
||||
}
|
||||
_ => format!("error: unknown command '{}'", line),
|
||||
};
|
||||
|
|
|
|||
62
src/main.rs
62
src/main.rs
|
|
@ -18,14 +18,14 @@ fn main() {
|
|||
let config_path = resolve_config_path(cli.config.as_deref());
|
||||
daemon::run(config_path);
|
||||
}
|
||||
Commands::Start { ref name } => cmd_start(name),
|
||||
Commands::Stop { ref name } => cmd_stop(name),
|
||||
Commands::Restart { ref name } => cmd_restart(name),
|
||||
Commands::Start { ref names } => cmd_start(names),
|
||||
Commands::Stop { ref names } => cmd_stop(names),
|
||||
Commands::Restart { ref names } => cmd_restart(names),
|
||||
Commands::Status { ref name } => cmd_status(name.as_deref()),
|
||||
Commands::List => cmd_list(),
|
||||
Commands::Logs { ref name, lines, follow } => cmd_logs(name, lines, follow),
|
||||
Commands::Enable { ref name, now } => cmd_enable(name, now),
|
||||
Commands::Disable { ref name } => cmd_disable(name),
|
||||
Commands::Enable { ref names, now } => cmd_enable(names, now),
|
||||
Commands::Disable { ref names } => cmd_disable(names),
|
||||
Commands::Supervise { .. } => {
|
||||
eprintln!("error: supervise is internal, use daemon");
|
||||
std::process::exit(1);
|
||||
|
|
@ -43,11 +43,12 @@ fn resolve_config_path(custom: Option<&str>) -> String {
|
|||
state::config_dir().join("config.toml").to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn cmd_start(name: &str) {
|
||||
match ipc::send_cmd(&format!("start {}", name)) {
|
||||
fn cmd_start(names: &[String]) {
|
||||
let cmd = format!("start {}", names.join(" "));
|
||||
match ipc::send_cmd(&cmd) {
|
||||
Ok(lines) => {
|
||||
if let Some(first) = lines.first() {
|
||||
println!("{}", first);
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -57,9 +58,14 @@ fn cmd_start(name: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmd_stop(name: &str) {
|
||||
match ipc::send_cmd(&format!("stop {}", name)) {
|
||||
Ok(_) => {}
|
||||
fn cmd_stop(names: &[String]) {
|
||||
let cmd = format!("stop {}", names.join(" "));
|
||||
match ipc::send_cmd(&cmd) {
|
||||
Ok(lines) => {
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
std::process::exit(1);
|
||||
|
|
@ -67,11 +73,12 @@ fn cmd_stop(name: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmd_restart(name: &str) {
|
||||
match ipc::send_cmd(&format!("restart {}", name)) {
|
||||
fn cmd_restart(names: &[String]) {
|
||||
let cmd = format!("restart {}", names.join(" "));
|
||||
match ipc::send_cmd(&cmd) {
|
||||
Ok(lines) => {
|
||||
if let Some(first) = lines.first() {
|
||||
println!("{}", first);
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -140,14 +147,18 @@ fn cmd_logs(name: &str, mut lines: Option<usize>, follow: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmd_enable(name: &str, now: bool) {
|
||||
fn cmd_enable(names: &[String], now: bool) {
|
||||
let cmd = if now {
|
||||
format!("enable {} now", name)
|
||||
format!("enable {} now", names.join(" "))
|
||||
} else {
|
||||
format!("enable {}", name)
|
||||
format!("enable {}", names.join(" "))
|
||||
};
|
||||
match ipc::send_cmd(&cmd) {
|
||||
Ok(_) => println!("enabled {}", name),
|
||||
Ok(lines) => {
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
std::process::exit(1);
|
||||
|
|
@ -155,9 +166,14 @@ fn cmd_enable(name: &str, now: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmd_disable(name: &str) {
|
||||
match ipc::send_cmd(&format!("disable {}", name)) {
|
||||
Ok(_) => println!("disabled {}", name),
|
||||
fn cmd_disable(names: &[String]) {
|
||||
let cmd = format!("disable {}", names.join(" "));
|
||||
match ipc::send_cmd(&cmd) {
|
||||
Ok(lines) => {
|
||||
for line in lines {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error: {}", e);
|
||||
std::process::exit(1);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue