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:
		| @@ -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())) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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() { | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user