Skip to content

Commit

Permalink
all servers minor feature: add support for Config::with_listener
Browse files Browse the repository at this point in the history
  • Loading branch information
jbr committed Apr 6, 2023
1 parent 3884ea9 commit 6df5c2f
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 11 deletions.
2 changes: 1 addition & 1 deletion async-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async fn main() {
*/

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

mod client;
pub use client::{ClientConfig, TcpConnector};
Expand Down
13 changes: 13 additions & 0 deletions server-common/src/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ pub enum Binding<T, U> {
Unix(U),
}

impl<T, U> Binding<T, U> {
/// constructs a new tcp variant
pub fn tcp(tcp: impl Into<T>) -> Self {
Self::Tcp(tcp.into())
}

#[cfg(unix)]
/// constructs a new unix variant
pub fn unix(unix: impl Into<U>) -> Self {
Self::Unix(unix.into())
}
}

impl<T: TryFrom<std::net::TcpListener>, U> TryFrom<std::net::TcpListener> for Binding<T, U> {
type Error = <T as TryFrom<std::net::TcpListener>>::Error;

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 @@ -54,7 +54,7 @@ In order to use this to _implement_ a trillium server, see
*/

#[derive(Debug)]
pub struct Config<ServerType: ?Sized, AcceptorType> {
pub struct Config<ServerType: Server + ?Sized, AcceptorType> {
pub(crate) acceptor: AcceptorType,
pub(crate) port: Option<u16>,
pub(crate) host: Option<String>,
Expand All @@ -63,6 +63,7 @@ pub struct Config<ServerType: ?Sized, AcceptorType> {
pub(crate) counter: CloneCounter,
pub(crate) register_signals: bool,
pub(crate) max_connections: Option<usize>,
pub(crate) binding: Option<ServerType::Listener>,
server: PhantomData<ServerType>,
}

Expand Down Expand Up @@ -93,6 +94,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 @@ -101,6 +105,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 @@ -118,6 +125,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 @@ -145,6 +156,7 @@ where
counter: self.counter,
register_signals: self.register_signals,
max_connections: self.max_connections,
binding: self.binding,
}
}

Expand All @@ -163,17 +175,51 @@ where
self.max_connections = max_connections;
self
}

/// Takes a pre-bound listener. The specific listener argument for
/// this will depend on the runtime adapter's server type. If it
/// accepts a [`Binding`], use [`Binding::tcp`] or
/// [`Binding::unix`] to construct your intended variant.
///
/// ## 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_listener(mut self, listener: ServerType::Listener) -> 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(listener);
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: ?Sized, 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 @@ -184,11 +230,12 @@ impl<ServerType: ?Sized, AcceptorType: Clone> Clone for Config<ServerType, Accep
counter: self.counter.clone(),
register_signals: self.register_signals,
max_connections: self.max_connections,
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 @@ -213,6 +260,7 @@ impl<ServerType> Default for Config<ServerType, ()> {
counter: CloneCounter::new(),
register_signals: cfg!(unix),
max_connections,
binding: None,
}
}
}
13 changes: 9 additions & 4 deletions server-common/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,15 @@ pub trait Server: Send + 'static {
/// [`Server::listener_from_tcp`] and
/// [`Server::listener_from_unix`].
#[cfg(unix)]
fn build_listener<A>(config: &Config<Self, A>) -> Self::Listener
fn build_listener<A>(config: &mut Config<Self, A>) -> Self::Listener
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 @@ -97,7 +102,7 @@ pub trait Server: Send + '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::Listener
fn build_listener<A>(config: &mut Config<Self, A>) -> Self::Listener
where
A: Acceptor<Self::Transport>,
{
Expand Down Expand Up @@ -147,7 +152,7 @@ pub trait Server: Send + '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 @@ -163,7 +168,7 @@ pub trait Server: Send + '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::Stopper;
pub use trillium_server_common::{Binding, Stopper};

mod client;
pub use client::{ClientConfig, TcpConnector};
Expand Down
26 changes: 26 additions & 0 deletions tokio/examples/tokio_binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use trillium_tokio::Binding;

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 listener = tokio::net::TcpListener::bind("localhost:8080")
.await
.unwrap();

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

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

mod client;
pub use client::{ClientConfig, TcpConnector};
Expand Down

0 comments on commit 6df5c2f

Please sign in to comment.