diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 855f05f..fb69cb8 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -158,6 +158,11 @@ path = "src/compression/server.rs" name = "compression-client" path = "src/compression/client.rs" +[[bin]] +name = "mock" +path = "src/mock/mock.rs" + + [dependencies] tonic = { path = "../tonic", features = ["tls"] } prost = "0.7" diff --git a/examples/src/mock/mock.rs b/examples/src/mock/mock.rs new file mode 100644 index 0000000..a776d0c --- /dev/null +++ b/examples/src/mock/mock.rs @@ -0,0 +1,124 @@ +use std::convert::TryFrom; +use tonic::{ + transport::{Endpoint, Server, Uri}, + Request, Response, Status, +}; +use tower::service_fn; + +pub mod hello_world { + tonic::include_proto!("helloworld"); +} + +use hello_world::{ + greeter_client::GreeterClient, + greeter_server::{Greeter, GreeterServer}, + HelloReply, HelloRequest, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let (client, server) = tokio::io::duplex(1024); + + let greeter = MyGreeter::default(); + + tokio::spawn(async move { + Server::builder() + .add_service(GreeterServer::new(greeter)) + .serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>( + mock::MockStream(server), + )])) + .await + }); + + // Move client to an option so we can _move_ the inner value + // on the first attempt to connect. All other attempts will fail. + let mut client = Some(client); + let channel = Endpoint::try_from("http://[::]:50051")? + .connect_with_connector(service_fn(move |_: Uri| { + let client = client.take().unwrap(); + + async move { Ok::<_, std::io::Error>(mock::MockStream(client)) } + })) + .await?; + + let mut client = GreeterClient::new(channel); + + let request = tonic::Request::new(HelloRequest { + name: "Tonic".into(), + }); + + let response = client.say_hello(request).await?; + + println!("RESPONSE={:?}", response); + + Ok(()) +} + +#[derive(Default)] +pub struct MyGreeter {} + +#[tonic::async_trait] +impl Greeter for MyGreeter { + async fn say_hello( + &self, + request: Request, + ) -> Result, Status> { + println!("Got a request: {:?}", request); + + let reply = hello_world::HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(Response::new(reply)) + } +} + +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> { + 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> { + Pin::new(&mut self.0).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.0).poll_flush(cx) + } + + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.0).poll_shutdown(cx) + } + } +} diff --git a/tests/compression/Cargo.toml b/tests/compression/Cargo.toml index 6646d39..f15dd22 100644 --- a/tests/compression/Cargo.toml +++ b/tests/compression/Cargo.toml @@ -18,7 +18,7 @@ tower-http = { version = "0.1", features = ["map-response-body", "map-request-bo bytes = "1" futures = "0.3" pin-project = "1.0" -hyper = "0.14" +hyper = "0.14.3" [build-dependencies] tonic-build = { path = "../../tonic-build", features = ["compression"] }