feat(lib): convert to use tokio 0.1

BREAKING CHANGE: All uses of `Handle` now need to be new-tokio `Handle`.

Co-authored-by: Sean McArthur <sean@seanmonstar.com>
This commit is contained in:
Sam Reis
2018-03-15 10:46:03 +11:00
committed by Sean McArthur
parent 8c52c2dfd3
commit 27b8db3af8
23 changed files with 680 additions and 505 deletions

View File

@@ -6,20 +6,21 @@
pub mod conn;
mod service;
use std::cell::RefCell;
use std::fmt;
use std::io;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::rc::{Rc, Weak};
use std::net::{SocketAddr, TcpListener as StdTcpListener};
use std::sync::{Arc, Mutex, Weak};
use std::time::Duration;
use futures::task::{self, Task};
use futures::future::{self};
use futures::{Future, Stream, Poll, Async};
use futures_timer::Delay;
use http::{Request, Response};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio::reactor::{Core, Handle, Timeout};
use tokio::spawn;
use tokio::reactor::Handle;
use tokio::net::TcpListener;
pub use tokio_service::{NewService, Service};
@@ -54,7 +55,7 @@ where
{
protocol: Http<B::Data>,
new_service: S,
reactor: Core,
handle: Handle,
listener: TcpListener,
shutdown_timeout: Duration,
}
@@ -81,14 +82,25 @@ pub struct SpawnAll<I, S, E> {
/// A stream of connections from binding to an address.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct AddrIncoming {
addr: SocketAddr,
keep_alive_timeout: Option<Duration>,
listener: TcpListener,
handle: Handle,
sleep_on_errors: bool,
timeout: Option<Timeout>,
timeout: Option<Delay>,
}
impl fmt::Debug for AddrIncoming {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AddrIncoming")
.field("addr", &self.addr)
.field("keep_alive_timeout", &self.keep_alive_timeout)
.field("listener", &self.listener)
.field("handle", &self.handle)
.field("sleep_on_errors", &self.sleep_on_errors)
.finish()
}
}
// ===== impl Http =====
@@ -156,19 +168,39 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
where S: NewService<Request = Request<Body>, Response = Response<Bd>, Error = ::Error> + 'static,
Bd: Entity<Data=B, Error=::Error>,
{
let core = try!(Core::new());
let handle = core.handle();
let listener = try!(TcpListener::bind(addr, &handle));
let handle = Handle::current();
let std_listener = StdTcpListener::bind(addr)?;
let listener = try!(TcpListener::from_std(std_listener, &handle));
Ok(Server {
new_service: new_service,
reactor: core,
handle: handle,
listener: listener,
protocol: self.clone(),
shutdown_timeout: Duration::new(1, 0),
})
}
/// Bind the provided `addr` and return a server with the default `Handle`.
///
/// This is method will bind the `addr` provided with a new TCP listener ready
/// to accept connections. Each connection will be processed with the
/// `new_service` object provided as well, creating a new service per
/// connection.
pub fn serve_addr<S, Bd>(&self, addr: &SocketAddr, new_service: S) -> ::Result<Serve<AddrIncoming, S>>
where S: NewService<Request = Request<Body>, Response = Response<Bd>, Error = ::Error>,
Bd: Entity<Data=B, Error=::Error>,
{
let handle = Handle::current();
let std_listener = StdTcpListener::bind(addr)?;
let listener = TcpListener::from_std(std_listener, &handle)?;
let mut incoming = AddrIncoming::new(listener, handle.clone(), self.sleep_on_errors)?;
if self.keep_alive {
incoming.set_keepalive(Some(Duration::from_secs(90)));
}
Ok(self.serve_incoming(incoming, new_service))
}
/// Bind the provided `addr` and return a server with a shared `Core`.
///
/// This method allows the ability to share a `Core` with multiple servers.
@@ -181,7 +213,8 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
where S: NewService<Request = Request<Body>, Response = Response<Bd>, Error = ::Error>,
Bd: Entity<Data=B, Error=::Error>,
{
let listener = TcpListener::bind(addr, &handle)?;
let std_listener = StdTcpListener::bind(addr)?;
let listener = TcpListener::from_std(std_listener, &handle)?;
let mut incoming = AddrIncoming::new(listener, handle.clone(), self.sleep_on_errors)?;
if self.keep_alive {
incoming.set_keepalive(Some(Duration::from_secs(90)));
@@ -221,17 +254,18 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
/// ```
/// # extern crate futures;
/// # extern crate hyper;
/// # extern crate tokio_core;
/// # extern crate tokio;
/// # extern crate tokio_io;
/// # use futures::Future;
/// # use hyper::{Body, Request, Response};
/// # use hyper::server::{Http, Service};
/// # use tokio_io::{AsyncRead, AsyncWrite};
/// # use tokio_core::reactor::Handle;
/// # fn run<I, S>(some_io: I, some_service: S, some_handle: &Handle)
/// # use tokio::reactor::Handle;
/// # fn run<I, S>(some_io: I, some_service: S)
/// # where
/// # I: AsyncRead + AsyncWrite + 'static,
/// # S: Service<Request=Request<Body>, Response=Response<Body>, Error=hyper::Error> + 'static,
/// # I: AsyncRead + AsyncWrite + Send + 'static,
/// # S: Service<Request=Request<Body>, Response=Response<Body>, Error=hyper::Error> + Send + 'static,
/// # S::Future: Send
/// # {
/// let http = Http::<hyper::Chunk>::new();
/// let conn = http.serve_connection(some_io, some_service);
@@ -240,7 +274,7 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
/// .map(|_| ())
/// .map_err(|e| eprintln!("server connection error: {}", e));
///
/// some_handle.spawn(fut);
/// tokio::spawn(fut);
/// # }
/// # fn main() {}
/// ```
@@ -286,21 +320,38 @@ impl<B> fmt::Debug for Http<B> {
// ===== impl Server =====
/// TODO: add docs
pub struct Run(Box<Future<Item=(), Error=::Error> + Send + 'static>);
impl fmt::Debug for Run {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Run").finish()
}
}
impl Future for Run {
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<(), ::Error> {
self.0.poll()
}
}
impl<S, B> Server<S, B>
where S: NewService<Request = Request<Body>, Response = Response<B>, Error = ::Error> + 'static,
B: Entity<Error=::Error> + 'static,
where S: NewService<Request = Request<Body>, Response = Response<B>, Error = ::Error> + Send + 'static,
<S as NewService>::Instance: Send,
<<S as NewService>::Instance as Service>::Future: Send,
B: Entity<Error=::Error> + Send + 'static,
B::Data: Send,
{
/// Returns the local address that this server is bound to.
pub fn local_addr(&self) -> ::Result<SocketAddr> {
Ok(try!(self.listener.local_addr()))
}
/// Returns a handle to the underlying event loop that this server will be
/// running on.
pub fn handle(&self) -> Handle {
self.reactor.handle()
}
/// Configure the amount of time this server will wait for a "graceful
/// shutdown".
///
@@ -318,7 +369,7 @@ impl<S, B> Server<S, B>
///
/// This method does not currently return, but it will return an error if
/// one occurs.
pub fn run(self) -> ::Result<()> {
pub fn run(self) -> Run {
self.run_until(future::empty())
}
@@ -335,40 +386,42 @@ impl<S, B> Server<S, B>
/// `shutdown_timeout` time waiting for active connections to shut down.
/// Once the `shutdown_timeout` elapses or all active connections are
/// cleaned out then this method will return.
pub fn run_until<F>(self, shutdown_signal: F) -> ::Result<()>
where F: Future<Item = (), Error = ()>,
pub fn run_until<F>(self, shutdown_signal: F) -> Run
where F: Future<Item = (), Error = ()> + Send + 'static,
{
let Server { protocol, new_service, mut reactor, listener, shutdown_timeout } = self;
let Server { protocol, new_service, handle, listener, shutdown_timeout } = self;
let handle = reactor.handle();
let mut incoming = AddrIncoming::new(listener, handle.clone(), protocol.sleep_on_errors)?;
let mut incoming = match AddrIncoming::new(listener, handle.clone(), protocol.sleep_on_errors) {
Ok(incoming) => incoming,
Err(err) => return Run(Box::new(future::err(err.into()))),
};
if protocol.keep_alive {
incoming.set_keepalive(Some(Duration::from_secs(90)));
}
// Mini future to track the number of active services
let info = Rc::new(RefCell::new(Info {
let info = Arc::new(Mutex::new(Info {
active: 0,
blocker: None,
}));
// Future for our server's execution
let srv = incoming.for_each(|socket| {
let info_cloned = info.clone();
let srv = incoming.for_each(move |socket| {
let addr = socket.remote_addr;
debug!("accepted new connection ({})", addr);
let service = new_service.new_service()?;
let s = NotifyService {
inner: service,
info: Rc::downgrade(&info),
info: Arc::downgrade(&info_cloned),
};
info.borrow_mut().active += 1;
info_cloned.lock().unwrap().active += 1;
let fut = protocol.serve_connection(socket, s)
.map(|_| ())
.map_err(move |err| error!("server connection error: ({}) {}", addr, err));
handle.spawn(fut);
spawn(fut);
Ok(())
});
@@ -383,24 +436,30 @@ impl<S, B> Server<S, B>
//
// When we get a shutdown signal (`Ok`) then we drop the TCP listener to
// stop accepting incoming connections.
match reactor.run(shutdown_signal.select(srv)) {
Ok(((), _incoming)) => {}
Err((e, _other)) => return Err(e.into()),
}
let main_execution = shutdown_signal.select(srv).then(move |result| {
match result {
Ok(((), _incoming)) => {},
Err((e, _other)) => return future::Either::A(future::err(e.into()))
}
// Ok we've stopped accepting new connections at this point, but we want
// to give existing connections a chance to clear themselves out. Wait
// at most `shutdown_timeout` time before we just return clearing
// everything out.
//
// Our custom `WaitUntilZero` will resolve once all services constructed
// here have been destroyed.
let timeout = try!(Timeout::new(shutdown_timeout, &handle));
let wait = WaitUntilZero { info: info.clone() };
match reactor.run(wait.select(timeout)) {
Ok(_) => Ok(()),
Err((e, _)) => Err(e.into())
}
// Ok we've stopped accepting new connections at this point, but we want
// to give existing connections a chance to clear themselves out. Wait
// at most `shutdown_timeout` time before we just return clearing
// everything out.
//
// Our custom `WaitUntilZero` will resolve once all services constructed
// here have been destroyed.
let timeout = Delay::new(shutdown_timeout);
let wait = WaitUntilZero { info: info.clone() };
future::Either::B(wait.select(timeout).then(|result| {
match result {
Ok(_) => Ok(()),
Err((e, _)) => Err(e.into())
}
}))
});
Run(Box::new(main_execution))
}
}
@@ -537,8 +596,8 @@ impl Stream for AddrIncoming {
}
self.timeout = None;
loop {
match self.listener.accept() {
Ok((socket, addr)) => {
match self.listener.poll_accept() {
Ok(Async::Ready((socket, addr))) => {
if let Some(dur) = self.keep_alive_timeout {
if let Err(e) = socket.set_keepalive(Some(dur)) {
trace!("error trying to set TCP keepalive: {}", e);
@@ -546,7 +605,7 @@ impl Stream for AddrIncoming {
}
return Ok(Async::Ready(Some(AddrStream::new(socket, addr))));
},
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(Async::NotReady),
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(ref e) if self.sleep_on_errors => {
// Connection errors can be ignored directly, continue by
// accepting the next request.
@@ -557,8 +616,7 @@ impl Stream for AddrIncoming {
let delay = ::std::time::Duration::from_millis(10);
debug!("accept error: {}; sleeping {:?}",
e, delay);
let mut timeout = Timeout::new(delay, &self.handle)
.expect("can always set a timeout");
let mut timeout = Delay::new(delay);
let result = timeout.poll()
.expect("timeout never fails");
match result {
@@ -660,11 +718,11 @@ mod addr_stream {
struct NotifyService<S> {
inner: S,
info: Weak<RefCell<Info>>,
info: Weak<Mutex<Info>>,
}
struct WaitUntilZero {
info: Rc<RefCell<Info>>,
info: Arc<Mutex<Info>>,
}
struct Info {
@@ -689,7 +747,7 @@ impl<S> Drop for NotifyService<S> {
Some(info) => info,
None => return,
};
let mut info = info.borrow_mut();
let mut info = info.lock().unwrap();
info.active -= 1;
if info.active == 0 {
if let Some(task) = info.blocker.take() {
@@ -704,7 +762,7 @@ impl Future for WaitUntilZero {
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
let mut info = self.info.borrow_mut();
let mut info = self.info.lock().unwrap();
if info.active == 0 {
Ok(().into())
} else {