Skip to content

Commit

Permalink
all servers minor feature: add support for Config::with_prebound_server
Browse files Browse the repository at this point in the history
  • Loading branch information
jbr committed Sep 13, 2023
1 parent 7fd3b60 commit aa157bd
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 12 deletions.
2 changes: 1 addition & 1 deletion async-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async fn main() {
use std::future::Future;

use trillium::Handler;
pub use trillium_server_common::{CloneCounterObserver, Stopper};
pub use trillium_server_common::{Binding, CloneCounterObserver, Stopper};

mod client;
pub use client::ClientConfig;
Expand Down
10 changes: 10 additions & 0 deletions async-std/src/server/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ use trillium_server_common::Server;
/// Tcp-only Trillium server for Async-std
#[derive(Debug)]
pub struct AsyncStdServer(TcpListener);
impl From<TcpListener> for AsyncStdServer {
fn from(value: TcpListener) -> Self {
Self(value)
}
}
impl From<std::net::TcpListener> for AsyncStdServer {
fn from(value: std::net::TcpListener) -> Self {
TcpListener::from(value).into()
}
}

impl Server for AsyncStdServer {
type Transport = AsyncStdTransport<TcpStream>;
Expand Down
21 changes: 21 additions & 0 deletions async-std/src/server/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,27 @@ use trillium_server_common::{
/// Tcp/Unix Trillium server adapter for Async-Std
#[derive(Debug)]
pub struct AsyncStdServer(Binding<TcpListener, UnixListener>);
impl From<TcpListener> for AsyncStdServer {
fn from(value: TcpListener) -> Self {
Self(Tcp(value))
}
}

impl From<UnixListener> for AsyncStdServer {
fn from(value: UnixListener) -> Self {
Self(Unix(value))
}
}
impl From<std::net::TcpListener> for AsyncStdServer {
fn from(value: std::net::TcpListener) -> Self {
TcpListener::from(value).into()
}
}
impl From<std::os::unix::net::UnixListener> for AsyncStdServer {
fn from(value: std::os::unix::net::UnixListener) -> Self {
UnixListener::from(value).into()
}
}

#[cfg(unix)]
impl Server for AsyncStdServer {
Expand Down
56 changes: 52 additions & 4 deletions server-common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ pub struct Config<ServerType, AcceptorType> {
pub(crate) max_connections: Option<usize>,
pub(crate) info: Arc<AsyncCell<Info>>,
pub(crate) completion_future: CompletionFuture,
server: PhantomData<ServerType>,
pub(crate) binding: Option<ServerType>,
pub(crate) server: PhantomData<ServerType>,
}

impl<ServerType, AcceptorType> Config<ServerType, AcceptorType>
Expand Down Expand Up @@ -119,6 +120,9 @@ where
/// Configures the server to listen on this port. The default is
/// the PORT environment variable or 8080
pub fn with_port(mut self, port: u16) -> Self {
if self.binding.is_some() {
eprintln!("constructing a config with both a port and a pre-bound listener will ignore the port. this may be a panic in the future");
}
self.port = Some(port);
self
}
Expand All @@ -127,6 +131,9 @@ where
/// address. The default is the HOST environment variable or
/// "localhost"
pub fn with_host(mut self, host: &str) -> Self {
if self.binding.is_some() {
eprintln!("constructing a config with both a host and a pre-bound listener will ignore the host. this may be a panic in the future");
}
self.host = Some(host.into());
self
}
Expand All @@ -144,6 +151,10 @@ where
/// <https://en.wikipedia.org/wiki/Nagle%27s_algorithm> for more
/// information on this setting.
pub fn with_nodelay(mut self) -> Self {
if self.binding.is_some() {
eprintln!("constructing a config with both nodelay and a pre-bound listener will ignore the nodelay setting. this may be a panic in the future");
}

self.nodelay = true;
self
}
Expand Down Expand Up @@ -173,6 +184,7 @@ where
max_connections: self.max_connections,
info: self.info,
completion_future: self.completion_future,
binding: self.binding,
}
}

Expand All @@ -198,17 +210,51 @@ where
self.max_connections = max_connections;
self
}

/// Use a pre-bound transport stream as server.
///
/// The argument to this varies for different servers, but usually accepts the runtime's
/// TcpListener and, on unix platforms, the UnixListener.
///
/// ## Note well
///
/// Many of the other options on this config will be ignored if
/// you provide a listener. In particular, `host`, `port`, and
/// `nodelay` will be ignored. All of the other options will be
/// used.
///
/// Additionally, cloning this config will not clone the listener.
pub fn with_prebound_server(mut self, server: impl Into<ServerType>) -> Self {
if self.host.is_some() {
eprintln!("constructing a config with both a host and a pre-bound listener will ignore the host. this may be a panic in the future");
}

if self.port.is_some() {
eprintln!("constructing a config with both a port and a pre-bound listener will ignore the port. this may be a panic in the future");
}

if self.nodelay {
eprintln!("constructing a config with nodelay and a pre-bound listener will ignore nodelay. this may be a panic in the future");
}

self.binding = Some(server.into());
self
}
}

impl<ServerType> Config<ServerType, ()> {
impl<ServerType: ?Sized + Server> Config<ServerType, ()> {
/// build a new config with default acceptor
pub fn new() -> Self {
Self::default()
}
}

impl<ServerType, AcceptorType: Clone> Clone for Config<ServerType, AcceptorType> {
impl<ServerType: ?Sized + Server, AcceptorType: Clone> Clone for Config<ServerType, AcceptorType> {
fn clone(&self) -> Self {
if self.binding.is_some() {
eprintln!("cloning a Config with a pre-bound listener will not clone the listener. this may be a panic in the future.");
}

Self {
acceptor: self.acceptor.clone(),
port: self.port,
Expand All @@ -221,11 +267,12 @@ impl<ServerType, AcceptorType: Clone> Clone for Config<ServerType, AcceptorType>
max_connections: self.max_connections,
info: AsyncCell::shared(),
completion_future: CompletionFuture::new(),
binding: None,
}
}
}

impl<ServerType> Default for Config<ServerType, ()> {
impl<ServerType: ?Sized + Server> Default for Config<ServerType, ()> {
fn default() -> Self {
#[cfg(unix)]
let max_connections = {
Expand All @@ -252,6 +299,7 @@ impl<ServerType> Default for Config<ServerType, ()> {
max_connections,
info: AsyncCell::shared(),
completion_future: CompletionFuture::new(),
binding: None,
}
}
}
18 changes: 14 additions & 4 deletions server-common/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ pub trait Server: Sized + Send + Sync + 'static {
/// [`Server::listener_from_tcp`] and
/// [`Server::listener_from_unix`].
#[cfg(unix)]
fn build_listener<A>(config: &Config<Self, A>) -> Self
fn build_listener<A>(config: &mut Config<Self, A>) -> Self
where
A: Acceptor<Self::Transport>,
{
if let Some(listener) = config.binding.take() {
log::debug!("taking prebound listener");
return listener;
}

use std::os::unix::prelude::FromRawFd;
let host = config.host();
if host.starts_with(|c| c == '/' || c == '.' || c == '~') {
Expand All @@ -69,10 +74,15 @@ pub trait Server: Sized + Send + Sync + 'static {
/// implementations could potentially implement this directly. To
/// use this default logic, implement [`Server::listener_from_tcp`]
#[cfg(not(unix))]
fn build_listener<A>(config: &Config<Self, A>) -> Self
fn build_listener<A>(config: &mut Config<Self, A>) -> Self
where
A: Acceptor<Self::Transport>,
{
if let Some(listener) = config.binding.take() {
log::debug!("taking prebound listener");
return listener;
}

let tcp_listener = std::net::TcpListener::bind((config.host(), config.port())).unwrap();
tcp_listener.set_nonblocking(true).unwrap();
Self::listener_from_tcp(tcp_listener)
Expand Down Expand Up @@ -119,7 +129,7 @@ pub trait Server: Sized + Send + Sync + 'static {
/// implementation of this method contains the core logic of this
/// Trait.
fn run_async<A, H>(
config: Config<Self, A>,
mut config: Config<Self, A>,
mut handler: H,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>
where
Expand All @@ -135,7 +145,7 @@ pub trait Server: Sized + Send + Sync + 'static {
log::error!("signals handling not supported on windows yet");
}

let mut listener = Self::build_listener(&config);
let mut listener = Self::build_listener(&mut config);
let mut info = Self::info(&listener);
info.server_description_mut().push_str(Self::DESCRIPTION);
handler.init(&mut info).await;
Expand Down
2 changes: 1 addition & 1 deletion smol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ trillium_testing::with_server("ok", |url| async move {
*/

use trillium::Handler;
pub use trillium_server_common::{CloneCounterObserver, Stopper};
pub use trillium_server_common::{Binding, CloneCounterObserver, Stopper};

mod client;
pub use client::ClientConfig;
Expand Down
5 changes: 5 additions & 0 deletions smol/src/server/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ use trillium_server_common::Server;

#[derive(Debug)]
pub struct SmolServer(TcpListener);
impl From<TcpListener> for SmolServer {
fn from(value: TcpListener) -> Self {
Self(value)
}
}

impl Server for SmolServer {
type Transport = SmolTransport<TcpStream>;
Expand Down
10 changes: 10 additions & 0 deletions smol/src/server/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ use trillium_server_common::{

#[derive(Debug, Clone)]
pub struct SmolServer(Binding<TcpListener, UnixListener>);
impl From<TcpListener> for SmolServer {
fn from(value: TcpListener) -> Self {
Self(Tcp(value))
}
}
impl From<UnixListener> for SmolServer {
fn from(value: UnixListener) -> Self {
Self(Unix(value))
}
}

#[cfg(unix)]
impl Server for SmolServer {
Expand Down
2 changes: 1 addition & 1 deletion testing/src/runtimeless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl Server for RuntimelessServer {
})
}

fn build_listener<A>(config: &Config<Self, A>) -> Self
fn build_listener<A>(config: &mut Config<Self, A>) -> Self
where
A: Acceptor<Self::Transport>,
{
Expand Down
24 changes: 24 additions & 0 deletions tokio/examples/tokio_binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pub fn app() -> impl trillium::Handler {
|conn: trillium::Conn| async move {
let response = tokio::task::spawn(async {
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
"successfully spawned a task"
})
.await
.unwrap();
conn.ok(response)
}
}

#[tokio::main]
pub async fn main() {
env_logger::init();
let server = tokio::net::TcpListener::bind("localhost:8080")
.await
.unwrap();

trillium_tokio::config()
.with_prebound_server(server)
.run_async(app())
.await;
}
3 changes: 2 additions & 1 deletion tokio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ async fn main() {
use std::future::Future;

use trillium::Handler;
pub use trillium_server_common::{CloneCounterObserver, Stopper};

pub use trillium_server_common::{Binding, CloneCounterObserver, Stopper};

mod client;
pub use client::ClientConfig;
Expand Down
6 changes: 6 additions & 0 deletions tokio/src/server/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ use trillium_server_common::Server;
#[derive(Debug)]
pub struct TokioServer(TcpListener);

impl From<TcpListener> for TokioServer {
fn from(value: TcpListener) -> Self {
Self(value)
}
}

impl Server for TokioServer {
type Transport = TokioTransport<Compat<TcpStream>>;
const DESCRIPTION: &'static str = concat!(
Expand Down
12 changes: 12 additions & 0 deletions tokio/src/server/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ use trillium_server_common::{
#[derive(Debug)]
pub struct TokioServer(Binding<TcpListener, UnixListener>);

impl From<TcpListener> for TokioServer {
fn from(value: TcpListener) -> Self {
Self(Tcp(value))
}
}

impl From<UnixListener> for TokioServer {
fn from(value: UnixListener) -> Self {
Self(Unix(value))
}
}

impl Server for TokioServer {
type Transport = Binding<TokioTransport<Compat<TcpStream>>, TokioTransport<Compat<UnixStream>>>;
const DESCRIPTION: &'static str = concat!(
Expand Down

0 comments on commit aa157bd

Please sign in to comment.