use std::io::Read;
use std::net::TcpListener;
use std::path::PathBuf;
use std::sync::Arc;
use super::config::Config;
use super::listen::serve;
use super::lys::LysSignIn;
use super::signin::Door;
const CONFIG_BYTES: u64 = 1_048_576;
const USAGE: &str = "usage: haematite door --config <absolute door.json>";
pub fn run(mut args: impl Iterator<Item = String>) -> Result<(), String> {
if args.next().as_deref() != Some("--config") {
return Err(USAGE.to_owned());
}
let path = PathBuf::from(args.next().ok_or(USAGE)?);
if !path.is_absolute() || args.next().is_some() {
return Err(USAGE.to_owned());
}
let file = super::config_upgrade::open_source(&path)?;
let mut bytes = Vec::new();
file.take(CONFIG_BYTES + 1)
.read_to_end(&mut bytes)
.map_err(|error| format!("the door configuration could not be read: {error}"))?;
if u64::try_from(bytes.len()).unwrap_or(u64::MAX) > CONFIG_BYTES {
return Err("the door configuration exceeds its byte limit".to_owned());
}
let bytes = super::config_upgrade::upgrade(&path, &bytes)?;
let config = Config::parse(&bytes)?;
let issuer = LysSignIn::connect(&config.lys)?;
let door = Arc::new(Door::new(issuer));
let assistant = super::assistant_socket::Listener::start(&door, &config)
.map_err(|error| format!("{}: {}", error.code, error.message))?;
let children = super::children::Children::start(&config.children)?;
let site = Arc::new(config.site());
let limits = config.limits();
let listener = TcpListener::bind(config.listen)
.map_err(|error| format!("the door could not listen on {}: {error}", config.listen))?;
eprintln!(
"haematite door: listening on {} for {}",
config.listen, config.origin
);
serve(&listener, &door, &site, &limits);
drop(assistant);
drop(children);
Ok(())
}