use std::{env, io, net::TcpListener};
use console::style;
const DEFAULT_HOST: &str = "127.0.0.1";
const DEFAULT_PORT: u16 = 3000;
pub(crate) struct Address {
pub host: String,
pub port: u16,
}
impl Address {
fn from_env() -> Self {
Self {
host: env::var("HOST").unwrap_or_else(|_| DEFAULT_HOST.to_owned()),
port: env::var("PORT")
.ok()
.and_then(|value| value.parse().ok())
.unwrap_or(DEFAULT_PORT),
}
}
}
pub fn resolve() -> Option<Address> {
let mut address = Address::from_env();
let original_port = address.port;
loop {
match TcpListener::bind((address.host.as_str(), address.port)) {
Ok(_listener) => break,
Err(err) if err.kind() == io::ErrorKind::AddrInUse => {
address.port = address.port.checked_add(1)?;
}
Err(_) => break,
}
}
if address.port != original_port {
eprintln!(
" {}",
style(format!(
"port {original_port} is in use; starting on port {} instead",
address.port
))
.yellow()
);
eprintln!();
}
Some(address)
}