-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
60f3cd5
commit bf60fe6
Showing
20 changed files
with
643 additions
and
300 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,11 @@ | ||
use std::io; | ||
use futures::TryFutureExt; | ||
use tokio::io::{AsyncRead, AsyncWrite}; | ||
|
||
use crate::listener::{Listener, Endpoint}; | ||
|
||
pub trait Bindable: Sized { | ||
type Listener: Listener + 'static; | ||
use crate::listener::{Endpoint, Listener}; | ||
|
||
pub trait Bind<T>: Listener<Connection: AsyncRead + AsyncWrite> + 'static { | ||
type Error: std::error::Error + Send + 'static; | ||
|
||
async fn bind(self) -> Result<Self::Listener, Self::Error>; | ||
|
||
/// The endpoint that `self` binds on. | ||
fn bind_endpoint(&self) -> io::Result<Endpoint>; | ||
} | ||
|
||
impl<L: Listener + 'static> Bindable for L { | ||
type Listener = L; | ||
|
||
type Error = std::convert::Infallible; | ||
|
||
async fn bind(self) -> Result<Self::Listener, Self::Error> { | ||
Ok(self) | ||
} | ||
|
||
fn bind_endpoint(&self) -> io::Result<Endpoint> { | ||
L::endpoint(self) | ||
} | ||
} | ||
|
||
impl<A: Bindable, B: Bindable> Bindable for either::Either<A, B> { | ||
type Listener = tokio_util::either::Either<A::Listener, B::Listener>; | ||
|
||
type Error = either::Either<A::Error, B::Error>; | ||
|
||
async fn bind(self) -> Result<Self::Listener, Self::Error> { | ||
match self { | ||
either::Either::Left(a) => a.bind() | ||
.map_ok(tokio_util::either::Either::Left) | ||
.map_err(either::Either::Left) | ||
.await, | ||
either::Either::Right(b) => b.bind() | ||
.map_ok(tokio_util::either::Either::Right) | ||
.map_err(either::Either::Right) | ||
.await, | ||
} | ||
} | ||
async fn bind(to: T) -> Result<Self, Self::Error>; | ||
|
||
fn bind_endpoint(&self) -> io::Result<Endpoint> { | ||
either::for_both!(self, a => a.bind_endpoint()) | ||
} | ||
fn bind_endpoint(to: &T) -> Option<Endpoint>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,87 @@ | ||
use either::Either; | ||
use serde::Deserialize; | ||
use tokio_util::either::{Either, Either::{Left, Right}}; | ||
use futures::TryFutureExt; | ||
|
||
use crate::listener::{Bindable, Endpoint}; | ||
use crate::error::{Error, ErrorKind}; | ||
use crate::error::ErrorKind; | ||
use crate::{Ignite, Rocket}; | ||
use crate::listener::{Bind, Endpoint, tcp::TcpListener}; | ||
|
||
#[derive(serde::Deserialize)] | ||
pub struct DefaultListener { | ||
#[cfg(unix)] use crate::listener::unix::UnixListener; | ||
#[cfg(feature = "tls")] use crate::tls::{TlsListener, TlsConfig}; | ||
|
||
mod private { | ||
use super::{Either, TcpListener}; | ||
|
||
#[cfg(feature = "tls")] pub type TlsListener<T> = super::TlsListener<T>; | ||
#[cfg(not(feature = "tls"))] pub type TlsListener<T> = T; | ||
#[cfg(unix)] pub type UnixListener = super::UnixListener; | ||
#[cfg(not(unix))] pub type UnixListener = super::TcpListener; | ||
|
||
pub type Listener = Either< | ||
Either<TlsListener<TcpListener>, TlsListener<UnixListener>>, | ||
Either<TcpListener, UnixListener>, | ||
>; | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct Config { | ||
#[serde(default)] | ||
pub address: Endpoint, | ||
pub port: Option<u16>, | ||
pub reuse: Option<bool>, | ||
address: Endpoint, | ||
#[cfg(feature = "tls")] | ||
pub tls: Option<crate::tls::TlsConfig>, | ||
tls: Option<TlsConfig>, | ||
} | ||
|
||
#[cfg(not(unix))] type BaseBindable = Either<std::net::SocketAddr, std::net::SocketAddr>; | ||
#[cfg(unix)] type BaseBindable = Either<std::net::SocketAddr, super::unix::UdsConfig>; | ||
pub type DefaultListener = private::Listener; | ||
|
||
#[cfg(not(feature = "tls"))] type TlsBindable<T> = Either<T, T>; | ||
#[cfg(feature = "tls")] type TlsBindable<T> = Either<super::tls::TlsBindable<T>, T>; | ||
impl<'r> Bind<&'r Rocket<Ignite>> for DefaultListener { | ||
type Error = crate::Error; | ||
|
||
impl DefaultListener { | ||
pub(crate) fn base_bindable(&self) -> Result<BaseBindable, crate::Error> { | ||
match &self.address { | ||
Endpoint::Tcp(mut address) => { | ||
if let Some(port) = self.port { | ||
address.set_port(port); | ||
} | ||
async fn bind(rocket: &'r Rocket<Ignite>) -> Result<Self, Self::Error> { | ||
let config: Config = rocket.figment().extract()?; | ||
|
||
Ok(BaseBindable::Left(address)) | ||
}, | ||
#[cfg(unix)] | ||
Endpoint::Unix(path) => { | ||
let uds = super::unix::UdsConfig { path: path.clone(), reuse: self.reuse, }; | ||
Ok(BaseBindable::Right(uds)) | ||
}, | ||
#[cfg(not(unix))] | ||
e@Endpoint::Unix(_) => { | ||
let msg = "Unix domain sockets unavailable on non-unix platforms."; | ||
let boxed = Box::<dyn std::error::Error + Send + Sync>::from(msg); | ||
Err(Error::new(ErrorKind::Bind(Some(e.clone()), boxed))) | ||
}, | ||
other => { | ||
let msg = format!("unsupported default listener address: {other}"); | ||
let boxed = Box::<dyn std::error::Error + Send + Sync>::from(msg); | ||
Err(Error::new(ErrorKind::Bind(Some(other.clone()), boxed))) | ||
let endpoint = config.address; | ||
match endpoint { | ||
#[cfg(feature = "tls")] | ||
Endpoint::Tcp(_) if config.tls.is_some() => { | ||
let listener = <TlsListener<TcpListener> as Bind<_>>::bind(rocket) | ||
.map_err(|e| ErrorKind::Bind(Some(endpoint), Box::new(e))) | ||
.await?; | ||
|
||
Ok(Left(Left(listener))) | ||
} | ||
} | ||
} | ||
Endpoint::Tcp(_) => { | ||
let listener = <TcpListener as Bind<_>>::bind(rocket) | ||
.map_err(|e| ErrorKind::Bind(Some(endpoint), Box::new(e))) | ||
.await?; | ||
|
||
pub(crate) fn tls_bindable<T>(&self, inner: T) -> TlsBindable<T> { | ||
#[cfg(feature = "tls")] | ||
if let Some(tls) = self.tls.clone() { | ||
return TlsBindable::Left(super::tls::TlsBindable { inner, tls }); | ||
} | ||
Ok(Right(Left(listener))) | ||
} | ||
#[cfg(all(unix, feature = "tls"))] | ||
Endpoint::Unix(_) if config.tls.is_some() => { | ||
let listener = <TlsListener<UnixListener> as Bind<_>>::bind(rocket) | ||
.map_err(|e| ErrorKind::Bind(Some(endpoint), Box::new(e))) | ||
.await?; | ||
|
||
Ok(Left(Right(listener))) | ||
} | ||
#[cfg(unix)] | ||
Endpoint::Unix(_) => { | ||
let listener = <UnixListener as Bind<_>>::bind(rocket) | ||
.map_err(|e| ErrorKind::Bind(Some(endpoint), Box::new(e))) | ||
.await?; | ||
|
||
TlsBindable::Right(inner) | ||
Ok(Right(Right(listener))) | ||
} | ||
_ => { | ||
let msg = format!("unsupported bind endpoint: {endpoint}"); | ||
let error = Box::<dyn std::error::Error + Send + Sync>::from(msg); | ||
Err(ErrorKind::Bind(Some(endpoint), error).into()) | ||
} | ||
} | ||
} | ||
|
||
pub fn bindable(&self) -> Result<impl Bindable, crate::Error> { | ||
self.base_bindable() | ||
.map(|b| b.map_either(|b| self.tls_bindable(b), |b| self.tls_bindable(b))) | ||
fn bind_endpoint(rocket: &&'r Rocket<Ignite>) -> Option<Endpoint> { | ||
let endpoint: Option<Endpoint> = rocket.figment().extract_inner("endpoint").ok()?; | ||
endpoint | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.