Add brokerd serve: startup, both sockets, and the expiry thread
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
+119
-3
@@ -1,4 +1,120 @@
|
||||
fn main() {
|
||||
eprintln!("brokerd: not implemented until M3");
|
||||
std::process::exit(2);
|
||||
//! `brokerd`: the broker role. `serve` takes the audit lock, binds both sockets, and serves.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
use std::sync::Arc;
|
||||
|
||||
use brokerd::audit::{AuditError, RECOVERED_NOTICE};
|
||||
use brokerd::config::Config;
|
||||
use brokerd::runner::Refusing;
|
||||
use brokerd::serve::{self, ServeError};
|
||||
|
||||
const USAGE: &str = "usage: brokerd serve --config <path> [--accept-break]";
|
||||
|
||||
fn main() -> ExitCode {
|
||||
// The first argument must be `serve`.
|
||||
let mut args = std::env::args().skip(1);
|
||||
match args.next() {
|
||||
Some(command) if command == "serve" => {}
|
||||
_ => return usage(),
|
||||
}
|
||||
|
||||
// `--config <path>` exactly once and `--accept-break` at most once, in any order.
|
||||
let (config_path, accept_break) = match parse_serve(args) {
|
||||
Ok(pair) => pair,
|
||||
Err(()) => return usage(),
|
||||
};
|
||||
|
||||
// Read the config before touching the filesystem: a bad config must make nothing.
|
||||
let cfg = match Config::load(&config_path) {
|
||||
Ok(cfg) => cfg,
|
||||
Err(e) => {
|
||||
eprintln!("brokerd: {e}");
|
||||
return ExitCode::from(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Keep the socket paths for the serving notice, before `cfg` is moved into `start`.
|
||||
let broker_path = cfg.broker_socket();
|
||||
let admin_path = cfg.admin_socket();
|
||||
|
||||
let started = match serve::start(
|
||||
cfg,
|
||||
accept_break,
|
||||
Box::new(Refusing),
|
||||
Arc::new(|line: &str| eprintln!("{line}")),
|
||||
) {
|
||||
Ok(started) => started,
|
||||
Err(ServeError::Audit(e @ AuditError::NothingToAccept)) => {
|
||||
eprintln!("brokerd: {e}");
|
||||
return ExitCode::from(2);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("brokerd: {e}");
|
||||
return ExitCode::from(1);
|
||||
}
|
||||
};
|
||||
|
||||
if started.recovered {
|
||||
eprintln!("{RECOVERED_NOTICE}");
|
||||
}
|
||||
if let Some(failure) = &started.accepted {
|
||||
eprintln!(
|
||||
"audit: accepted the break at {}:{}: {}",
|
||||
failure.file, failure.line, failure.what
|
||||
);
|
||||
}
|
||||
eprintln!(
|
||||
"brokerd: serving tools on {} and approvals on {}",
|
||||
broker_path.display(),
|
||||
admin_path.display()
|
||||
);
|
||||
|
||||
match started.run() {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(e) => {
|
||||
eprintln!("brokerd: {e}");
|
||||
ExitCode::from(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The argument list was not `serve --config <path> [--accept-break]`.
|
||||
fn usage() -> ExitCode {
|
||||
eprintln!("{USAGE}");
|
||||
ExitCode::from(2)
|
||||
}
|
||||
|
||||
/// The `--config` and `--accept-break` flags after `serve`, or `Err(())` for a bad list.
|
||||
fn parse_serve<I: Iterator<Item = String>>(mut args: I) -> Result<(PathBuf, bool), ()> {
|
||||
let mut config: Option<String> = None;
|
||||
let mut accept_break = false;
|
||||
loop {
|
||||
match args.next() {
|
||||
None => {
|
||||
return match config {
|
||||
Some(path) => Ok((PathBuf::from(path), accept_break)),
|
||||
None => Err(()),
|
||||
};
|
||||
}
|
||||
Some(arg) => match arg.as_str() {
|
||||
"--config" => match args.next() {
|
||||
Some(path) => {
|
||||
if config.is_some() {
|
||||
return Err(());
|
||||
}
|
||||
config = Some(path);
|
||||
}
|
||||
None => return Err(()),
|
||||
},
|
||||
"--accept-break" => {
|
||||
if accept_break {
|
||||
return Err(());
|
||||
}
|
||||
accept_break = true;
|
||||
}
|
||||
_ => return Err(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user