objectstore_server/
cli.rs1use std::fs::File;
7use std::path::PathBuf;
8use std::thread;
9use std::time::Duration;
10
11use anyhow::Result;
12use argh::FromArgs;
13
14use crate::config::Config;
15use crate::{healthcheck, observability, web};
16
17const SHUTDOWN_MARKER_PATH: &str = "/tmp/objectstore.down";
20
21#[derive(Debug, FromArgs)]
23struct Args {
24 #[argh(option, short = 'c')]
26 pub config: Option<PathBuf>,
27
28 #[argh(subcommand)]
29 pub command: Command,
30}
31
32#[derive(Debug, FromArgs)]
33#[argh(subcommand)]
34enum Command {
35 Run(RunCommand),
36 Healthcheck(HealthcheckCommand),
37 Version(VersionCommand),
38 Sleep(SleepCommand),
39 Down(DownCommand),
40}
41
42#[derive(Debug, FromArgs)]
44#[argh(subcommand, name = "run")]
45struct RunCommand {}
46
47#[derive(Debug, FromArgs)]
52#[argh(subcommand, name = "healthcheck")]
53struct HealthcheckCommand {}
54
55#[derive(Default, Debug, FromArgs)]
57#[argh(subcommand, name = "version")]
58struct VersionCommand {}
59
60#[derive(Debug, FromArgs)]
62#[argh(subcommand, name = "sleep")]
63struct SleepCommand {
64 #[argh(positional)]
65 seconds: u64,
66}
67
68#[derive(Debug, FromArgs)]
70#[argh(subcommand, name = "down")]
71struct DownCommand {
72 #[argh(positional)]
74 sleep_seconds: Option<u64>,
75}
76
77pub fn execute() -> Result<()> {
79 let args: Args = argh::from_env();
80
81 if let Command::Version(_) = args.command {
83 println!("{}", env!("OBJECTSTORE_RELEASE"));
84 return Ok(());
85 }
86
87 if let Command::Sleep(SleepCommand { seconds }) = args.command {
88 thread::sleep(Duration::from_secs(seconds));
89 return Ok(());
90 }
91
92 if let Command::Down(DownCommand { sleep_seconds }) = args.command {
93 File::create(SHUTDOWN_MARKER_PATH)?;
94 if let Some(seconds) = sleep_seconds {
95 thread::sleep(Duration::from_secs(seconds));
96 }
97 return Ok(());
98 }
99
100 let config = Config::load(args.config.as_deref())?;
101
102 rustls::crypto::ring::default_provider()
104 .install_default()
105 .map_err(|_| anyhow::anyhow!("Failed to install rustls crypto provider"))?;
106
107 let _sentry_guard = observability::init_sentry(&config);
109
110 let runtime = tokio::runtime::Builder::new_multi_thread()
111 .thread_name("main-rt")
112 .enable_all()
113 .worker_threads(config.runtime.worker_threads)
114 .build()?;
115 let _runtime_guard = runtime.enter();
116
117 objectstore_log::init(&config.logging);
118 objectstore_log::debug!(?config);
119
120 objectstore_metrics::init(&config.metrics)?;
121
122 runtime.block_on(async move {
123 match args.command {
124 Command::Run(RunCommand {}) => {
125 objectstore_options::init()?;
128 web::server(config).await
129 }
130 Command::Healthcheck(HealthcheckCommand {}) => healthcheck::healthcheck(config).await,
131 Command::Version(VersionCommand {})
132 | Command::Sleep(SleepCommand { .. })
133 | Command::Down(DownCommand { .. }) => {
134 unreachable!()
135 }
136 }
137 })
138}