use core::fmt;
use core::str::FromStr;
use std::net::SocketAddr;
use std::path::PathBuf;
use http::Uri;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ListenAddress {
Network(SocketAddr),
UnixSocket(PathBuf),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConnectAddress {
Uri(Uri),
UnixSocket(PathBuf),
}
impl FromStr for ListenAddress {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.strip_prefix("unix:") {
Some(v) => Ok(Self::UnixSocket(v.into())),
None => match SocketAddr::from_str(s) {
Ok(v) => Ok(Self::Network(v)),
Err(_) => Err(Error::InvalidListenAddress(s.to_owned())),
},
}
}
}
impl fmt::Display for ListenAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::Network(addr) => addr.fmt(f),
Self::UnixSocket(path) => {
f.write_str("unix:")?;
path.display().fmt(f)
},
}
}
}
impl FromStr for ConnectAddress {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.strip_prefix("unix:") {
Some(v) => Ok(Self::UnixSocket(v.into())),
None => Ok(Self::Uri(Uri::from_str(s)?)),
}
}
}
impl fmt::Display for ConnectAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::UnixSocket(path) => {
f.write_str("unix:")?;
path.display().fmt(f)
},
Self::Uri(uri) => uri.fmt(f),
}
}
}
impl TryFrom<ConnectAddress> for ListenAddress {
type Error = Error;
fn try_from(value: ConnectAddress) -> Result<Self, Self::Error> {
Ok(match value {
ConnectAddress::Uri(uri) => {
let no_scheme = format!("{}:{}", uri.host().ok_or(Error::MissingHost)?, uri.port().ok_or(Error::MissingPort)?);
Self::Network(SocketAddr::from_str(&no_scheme).map_err(|_| Error::InvalidListenAddress(no_scheme))?)
},
ConnectAddress::UnixSocket(path) => Self::UnixSocket(path),
})
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("'{0}' is neither a valid IP:port address nor a path prefixed with 'unix:'")]
InvalidListenAddress(String),
#[error("String has a scheme prefix of either http or https but could not be parsed into a Uri: {0}")]
InvalidUri(#[from] http::uri::InvalidUri),
#[error("The address is missing a host")]
MissingHost,
#[error("The address is missing a port")]
MissingPort,
}