feat(server): change default dispatcher

- Deprecates the `no_proto` configuration on `Server`. It is always
  enabled.
- Deprecates all pieces related to tokio-proto.
- Makes the tokio-proto crate optional, and the `server-proto` feature
  can be used to completely remove the dependency. It is enabled by
  default.
This commit is contained in:
Sean McArthur
2017-12-28 18:56:15 -08:00
parent 0892cb2777
commit 6ade21aa7f
15 changed files with 124 additions and 118 deletions

View File

@@ -1,11 +1,13 @@
use bytes::Bytes;
use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend, Stream};
use futures::sync::{mpsc, oneshot};
#[cfg(feature = "tokio-proto")]
use tokio_proto;
use std::borrow::Cow;
use super::Chunk;
#[cfg(feature = "tokio-proto")]
pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>;
pub type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;
@@ -16,17 +18,21 @@ pub struct Body(Inner);
#[derive(Debug)]
enum Inner {
#[cfg(feature = "tokio-proto")]
Tokio(TokioBody),
Hyper {
close_tx: oneshot::Sender<()>,
Chan {
close_tx: oneshot::Sender<bool>,
rx: mpsc::Receiver<Result<Chunk, ::Error>>,
}
},
Once(Option<Chunk>),
Empty,
}
//pub(crate)
#[derive(Debug)]
pub struct ChunkSender {
close_rx: oneshot::Receiver<()>,
close_rx: oneshot::Receiver<bool>,
close_rx_check: bool,
tx: BodySender,
}
@@ -34,15 +40,14 @@ impl Body {
/// Return an empty body stream
#[inline]
pub fn empty() -> Body {
Body(Inner::Tokio(TokioBody::empty()))
Body(Inner::Empty)
}
/// Return a body stream with an associated sender half
#[inline]
pub fn pair() -> (mpsc::Sender<Result<Chunk, ::Error>>, Body) {
let (tx, rx) = TokioBody::pair();
let rx = Body(Inner::Tokio(rx));
(tx, rx)
let (tx, rx) = channel();
(tx.tx, rx)
}
}
@@ -60,13 +65,16 @@ impl Stream for Body {
#[inline]
fn poll(&mut self) -> Poll<Option<Chunk>, ::Error> {
match self.0 {
#[cfg(feature = "tokio-proto")]
Inner::Tokio(ref mut rx) => rx.poll(),
Inner::Hyper { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") {
Inner::Chan { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") {
Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))),
Async::Ready(Some(Err(err))) => Err(err),
Async::Ready(None) => Ok(Async::Ready(None)),
Async::NotReady => Ok(Async::NotReady),
},
Inner::Once(ref mut val) => Ok(Async::Ready(val.take())),
Inner::Empty => Ok(Async::Ready(None)),
}
}
}
@@ -78,9 +86,10 @@ pub fn channel() -> (ChunkSender, Body) {
let tx = ChunkSender {
close_rx: close_rx,
close_rx_check: true,
tx: tx,
};
let rx = Body(Inner::Hyper {
let rx = Body(Inner::Chan {
close_tx: close_tx,
rx: rx,
});
@@ -90,9 +99,16 @@ pub fn channel() -> (ChunkSender, Body) {
impl ChunkSender {
pub fn poll_ready(&mut self) -> Poll<(), ()> {
match self.close_rx.poll() {
Ok(Async::Ready(())) | Err(_) => return Err(()),
Ok(Async::NotReady) => (),
if self.close_rx_check {
match self.close_rx.poll() {
Ok(Async::Ready(true)) | Err(_) => return Err(()),
Ok(Async::Ready(false)) => {
// needed to allow converting into a plain mpsc::Receiver
// if it has been, the tx will send false to disable this check
self.close_rx_check = false;
}
Ok(Async::NotReady) => (),
}
}
self.tx.poll_ready().map_err(|_| ())
@@ -107,63 +123,67 @@ impl ChunkSender {
}
}
// deprecate soon, but can't really deprecate trait impls
#[doc(hidden)]
impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> {
#[inline]
fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> {
match b.0 {
Inner::Tokio(b) => b,
Inner::Hyper { close_tx, rx } => {
warn!("converting hyper::Body into a tokio_proto Body is deprecated");
::std::mem::forget(close_tx);
rx.into()
feat_server_proto! {
impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> {
fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> {
match b.0 {
Inner::Tokio(b) => b,
Inner::Chan { close_tx, rx } => {
// disable knowing if the Rx gets dropped, since we cannot
// pass this tx along.
let _ = close_tx.send(false);
rx.into()
},
Inner::Once(Some(chunk)) => TokioBody::from(chunk),
Inner::Once(None) |
Inner::Empty => TokioBody::empty(),
}
}
}
}
// deprecate soon, but can't really deprecate trait impls
#[doc(hidden)]
impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body {
#[inline]
fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body {
Body(Inner::Tokio(tokio_body))
impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body {
fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body {
Body(Inner::Tokio(tokio_body))
}
}
}
impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body {
#[inline]
fn from(src: mpsc::Receiver<Result<Chunk, ::Error>>) -> Body {
TokioBody::from(src).into()
let (tx, _) = oneshot::channel();
Body(Inner::Chan {
close_tx: tx,
rx: src,
})
}
}
impl From<Chunk> for Body {
#[inline]
fn from (chunk: Chunk) -> Body {
TokioBody::from(chunk).into()
Body(Inner::Once(Some(chunk)))
}
}
impl From<Bytes> for Body {
#[inline]
fn from (bytes: Bytes) -> Body {
Body::from(TokioBody::from(Chunk::from(bytes)))
Body::from(Chunk::from(bytes))
}
}
impl From<Vec<u8>> for Body {
#[inline]
fn from (vec: Vec<u8>) -> Body {
Body::from(TokioBody::from(Chunk::from(vec)))
Body::from(Chunk::from(vec))
}
}
impl From<&'static [u8]> for Body {
#[inline]
fn from (slice: &'static [u8]) -> Body {
Body::from(TokioBody::from(Chunk::from(slice)))
Body::from(Chunk::from(slice))
}
}
@@ -180,14 +200,14 @@ impl From<Cow<'static, [u8]>> for Body {
impl From<String> for Body {
#[inline]
fn from (s: String) -> Body {
Body::from(TokioBody::from(Chunk::from(s.into_bytes())))
Body::from(Chunk::from(s.into_bytes()))
}
}
impl From<&'static str> for Body {
#[inline]
fn from(slice: &'static str) -> Body {
Body::from(TokioBody::from(Chunk::from(slice.as_bytes())))
Body::from(Chunk::from(slice.as_bytes()))
}
}

View File

@@ -2,9 +2,12 @@ use std::fmt;
use std::io::{self, Write};
use std::marker::PhantomData;
use futures::{Poll, Async, AsyncSink, Stream, Sink, StartSend};
use futures::{Async, AsyncSink, Poll, StartSend};
#[cfg(feature = "tokio-proto")]
use futures::{Sink, Stream};
use futures::task::Task;
use tokio_io::{AsyncRead, AsyncWrite};
#[cfg(feature = "tokio-proto")]
use tokio_proto::streaming::pipeline::{Frame, Transport};
use proto::Http1Transaction;
@@ -51,6 +54,7 @@ where I: AsyncRead + AsyncWrite,
self.io.set_flush_pipeline(enabled);
}
#[cfg(feature = "tokio-proto")]
fn poll_incoming(&mut self) -> Poll<Option<Frame<super::MessageHead<T::Incoming>, super::Chunk, ::Error>>, io::Error> {
trace!("Conn::poll_incoming()");
@@ -123,7 +127,7 @@ where I: AsyncRead + AsyncWrite,
}
}
fn can_write_continue(&self) -> bool {
pub fn can_write_continue(&self) -> bool {
match self.state.writing {
Writing::Continue(..) => true,
_ => false,
@@ -511,11 +515,6 @@ where I: AsyncRead + AsyncWrite,
}
pub fn close_and_shutdown(&mut self) -> Poll<(), io::Error> {
try_ready!(self.flush());
self.shutdown()
}
pub fn shutdown(&mut self) -> Poll<(), io::Error> {
match self.io.io_mut().shutdown() {
Ok(Async::NotReady) => Ok(Async::NotReady),
@@ -549,6 +548,7 @@ where I: AsyncRead + AsyncWrite,
// ==== tokio_proto impl ====
#[cfg(feature = "tokio-proto")]
impl<I, B, T, K> Stream for Conn<I, B, T, K>
where I: AsyncRead + AsyncWrite,
B: AsRef<[u8]>,
@@ -567,6 +567,7 @@ where I: AsyncRead + AsyncWrite,
}
}
#[cfg(feature = "tokio-proto")]
impl<I, B, T, K> Sink for Conn<I, B, T, K>
where I: AsyncRead + AsyncWrite,
B: AsRef<[u8]>,
@@ -630,10 +631,12 @@ where I: AsyncRead + AsyncWrite,
#[inline]
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.close_and_shutdown()
try_ready!(self.flush());
self.shutdown()
}
}
#[cfg(feature = "tokio-proto")]
impl<I, B, T, K> Transport for Conn<I, B, T, K>
where I: AsyncRead + AsyncWrite + 'static,
B: AsRef<[u8]> + 'static,
@@ -838,8 +841,10 @@ impl<B, K: KeepAlive> State<B, K> {
// The DebugFrame and DebugChunk are simple Debug implementations that allow
// us to dump the frame into logs, without logging the entirety of the bytes.
#[cfg(feature = "tokio-proto")]
struct DebugFrame<'a, T: fmt::Debug + 'a, B: AsRef<[u8]> + 'a>(&'a Frame<super::MessageHead<T>, B, ::Error>);
#[cfg(feature = "tokio-proto")]
impl<'a, T: fmt::Debug + 'a, B: AsRef<[u8]> + 'a> fmt::Debug for DebugFrame<'a, T, B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
@@ -868,6 +873,8 @@ impl<'a, T: fmt::Debug + 'a, B: AsRef<[u8]> + 'a> fmt::Debug for DebugFrame<'a,
}
#[cfg(test)]
#[cfg(feature = "tokio-proto")]
//TODO: rewrite these using dispatch instead of tokio-proto API
mod tests {
use futures::{Async, Future, Stream, Sink};
use futures::future;

View File

@@ -108,6 +108,8 @@ where
return Ok(Async::Ready(()));
}
}
} else if self.conn.can_write_continue() {
try_nb!(self.conn.flush());
} else if let Some(mut body) = self.body_tx.take() {
let can_read_body = self.conn.can_read_body();
match body.poll_ready() {

View File

@@ -13,7 +13,9 @@ use version::HttpVersion;
use version::HttpVersion::{Http10, Http11};
pub use self::conn::{Conn, KeepAlive, KA};
pub use self::body::{Body, TokioBody};
pub use self::body::Body;
#[cfg(feature = "tokio-proto")]
pub use self::body::TokioBody;
pub use self::chunk::Chunk;
mod body;