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 = std::fs::File::open(&path)
.map_err(|error| format!("the door configuration could not be opened: {error}"))?;
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 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 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);
Ok(())
}