fix(tonic): Remove Sync requirement for streams (#804)

This commit is contained in:
Lucio Franco
2021-10-24 21:48:05 -04:00
committed by GitHub
parent 1f3df8db9e
commit 23c1392fb7
31 changed files with 207 additions and 165 deletions
+2 -1
View File
@@ -12,14 +12,15 @@ version = "0.1.0"
bytes = "1.0"
futures-util = "0.3"
prost = "0.9"
tokio = {version = "1.0", features = ["macros", "rt-multi-thread", "net"]}
tonic = {path = "../../tonic"}
[dev-dependencies]
async-stream = "0.3"
futures = "0.3"
http = "0.2"
http-body = "0.4"
hyper = "0.14"
tokio = {version = "1.0", features = ["macros", "rt-multi-thread", "net"]}
tokio-stream = {version = "0.1.5", features = ["net"]}
tower = {version = "0.4", features = []}
tower-service = "0.3"
+51
View File
@@ -2,3 +2,54 @@ pub mod pb {
tonic::include_proto!("test");
tonic::include_proto!("stream");
}
pub mod mock {
use std::{
pin::Pin,
task::{Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tonic::transport::server::Connected;
#[derive(Debug)]
pub struct MockStream(pub tokio::io::DuplexStream);
impl Connected for MockStream {
type ConnectInfo = ();
/// Create type holding information about the connection.
fn connect_info(&self) -> Self::ConnectInfo {}
}
impl AsyncRead for MockStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_read(cx, buf)
}
}
impl AsyncWrite for MockStream {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<std::io::Result<usize>> {
Pin::new(&mut self.0).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_flush(cx)
}
fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_shutdown(cx)
}
}
}
+4 -55
View File
@@ -1,6 +1,7 @@
use bytes::Bytes;
use futures_util::FutureExt;
use http::Uri;
use integration_tests::mock::MockStream;
use integration_tests::pb::{
test_client, test_server, test_stream_client, test_stream_server, Input, InputStream, Output,
OutputStream,
@@ -125,9 +126,8 @@ async fn status_with_metadata() {
jh.await.unwrap();
}
type Stream<T> = std::pin::Pin<
Box<dyn futures::Stream<Item = std::result::Result<T, Status>> + Send + Sync + 'static>,
>;
type Stream<T> =
std::pin::Pin<Box<dyn futures::Stream<Item = std::result::Result<T, Status>> + Send + 'static>>;
#[tokio::test]
async fn status_from_server_stream() {
@@ -184,7 +184,7 @@ async fn status_from_server_stream_with_source() {
let channel = Endpoint::try_from("http://[::]:50051")
.unwrap()
.connect_with_connector_lazy(tower::service_fn(move |_: Uri| async move {
Err::<mock::MockStream, _>(std::io::Error::new(std::io::ErrorKind::Other, "WTF"))
Err::<MockStream, _>(std::io::Error::new(std::io::ErrorKind::Other, "WTF"))
}))
.unwrap();
@@ -201,54 +201,3 @@ fn trace_init() {
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init();
}
mod mock {
use std::{
pin::Pin,
task::{Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tonic::transport::server::Connected;
#[derive(Debug)]
pub struct MockStream(pub tokio::io::DuplexStream);
impl Connected for MockStream {
type ConnectInfo = ();
/// Create type holding information about the connection.
fn connect_info(&self) -> Self::ConnectInfo {}
}
impl AsyncRead for MockStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_read(cx, buf)
}
}
impl AsyncWrite for MockStream {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<std::io::Result<usize>> {
Pin::new(&mut self.0).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_flush(cx)
}
fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<std::io::Result<()>> {
Pin::new(&mut self.0).poll_shutdown(cx)
}
}
}
+47
View File
@@ -0,0 +1,47 @@
use futures::FutureExt;
use integration_tests::pb::{test_stream_server, InputStream, OutputStream};
use tonic::{transport::Server, Request, Response, Status};
type Stream<T> =
std::pin::Pin<Box<dyn futures::Stream<Item = std::result::Result<T, Status>> + Send + 'static>>;
#[tokio::test]
async fn status_from_server_stream_with_source() {
struct Svc;
#[tonic::async_trait]
impl test_stream_server::TestStream for Svc {
type StreamCallStream = Stream<OutputStream>;
async fn stream_call(
&self,
_: Request<InputStream>,
) -> Result<Response<Self::StreamCallStream>, Status> {
let s = Unsync(0 as *mut ());
Ok(Response::new(Box::pin(s) as Self::StreamCallStream))
}
}
let svc = test_stream_server::TestStreamServer::new(Svc);
Server::builder()
.add_service(svc)
.serve("127.0.0.1:1339".parse().unwrap())
.now_or_never();
}
struct Unsync(*mut ());
unsafe impl Send for Unsync {}
impl futures::Stream for Unsync {
type Item = Result<OutputStream, Status>;
fn poll_next(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
unimplemented!()
}
}