You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.0 KiB
172 lines
4.0 KiB
4 years ago
|
//! For binding to sockets
|
||
|
use super::*;
|
||
|
use futures::{
|
||
|
prelude::*,
|
||
|
};
|
||
|
use std::{
|
||
|
marker::{
|
||
|
Send,
|
||
|
Unpin,
|
||
|
},
|
||
|
fmt,
|
||
|
error,
|
||
|
path::{
|
||
|
Path,
|
||
|
PathBuf,
|
||
|
},
|
||
|
};
|
||
|
use tokio::{
|
||
|
io::{
|
||
|
self,
|
||
|
AsyncRead,
|
||
|
AsyncWrite,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub enum BindError<E>
|
||
|
{
|
||
|
IO(io::Error),
|
||
|
Warp(warp::Error),
|
||
|
Other(E),
|
||
|
}
|
||
|
|
||
|
impl<E: error::Error + 'static> error::Error for BindError<E>
|
||
|
{
|
||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||
|
Some(match &self {
|
||
|
Self::IO(io) => io,
|
||
|
Self::Other(o) => o,
|
||
|
Self::Warp(w) => w,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
impl<E: fmt::Display> fmt::Display for BindError<E>
|
||
|
{
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||
|
{
|
||
|
match self {
|
||
|
Self::IO(io) => write!(f, "io error: {}", io),
|
||
|
Self::Other(other) => write!(f, "{}", other),
|
||
|
Self::Warp(warp) => write!(f, "server error: {}", warp),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
pub struct BindpointParseError;
|
||
|
|
||
|
impl error::Error for BindpointParseError{}
|
||
|
impl fmt::Display for BindpointParseError
|
||
|
{
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||
|
{
|
||
|
write!(f, "Failed to parse bindpoint as IP or unix domain socket")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd)]
|
||
|
pub enum Bindpoint
|
||
|
{
|
||
|
Unix(PathBuf),
|
||
|
TCP(SocketAddr),
|
||
|
}
|
||
|
|
||
|
impl fmt::Display for Bindpoint
|
||
|
{
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||
|
{
|
||
|
match self {
|
||
|
Self::Unix(unix) => write!(f, "unix:/{}", unix.to_string_lossy()),
|
||
|
Self::TCP(tcp) => write!(f, "{}", tcp),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl std::str::FromStr for Bindpoint
|
||
|
{
|
||
|
type Err = BindpointParseError;
|
||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
|
Ok(if let Ok(ip) = s.parse::<SocketAddr>() {
|
||
|
Self::TCP(ip)
|
||
|
} else if s.starts_with("unix:/") {
|
||
|
Self::Unix(PathBuf::from(&s[6..].to_owned()))
|
||
|
} else {
|
||
|
return Err(BindpointParseError);
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn bind_unix(to: impl AsRef<Path>) -> io::Result<impl TryStream<Ok= impl AsyncRead + AsyncWrite + Send + Unpin + 'static + Send, Error = impl Into<Box<dyn std::error::Error + Send + Sync>>>>
|
||
|
{
|
||
|
debug!("Binding to AF_UNIX: {:?}", to.as_ref());
|
||
|
let listener = tokio::net::UnixListener::bind(to)?;
|
||
|
Ok(listener)
|
||
|
}
|
||
|
|
||
|
pub fn serve<F>(server: warp::Server<F>, bind: Bindpoint, signal: impl Future<Output=()> + Send + 'static) -> Result<(Bindpoint, BoxFuture<'static, ()>), BindError<std::convert::Infallible>>
|
||
|
where F: Filter + Clone + Send + Sync + 'static,
|
||
|
<F::Future as TryFuture>::Ok: warp::Reply,
|
||
|
{
|
||
|
Ok(match bind {
|
||
|
Bindpoint::TCP(sock) => server.try_bind_with_graceful_shutdown(sock, signal).map(|(sock, fut)| (Bindpoint::TCP(sock), fut.boxed())).map_err(BindError::Warp)?,
|
||
|
Bindpoint::Unix(unix) => {
|
||
|
(Bindpoint::Unix(unix.clone()),
|
||
|
server.serve_incoming_with_graceful_shutdown(bind_unix(unix).map_err(BindError::IO)?, signal).boxed())
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
impl From<SocketAddr> for Bindpoint
|
||
|
{
|
||
|
fn from(from: SocketAddr) -> Self
|
||
|
{
|
||
|
Self::TCP(from)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn try_serve<F>(server: warp::Server<F>, bind: impl TryBindpoint, signal: impl Future<Output=()> + Send + 'static) -> Result<(Bindpoint, BoxFuture<'static, ()>), BindError<impl error::Error + 'static>>
|
||
|
where F: Filter + Clone + Send + Sync + 'static,
|
||
|
<F::Future as TryFuture>::Ok: warp::Reply,
|
||
|
{
|
||
|
serve(server, bind.try_parse().map_err(BindError::Other)?, signal).map_err(BindError::coerce)
|
||
|
}
|
||
|
|
||
|
pub trait TryBindpoint: Sized
|
||
|
{
|
||
|
type Err: error::Error + 'static;
|
||
|
fn try_parse(self) -> Result<Bindpoint, Self::Err>;
|
||
|
}
|
||
|
|
||
|
impl TryBindpoint for Bindpoint
|
||
|
{
|
||
|
type Err = std::convert::Infallible;
|
||
|
fn try_parse(self) -> Result<Bindpoint, Self::Err>
|
||
|
{
|
||
|
Ok(self)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: AsRef<str>> TryBindpoint for T
|
||
|
{
|
||
|
type Err = BindpointParseError;
|
||
|
fn try_parse(self) -> Result<Bindpoint, Self::Err>
|
||
|
{
|
||
|
self.as_ref().parse()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl BindError<std::convert::Infallible>
|
||
|
{
|
||
|
pub fn coerce<T>(self) -> BindError<T>
|
||
|
{
|
||
|
match self {
|
||
|
Self::Warp(w) => BindError::Warp(w),
|
||
|
Self::IO(w) => BindError::IO(w),
|
||
|
#[cold] _ => unreachable!(),
|
||
|
}
|
||
|
}
|
||
|
}
|