106 lines
4.1 KiB
Rust
106 lines
4.1 KiB
Rust
//! `gatewayd serve --config <path>`: the Mattermost channel. It loads its configuration and its
|
|
//! token, prepares its directory, then serves until it must stop (exit 1).
|
|
|
|
use std::os::unix::fs::DirBuilderExt;
|
|
use std::path::Path;
|
|
use std::process::ExitCode;
|
|
use std::sync::Arc;
|
|
use std::sync::atomic::AtomicBool;
|
|
|
|
use bxcore::{instance, secrets};
|
|
use gatewayd::config::{Config, MATTERMOST_TOKEN};
|
|
use gatewayd::serve::{START_FAILED, Tuning, run};
|
|
|
|
fn main() -> ExitCode {
|
|
// `args_os`: the config path need not be UTF-8, and `args` would panic on one that is not.
|
|
let args: Vec<std::ffi::OsString> = std::env::args_os().skip(1).collect();
|
|
let words: Vec<Option<&str>> = args.iter().map(|a| a.to_str()).collect();
|
|
match (words.as_slice(), args.get(2)) {
|
|
([Some("serve"), Some("--config"), _], Some(path)) => serve(Path::new(path)),
|
|
_ => {
|
|
eprintln!("usage: gatewayd serve --config <path>");
|
|
ExitCode::from(2)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn serve(path: &Path) -> ExitCode {
|
|
// Each failure prints its message with `eprintln!` and returns `ExitCode::from(1)`.
|
|
// 1. `let config = match Config::load(path) { ... }`: an Err(e) prints
|
|
// "gatewayd: {e}\n{START_FAILED}".
|
|
// 2. `let source = match config.token_source() { ... }`: an Err(why) prints
|
|
// "gatewayd: {}: {why}\n{START_FAILED}" with `path.display()`.
|
|
// 3. `let env = |k: &str| std::env::var_os(k);`, then
|
|
// `let loaded = match secrets::load("gatewayd", MATTERMOST_TOKEN, &source, &env)`: an Err(e)
|
|
// prints "gatewayd: {e}" (the error carries its own pointer).
|
|
// Then `if let Some(warning) = &loaded.warning { eprintln!("{warning}"); }`.
|
|
// 3b. The instance lock, `<home>/run/gatewayd.lock` (M5b spec, section 9a): after the secret,
|
|
// which is read before anything is made, and before the directory and the socket.
|
|
// 4. The state file's directory:
|
|
// `let dir = config.state_path().parent().map(Path::to_path_buf).unwrap_or_default();`
|
|
// `std::fs::DirBuilder::new().recursive(true).mode(0o700).create(&dir)`: an Err(e) prints
|
|
// "gatewayd: cannot prepare {}: {e}\n{START_FAILED}" with `dir.display()`.
|
|
// 5. `let log: gatewayd::serve::Log = Arc::new(|line: &str| eprintln!("{line}"));`
|
|
// `let stop = run(config, loaded.secret, Tuning::default(), log, &AtomicBool::new(false));`
|
|
// `eprintln!("{stop}");` and `ExitCode::from(1)`.
|
|
let config = match Config::load(path) {
|
|
Ok(config) => config,
|
|
Err(e) => {
|
|
eprintln!("gatewayd: {e}\n{START_FAILED}");
|
|
return ExitCode::from(1);
|
|
}
|
|
};
|
|
let source = match config.token_source() {
|
|
Ok(source) => source,
|
|
Err(why) => {
|
|
eprintln!("gatewayd: {}: {why}\n{START_FAILED}", path.display());
|
|
return ExitCode::from(1);
|
|
}
|
|
};
|
|
let env = |k: &str| std::env::var_os(k);
|
|
let loaded = match secrets::load("gatewayd", MATTERMOST_TOKEN, &source, &env) {
|
|
Ok(loaded) => loaded,
|
|
Err(e) => {
|
|
eprintln!("gatewayd: {e}");
|
|
return ExitCode::from(1);
|
|
}
|
|
};
|
|
if let Some(warning) = &loaded.warning {
|
|
eprintln!("{warning}");
|
|
}
|
|
let lock_path = config.paths.home.join("run/gatewayd.lock");
|
|
let _instance = match instance::lock(&lock_path) {
|
|
Ok(held) => held,
|
|
Err(e) => {
|
|
eprintln!("{}", e.line("gatewayd", &lock_path));
|
|
return ExitCode::from(1);
|
|
}
|
|
};
|
|
let dir = config
|
|
.state_path()
|
|
.parent()
|
|
.map(Path::to_path_buf)
|
|
.unwrap_or_default();
|
|
if let Err(e) = std::fs::DirBuilder::new()
|
|
.recursive(true)
|
|
.mode(0o700)
|
|
.create(&dir)
|
|
{
|
|
eprintln!(
|
|
"gatewayd: cannot prepare {}: {e}\n{START_FAILED}",
|
|
dir.display()
|
|
);
|
|
return ExitCode::from(1);
|
|
}
|
|
let log: gatewayd::serve::Log = Arc::new(|line: &str| eprintln!("{line}"));
|
|
let stop = run(
|
|
config,
|
|
loaded.secret,
|
|
Tuning::default(),
|
|
log,
|
|
&AtomicBool::new(false),
|
|
);
|
|
eprintln!("{stop}");
|
|
ExitCode::from(1)
|
|
}
|