use std::net::{SocketAddr, ToSocketAddrs};
use std::path::PathBuf;
const DEFAULT_HOST: &str = "127.0.0.1";
const DEFAULT_PORT: u16 = 29653;
#[derive(Debug)]
pub(super) struct ServeOptions {
pub addr: SocketAddr,
pub workspace: PathBuf,
pub web_dir: Option<PathBuf>,
pub api_only: bool,
pub help: bool,
}
impl ServeOptions {
pub(super) fn parse(args: &[String]) -> anyhow::Result<Self> {
let mut host = std::env::var("A3S_CODE_WEB_HOST").unwrap_or_else(|_| DEFAULT_HOST.into());
let mut port = std::env::var("A3S_CODE_WEB_PORT")
.ok()
.and_then(|value| value.parse::<u16>().ok())
.unwrap_or(DEFAULT_PORT);
let mut workspace = std::env::current_dir()?;
let mut web_dir = std::env::var_os("A3S_CODE_WEB_DIR").map(PathBuf::from);
let mut api_only = false;
let mut help = false;
let mut index = 0;
while index < args.len() {
match args[index].as_str() {
"-h" | "--help" | "help" => {
help = true;
index += 1;
}
"--host" => {
host = take_value(args, &mut index, "--host")?;
}
"--port" => {
let value = take_value(args, &mut index, "--port")?;
port = value
.parse::<u16>()
.map_err(|_| anyhow::anyhow!("--port must be a number from 0 to 65535"))?;
}
"--workspace" | "-w" => {
workspace = PathBuf::from(take_value(args, &mut index, "--workspace")?);
}
"--web-dir" => {
web_dir = Some(PathBuf::from(take_value(args, &mut index, "--web-dir")?));
}
"--api-only" => {
api_only = true;
index += 1;
}
other => anyhow::bail!("unknown a3s code serve option `{other}`"),
}
}
let addr = resolve_addr(&host, port)?;
Ok(Self {
addr,
workspace,
web_dir,
api_only,
help,
})
}
}
fn take_value(args: &[String], index: &mut usize, flag: &str) -> anyhow::Result<String> {
let value_index = *index + 1;
let value = args
.get(value_index)
.filter(|value| !value.starts_with('-'))
.ok_or_else(|| anyhow::anyhow!("{flag} requires a value"))?;
*index += 2;
Ok(value.clone())
}
fn resolve_addr(host: &str, port: u16) -> anyhow::Result<SocketAddr> {
let mut addrs = format!("{host}:{port}")
.to_socket_addrs()
.map_err(|e| anyhow::anyhow!("invalid host/port {host}:{port}: {e}"))?;
addrs
.next()
.ok_or_else(|| anyhow::anyhow!("could not resolve {host}:{port}"))
}