From e86e9575f119f2854f58486017364c8b9ffeb619 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Fri, 26 Jun 2020 20:37:58 -0700 Subject: [PATCH] variant with no ToListener for discussion --- Cargo.toml | 1 + src/listener/mod.rs | 21 +- src/listener/multi_listener.rs | 103 ++---- src/listener/parsed_listener.rs | 33 -- src/listener/tcp_listener.rs | 5 +- src/listener/to_listener.rs | 573 +++++++++++++++----------------- src/listener/unix_listener.rs | 5 +- src/server.rs | 6 +- 8 files changed, 303 insertions(+), 444 deletions(-) delete mode 100644 src/listener/parsed_listener.rs diff --git a/Cargo.toml b/Cargo.toml index 87e70b812..cd443523f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ kv-log-macro = "1.0.4" serde = "1.0.102" serde_json = "1.0.41" route-recognizer = "0.2.0" +futures = "0.3.5" [dev-dependencies] async-std = { version = "1.6.0", features = ["unstable", "attributes"] } diff --git a/src/listener/mod.rs b/src/listener/mod.rs index 29dd18f9a..c247405bc 100644 --- a/src/listener/mod.rs +++ b/src/listener/mod.rs @@ -1,37 +1,20 @@ //! Types that represent HTTP transports and binding mod multi_listener; -mod parsed_listener; mod tcp_listener; mod to_listener; #[cfg(unix)] mod unix_listener; - -use crate::utils::BoxFuture; -use crate::Server; use async_std::io; pub use multi_listener::MultiListener; -pub use to_listener::ToListener; +pub use to_listener::Listener; +pub(crate) use to_listener::ResultFuture; -pub(crate) use parsed_listener::ParsedListener; pub(crate) use tcp_listener::TcpListener; #[cfg(unix)] pub(crate) use unix_listener::UnixListener; -/// The Listener trait represents an implementation of http transport -/// for a tide application. In order to provide a Listener to tide, -/// you will also need to implement at least one [`ToListener`](crate::listener::ToListener) that -/// outputs your Listener type. -pub trait Listener: - std::fmt::Debug + std::fmt::Display + Send + Sync + 'static -{ - /// This is the primary entrypoint for the Listener trait. listen - /// is called exactly once, and is expected to spawn tasks for - /// each incoming connection. - fn listen<'a>(&'a mut self, app: Server) -> BoxFuture<'a, io::Result<()>>; -} - pub(crate) fn is_transient_error(e: &io::Error) -> bool { e.kind() == io::ErrorKind::ConnectionRefused || e.kind() == io::ErrorKind::ConnectionAborted diff --git a/src/listener/multi_listener.rs b/src/listener/multi_listener.rs index e5e38d1e6..59e0054ea 100644 --- a/src/listener/multi_listener.rs +++ b/src/listener/multi_listener.rs @@ -1,11 +1,8 @@ -use crate::listener::{Listener, ToListener}; -use crate::utils::BoxFuture; +use crate::listener::{Listener, ResultFuture}; use crate::Server; +use async_std::{io, task}; -use std::fmt::{self, Debug, Display, Formatter}; - -use async_std::io; -use async_std::prelude::*; +use futures::stream::{futures_unordered::FuturesUnordered, StreamExt}; /// MultiListener allows tide to listen on any number of transports /// simultaneously (such as tcp ports, unix sockets, or tls). @@ -19,10 +16,10 @@ use async_std::prelude::*; /// app.at("/").get(|_| async { Ok("Hello, world!") }); /// /// let mut multi = tide::listener::MultiListener::new(); -/// multi.add("127.0.0.1:8000")?; -/// multi.add(async_std::net::TcpListener::bind("127.0.0.1:8001").await?)?; +/// multi.bind("127.0.0.1:8000")?; +/// multi.bind(async_std::net::TcpListener::bind("127.0.0.1:8001").await?)?; /// # if cfg!(unix) { -/// multi.add("unix://unix.socket")?; +/// multi.bind("unix://unix.socket")?; /// # } /// /// # if false { @@ -33,84 +30,34 @@ use async_std::prelude::*; ///} ///``` -#[derive(Default)] -pub struct MultiListener(Vec>>); +pub struct MultiListener( + Server, + FuturesUnordered>>, +); -impl MultiListener { - /// creates a new MultiListener - pub fn new() -> Self { - Self(vec![]) +impl std::fmt::Debug for MultiListener { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MultiListener").finish() } +} - /// Adds any [`ToListener`](crate::listener::ToListener) to this - /// MultiListener. An error result represents a failure to convert - /// the [`ToListener`](crate::listener::ToListener) into a - /// [`Listener`](crate::listener::Listener). - /// - /// ```rust - /// # fn main() -> std::io::Result<()> { - /// let mut multi = tide::listener::MultiListener::new(); - /// multi.add("127.0.0.1:8000")?; - /// multi.add(("localhost", 8001))?; - /// multi.add(std::net::TcpListener::bind(("localhost", 8002))?)?; - /// # std::mem::drop(tide::new().listen(multi)); // for the State generic - /// # Ok(()) } - /// ``` - pub fn add>(&mut self, listener: TL) -> io::Result<()> { - self.0.push(Box::new(listener.to_listener()?)); - Ok(()) +impl MultiListener { + pub fn new(app: Server) -> Self { + Self(app, FuturesUnordered::new()) } - /// `MultiListener::with_listener` allows for chained construction of a MultiListener: - /// ```rust,no_run - /// # use tide::listener::MultiListener; - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async move { - /// # let app = tide::new(); - /// app.listen( - /// MultiListener::new() - /// .with_listener("127.0.0.1:8080") - /// .with_listener(async_std::net::TcpListener::bind("127.0.0.1:8081").await?), - /// ).await?; - /// # Ok(()) }) } - pub fn with_listener>(mut self, listener: TL) -> Self { - self.add(listener).expect("Unable to add listener"); - self + pub fn bind + Send + Sync + 'static>(&mut self, listener: TL) { + self.1.push(task::spawn(listener.listen(self.0.clone()))); } } impl Listener for MultiListener { - fn listen<'a>(&'a mut self, app: Server) -> BoxFuture<'a, io::Result<()>> { - let mut fut: Option>> = None; - - for listener in self.0.iter_mut() { - let app = app.clone(); - let listened = listener.listen(app); - if let Some(f) = fut { - fut = Some(Box::pin(f.race(listened))); - } else { - fut = Some(Box::pin(listened)); + fn listen(mut self, _: Server) -> ResultFuture { + Box::pin(async move { + while let Some(result) = self.1.next().await { + result?; } - } - - fut.expect("at least one listener must be provided to a MultiListener") - } -} - -impl Debug for MultiListener { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - -impl Display for MultiListener { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let string = self - .0 - .iter() - .map(|l| l.to_string()) - .collect::>() - .join(", "); - - writeln!(f, "{}", string) + Ok(()) + }) } } diff --git a/src/listener/parsed_listener.rs b/src/listener/parsed_listener.rs deleted file mode 100644 index 94796af2c..000000000 --- a/src/listener/parsed_listener.rs +++ /dev/null @@ -1,33 +0,0 @@ -#[cfg(unix)] -use super::UnixListener; -use super::{Listener, TcpListener}; -use crate::{utils::BoxFuture, Server}; -use async_std::io; -use std::fmt::{self, Display, Formatter}; - -#[derive(Debug)] -pub enum ParsedListener { - #[cfg(unix)] - Unix(UnixListener), - Tcp(TcpListener), -} - -impl Display for ParsedListener { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - #[cfg(unix)] - Self::Unix(u) => write!(f, "{}", u), - Self::Tcp(t) => write!(f, "{}", t), - } - } -} - -impl Listener for ParsedListener { - fn listen<'a>(&'a mut self, app: Server) -> BoxFuture<'a, io::Result<()>> { - match self { - #[cfg(unix)] - Self::Unix(u) => u.listen(app), - Self::Tcp(t) => t.listen(app), - } - } -} diff --git a/src/listener/tcp_listener.rs b/src/listener/tcp_listener.rs index e452bbc50..0fad7ea69 100644 --- a/src/listener/tcp_listener.rs +++ b/src/listener/tcp_listener.rs @@ -1,7 +1,6 @@ use super::is_transient_error; -use crate::listener::Listener; -use crate::utils::BoxFuture; +use crate::listener::{Listener, ResultFuture}; use crate::{log, Server}; use std::fmt::{self, Display, Formatter}; @@ -62,7 +61,7 @@ fn handle_tcp(app: Server, stream: TcpStrea } impl Listener for TcpListener { - fn listen<'a>(&'a mut self, app: Server) -> BoxFuture<'a, async_std::io::Result<()>> { + fn listen(mut self, app: Server) -> ResultFuture { Box::pin(async move { self.connect().await?; let listener = self.listener()?; diff --git a/src/listener/to_listener.rs b/src/listener/to_listener.rs index 3a60f92da..0495ab66f 100644 --- a/src/listener/to_listener.rs +++ b/src/listener/to_listener.rs @@ -1,7 +1,7 @@ -#[cfg(unix)] use super::UnixListener; -use super::{Listener, MultiListener, ParsedListener, TcpListener}; +use super::{MultiListener, TcpListener}; use crate::http::url::Url; +use crate::Server; use async_std::io; use std::net::ToSocketAddrs; @@ -53,353 +53,316 @@ use std::net::ToSocketAddrs; /// # Other implementations /// See below for additional provided implementations of ToListener. -pub trait ToListener { - type Listener: Listener; - /// Transform self into a - /// [`Listener`](crate::listener::Listener). Unless self is - /// already bound/connected to the underlying io, converting to a - /// listener does not initiate a connection. An Err return - /// indicates an unsuccessful conversion to a listener, not an - /// unsuccessful bind attempt. - fn to_listener(self) -> io::Result; +pub(crate) type ResultFuture = + std::pin::Pin> + Send>>; + +pub trait Listener { + fn listen(self, app: Server) -> ResultFuture; } -impl ToListener for Url { - type Listener = ParsedListener; - - fn to_listener(self) -> io::Result { - match self.scheme() { - "unix" | "file" | "http+unix" => { - #[cfg(unix)] - { - let path = std::path::PathBuf::from(format!( - "{}{}", - self.domain().unwrap_or_default(), - self.path() - )); - - Ok(ParsedListener::Unix(UnixListener::from_path(path))) +impl Listener for Url { + fn listen(self, app: Server) -> ResultFuture { + Box::pin(async move { + match self.scheme() { + "unix" | "file" | "http+unix" => { + #[cfg(unix)] + { + let path = std::path::PathBuf::from(format!( + "{}{}", + self.domain().unwrap_or_default(), + self.path() + )); + + UnixListener::from_path(path).listen(app).await + } + + #[cfg(not(unix))] + { + Err(io::Error::new( + io::ErrorKind::Other, + "Unix sockets not supported on this platform", + )) + } } - #[cfg(not(unix))] - { - Err(io::Error::new( - io::ErrorKind::Other, - "Unix sockets not supported on this platform", - )) + "tcp" | "http" => { + TcpListener::from_addrs(self.socket_addrs(|| Some(80))?) + .listen(app) + .await } - } - "tcp" | "http" => Ok(ParsedListener::Tcp(TcpListener::from_addrs( - self.socket_addrs(|| Some(80))?, - ))), + "tls" | "ssl" | "https" => Err(io::Error::new( + io::ErrorKind::Other, + "parsing TLS listeners not supported yet", + )), - "tls" | "ssl" | "https" => Err(io::Error::new( - io::ErrorKind::Other, - "parsing TLS listeners not supported yet", - )), - - _ => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "unrecognized url scheme", - )), - } + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "unrecognized url scheme", + )), + } + }) } } -impl ToListener for String { - type Listener = ParsedListener; - fn to_listener(self) -> io::Result { - ToListener::::to_listener(self.as_str()) +impl Listener for String { + fn listen(self, app: Server) -> ResultFuture { + Box::pin(async move { + if let Ok(socket_addrs) = self.to_socket_addrs() { + return TcpListener::from_addrs(socket_addrs.collect()) + .listen(app) + .await; + } + + match Url::parse(&self) { + Err(_) => Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("unable to parse listener from `{}`", self), + )), + Ok(url) => Listener::::listen(url, app).await, + } + }) } } -impl ToListener for &str { - type Listener = ParsedListener; - - fn to_listener(self) -> io::Result { - self.to_socket_addrs() - .and_then(|socket_addrs| { - Ok(ParsedListener::Tcp(TcpListener::from_addrs( - socket_addrs.collect(), - ))) - }) - .or_else(|_| { - Url::parse(self) - .map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - format!("unable to parse listener from `{}`", self), - ) - }) - .and_then(ToListener::::to_listener) - }) +impl Listener for &'static str { + fn listen(self, app: Server) -> ResultFuture { + Listener::::listen(self.to_owned(), app) } } #[cfg(unix)] -impl ToListener for async_std::path::PathBuf { - type Listener = UnixListener; - fn to_listener(self) -> io::Result { - Ok(UnixListener::from_path(self)) +impl Listener for async_std::path::PathBuf { + fn listen(self, app: Server) -> ResultFuture { + UnixListener::from_path(self.clone()).listen(app) } } #[cfg(unix)] -impl ToListener for std::path::PathBuf { - type Listener = UnixListener; - fn to_listener(self) -> io::Result { - Ok(UnixListener::from_path(self)) +impl Listener for std::path::PathBuf { + fn listen(self, app: Server) -> ResultFuture { + UnixListener::from_path(self.clone()).listen(app) } } -impl ToListener for async_std::net::TcpListener { - type Listener = TcpListener; - fn to_listener(self) -> io::Result { - Ok(TcpListener::from_listener(self)) +impl Listener for async_std::net::TcpListener { + fn listen(self, app: Server) -> ResultFuture { + TcpListener::from_listener(self).listen(app) } } -impl ToListener for std::net::TcpListener { - type Listener = TcpListener; - fn to_listener(self) -> io::Result { - Ok(TcpListener::from_listener(self)) +impl Listener for std::net::TcpListener { + fn listen(self, app: Server) -> ResultFuture { + TcpListener::from_listener(self).listen(app) } } -impl ToListener for (&str, u16) { - type Listener = TcpListener; - - fn to_listener(self) -> io::Result { - Ok(TcpListener::from_addrs(self.to_socket_addrs()?.collect())) +impl Listener for (&'static str, u16) { + fn listen(self, app: Server) -> ResultFuture { + Box::pin(async move { + TcpListener::from_addrs(self.to_socket_addrs()?.collect()) + .listen(app) + .await + }) } } #[cfg(unix)] -impl ToListener for async_std::os::unix::net::UnixListener { - type Listener = UnixListener; - fn to_listener(self) -> io::Result { - Ok(UnixListener::from_listener(self)) +impl Listener for async_std::os::unix::net::UnixListener { + fn listen(self, app: Server) -> ResultFuture { + UnixListener::from_listener(self).listen(app) } } #[cfg(unix)] -impl ToListener for std::os::unix::net::UnixListener { - type Listener = UnixListener; - fn to_listener(self) -> io::Result { - Ok(UnixListener::from_listener(self)) +impl Listener for std::os::unix::net::UnixListener { + fn listen(self, app: Server) -> ResultFuture { + UnixListener::from_listener(self).listen(app) } } -impl ToListener for TcpListener { - type Listener = Self; - fn to_listener(self) -> io::Result { - Ok(self) +impl Listener for std::net::SocketAddr { + fn listen(self, app: Server) -> ResultFuture { + TcpListener::from_addrs(vec![self]).listen(app) } } -#[cfg(unix)] -impl ToListener for UnixListener { - type Listener = Self; - fn to_listener(self) -> io::Result { - Ok(self) - } -} - -impl ToListener for MultiListener { - type Listener = Self; - fn to_listener(self) -> io::Result { - Ok(self) - } -} - -impl ToListener for ParsedListener { - type Listener = Self; - fn to_listener(self) -> io::Result { - Ok(self) - } -} - -impl ToListener for std::net::SocketAddr { - type Listener = TcpListener; - fn to_listener(self) -> io::Result { - Ok(TcpListener::from_addrs(vec![self])) - } -} - -impl, State: Send + Sync + 'static> ToListener for Vec { - type Listener = MultiListener; - fn to_listener(self) -> io::Result { - let mut multi = MultiListener::new(); - for listener in self { - multi.add(listener)?; - } - Ok(multi) +impl + Send + Sync + 'static, State: Send + Sync + 'static> Listener + for Vec +{ + fn listen(mut self, app: Server) -> ResultFuture { + Box::pin(async move { + let mut multi = MultiListener::new(app.clone()); + for listener in self.drain(..) { + multi.bind(listener); + } + multi.listen(app).await + }) } } -#[cfg(test)] -mod parse_tests { - use super::*; - - fn listen>(listener: TL) -> io::Result { - listener.to_listener() - } - - #[test] - fn url_to_tcp_listener() { - let listener = listen(Url::parse("http://localhost:8000").unwrap()).unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert!(listener.to_string().contains("http://127.0.0.1:8000")); - - let listener = listen(Url::parse("tcp://localhost:8000").unwrap()).unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert!(listener.to_string().contains("http://127.0.0.1:8000")); - - let listener = listen(Url::parse("http://127.0.0.1").unwrap()).unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert_eq!(listener.to_string(), "http://127.0.0.1:80"); - } - - #[test] - fn str_url_to_tcp_listener() { - let listener = listen("tcp://localhost:8000").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert!(listener.to_string().contains("http://127.0.0.1:8000")); - - let listener = listen("tcp://localhost:8000").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert!(listener.to_string().contains("http://127.0.0.1:8000")); - - let listener = listen("tcp://127.0.0.1").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert_eq!(listener.to_string(), "http://127.0.0.1:80"); - } - - #[cfg(unix)] - mod unix { - use super::*; - - #[test] - fn str_url_to_unix_listener() { - let listener = listen("unix:///var/run/tide/socket").unwrap(); - assert!(matches!( - listener, - ParsedListener::Unix(UnixListener::FromPath(_, None)) - )); - assert_eq!("unix:///var/run/tide/socket", listener.to_string()); - - let listener = listen("unix://./socket").unwrap(); - assert!(matches!( - listener, - ParsedListener::Unix(UnixListener::FromPath(_, None)) - )); - assert_eq!("unix://./socket", listener.to_string()); - - let listener = listen("unix://socket").unwrap(); - assert!(matches!( - listener, - ParsedListener::Unix(UnixListener::FromPath(_, None)) - )); - assert_eq!("unix://socket", listener.to_string()); - } - - #[test] - fn colon_port_does_not_work() { - let err = listen(":3000").unwrap_err().to_string(); - assert_eq!(err, "unable to parse listener from `:3000`"); - } - } - - #[cfg(not(unix))] - mod not_unix { - use super::*; - #[test] - fn str_url_to_unix_listener() { - let err = listen("unix:///var/run/tide/socket").unwrap_err(); - assert_eq!( - err.to_string(), - "Unix sockets not supported on this platform" - ); - } - - #[test] - fn colon_port_works() { - let listener = listen(":3000").unwrap(); - assert!(listener.to_string().ends_with(":3000")); - assert!(listener.to_string().starts_with("http://")); - } - } - - #[test] - fn str_tls_parse_and_url() { - let err = listen("tls://localhost:443").unwrap_err(); - assert_eq!(err.to_string(), "parsing TLS listeners not supported yet"); - - let err = listen(Url::parse("https://localhost:443").unwrap()).unwrap_err(); - assert_eq!(err.to_string(), "parsing TLS listeners not supported yet"); - } - - #[test] - fn str_unknown_scheme() { - let err = listen("pigeon://localhost:443").unwrap_err(); - assert_eq!(err.to_string(), "unrecognized url scheme"); - - let err = listen(Url::parse("pigeon:///localhost:443").unwrap()).unwrap_err(); - assert_eq!(err.to_string(), "unrecognized url scheme"); - } - - #[test] - fn str_to_socket_addr() { - let listener = listen("127.0.0.1:1312").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert_eq!("http://127.0.0.1:1312", listener.to_string()); - - let listener = listen("[::1]:1312").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert_eq!("http://[::1]:1312", listener.to_string()); - - let listener = listen("localhost:3000").unwrap(); - assert!(matches!( - listener, - ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) - )); - assert!(listener.to_string().contains(":3000")); - } - - #[test] - fn invalid_str_input() { - let err = listen("hello world").unwrap_err(); - assert_eq!( - err.to_string(), - "unable to parse listener from `hello world`" - ); - - let err = listen("🌊").unwrap_err(); - assert_eq!(err.to_string(), "unable to parse listener from `🌊`"); - } -} +// #[cfg(test)] +// mod parse_tests { +// use super::*; + +// fn listen>(listener: TL) -> io::Result { +// listener.listen() +// } + +// #[test] +// fn url_to_tcp_listener() { +// let listener = listen(Url::parse("http://localhost:8000").unwrap()).unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert!(listener.to_string().contains("http://127.0.0.1:8000")); + +// let listener = listen(Url::parse("tcp://localhost:8000").unwrap()).unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert!(listener.to_string().contains("http://127.0.0.1:8000")); + +// let listener = listen(Url::parse("http://127.0.0.1").unwrap()).unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert_eq!(listener.to_string(), "http://127.0.0.1:80"); +// } + +// #[test] +// fn str_url_to_tcp_listener() { +// let listener = listen("tcp://localhost:8000").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert!(listener.to_string().contains("http://127.0.0.1:8000")); + +// let listener = listen("tcp://localhost:8000").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert!(listener.to_string().contains("http://127.0.0.1:8000")); + +// let listener = listen("tcp://127.0.0.1").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert_eq!(listener.to_string(), "http://127.0.0.1:80"); +// } + +// #[cfg(unix)] +// mod unix { +// use super::*; + +// #[test] +// fn str_url_to_unix_listener() { +// let listener = listen("unix:///var/run/tide/socket").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Unix(UnixListener::FromPath(_, None)) +// )); +// assert_eq!("unix:///var/run/tide/socket", listener.to_string()); + +// let listener = listen("unix://./socket").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Unix(UnixListener::FromPath(_, None)) +// )); +// assert_eq!("unix://./socket", listener.to_string()); + +// let listener = listen("unix://socket").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Unix(UnixListener::FromPath(_, None)) +// )); +// assert_eq!("unix://socket", listener.to_string()); +// } + +// #[test] +// fn colon_port_does_not_work() { +// let err = listen(":3000").unwrap_err().to_string(); +// assert_eq!(err, "unable to parse listener from `:3000`"); +// } +// } + +// #[cfg(not(unix))] +// mod not_unix { +// use super::*; +// #[test] +// fn str_url_to_unix_listener() { +// let err = listen("unix:///var/run/tide/socket").unwrap_err(); +// assert_eq!( +// err.to_string(), +// "Unix sockets not supported on this platform" +// ); +// } + +// #[test] +// fn colon_port_works() { +// let listener = listen(":3000").unwrap(); +// assert!(listener.to_string().ends_with(":3000")); +// assert!(listener.to_string().starts_with("http://")); +// } +// } + +// #[test] +// fn str_tls_parse_and_url() { +// let err = listen("tls://localhost:443").unwrap_err(); +// assert_eq!(err.to_string(), "parsing TLS listeners not supported yet"); + +// let err = listen(Url::parse("https://localhost:443").unwrap()).unwrap_err(); +// assert_eq!(err.to_string(), "parsing TLS listeners not supported yet"); +// } + +// #[test] +// fn str_unknown_scheme() { +// let err = listen("pigeon://localhost:443").unwrap_err(); +// assert_eq!(err.to_string(), "unrecognized url scheme"); + +// let err = listen(Url::parse("pigeon:///localhost:443").unwrap()).unwrap_err(); +// assert_eq!(err.to_string(), "unrecognized url scheme"); +// } + +// #[test] +// fn str_to_socket_addr() { +// let listener = listen("127.0.0.1:1312").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert_eq!("http://127.0.0.1:1312", listener.to_string()); + +// let listener = listen("[::1]:1312").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert_eq!("http://[::1]:1312", listener.to_string()); + +// let listener = listen("localhost:3000").unwrap(); +// assert!(matches!( +// listener, +// ParsedListener::Tcp(TcpListener::FromAddrs(_, None)) +// )); +// assert!(listener.to_string().contains(":3000")); +// } + +// #[test] +// fn invalid_str_input() { +// let err = listen("hello world").unwrap_err(); +// assert_eq!( +// err.to_string(), +// "unable to parse listener from `hello world`" +// ); + +// let err = listen("🌊").unwrap_err(); +// assert_eq!(err.to_string(), "unable to parse listener from `🌊`"); +// } +// } diff --git a/src/listener/unix_listener.rs b/src/listener/unix_listener.rs index 0dea7b8be..18a1522f3 100644 --- a/src/listener/unix_listener.rs +++ b/src/listener/unix_listener.rs @@ -1,7 +1,6 @@ use super::is_transient_error; -use crate::listener::Listener; -use crate::utils::BoxFuture; +use crate::listener::{Listener, ResultFuture}; use crate::{log, Server}; use std::fmt::{self, Display, Formatter}; @@ -72,7 +71,7 @@ fn handle_unix(app: Server, stream: UnixStr } impl Listener for UnixListener { - fn listen<'a>(&'a mut self, app: Server) -> BoxFuture<'a, io::Result<()>> { + fn listen(mut self, app: Server) -> ResultFuture { Box::pin(async move { self.connect().await?; crate::log::info!("listening on {}", self); diff --git a/src/server.rs b/src/server.rs index 4ba05f0ef..c0994fa3d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,7 +4,7 @@ use async_std::io; use async_std::sync::Arc; use crate::cookies; -use crate::listener::{Listener, ToListener}; +use crate::listener::Listener; use crate::log; use crate::middleware::{Middleware, Next}; use crate::router::{Router, Selection}; @@ -175,8 +175,8 @@ impl Server { } /// Asynchronously serve the app with the supplied listener. For more details, see [Listener] and [ToListener] - pub async fn listen>(self, listener: TL) -> io::Result<()> { - listener.to_listener()?.listen(self).await + pub async fn listen>(self, listener: TL) -> io::Result<()> { + listener.listen(self).await } /// Respond to a `Request` with a `Response`.