actionqueue_cli/cmd/
daemon.rs1use std::net::SocketAddr;
4
5use serde_json::json;
6
7use crate::args::DaemonArgs;
8use crate::cmd::{resolve_data_dir, CliError, CommandOutput};
9
10pub fn run(args: DaemonArgs) -> Result<CommandOutput, CliError> {
12 let mut config = actionqueue_daemon::config::DaemonConfig::default();
13 let data_dir = resolve_data_dir(args.data_dir.as_deref());
14 config.data_dir = data_dir.clone();
15
16 if let Some(bind) = args.bind.as_deref() {
17 config.bind_address = parse_socket_addr(bind, "bind_address")?;
18 }
19 if let Some(metrics_bind) = args.metrics_bind.as_deref() {
20 config.metrics_bind = Some(parse_socket_addr(metrics_bind, "metrics_bind")?);
21 }
22 config.enable_control = args.enable_control;
23
24 config.validate().map_err(|error| {
25 CliError::validation(
26 "daemon_config_invalid",
27 format!("daemon configuration rejected: {error}"),
28 )
29 })?;
30
31 let state = actionqueue_daemon::bootstrap::bootstrap(config).map_err(|error| {
32 CliError::runtime("daemon_bootstrap_failed", format!("daemon bootstrap failed: {error}"))
33 })?;
34
35 let ready = state.ready_status();
36 let metrics_bind = state.config().metrics_bind.map(|addr| addr.to_string());
37
38 if args.json {
39 return Ok(CommandOutput::Json(json!({
40 "command": "daemon",
41 "data_dir": data_dir.display().to_string(),
42 "bind_address": state.config().bind_address.to_string(),
43 "metrics_bind": metrics_bind,
44 "control_enabled": state.config().enable_control,
45 "ready": ready.is_ready(),
46 "ready_reason": ready.reason(),
47 })));
48 }
49
50 let lines = [
51 "command=daemon".to_string(),
52 format!("data_dir={}", data_dir.display()),
53 format!("bind_address={}", state.config().bind_address),
54 format!("metrics_bind={}", metrics_bind.as_deref().unwrap_or("disabled")),
55 format!("control_enabled={}", state.config().enable_control),
56 format!("ready={}", ready.is_ready()),
57 format!("ready_reason={}", ready.reason()),
58 ];
59 Ok(CommandOutput::Text(lines.join("\n")))
60}
61
62fn parse_socket_addr(raw: &str, field: &str) -> Result<SocketAddr, CliError> {
63 raw.parse::<SocketAddr>().map_err(|error| {
64 CliError::validation("invalid_socket_address", format!("invalid {field} '{raw}': {error}"))
65 })
66}