parent
ca16c97629
commit
ef5dc3cbf1
@ -1,3 +0,0 @@
|
||||
Maybe see if `split-sentance` is stable enough to be enabled in prod now?
|
||||
Allow Unix domain socket for bind
|
||||
|
@ -0,0 +1,171 @@
|
||||
//! 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!(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue