chore: Reorganize examples and interop crates (#180)

* chore: Reorganize examples and interop crates

* fix interop tests
This commit is contained in:
Lucio Franco
2019-12-12 11:53:15 -05:00
committed by GitHub
parent f096a238ac
commit d9a481baef
69 changed files with 25 additions and 22 deletions
+32
View File
@@ -0,0 +1,32 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use http::header::HeaderValue;
use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::Channel;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let channel = Channel::from_static("http://[::1]:50051")
.intercept_headers(|headers| {
headers.insert(
"authorization",
HeaderValue::from_static("Bearer some-secret-token"),
);
})
.connect()
.await?;
let mut client = EchoClient::new(channel);
let request = tonic::Request::new(EchoRequest {
message: "hello".into(),
});
let response = client.unary_echo(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}
+87
View File
@@ -0,0 +1,87 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::{body::BoxBody, transport::Server, Request, Response, Status, Streaming};
use tower::Service;
type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + Sync>>;
#[derive(Default)]
pub struct EchoServer;
#[tonic::async_trait]
impl pb::echo_server::Echo for EchoServer {
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}
type ServerStreamingEchoStream = ResponseStream;
async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}
type BidirectionalStreamingEchoStream = ResponseStream;
async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let server = EchoServer::default();
Server::builder()
.interceptor_fn(move |svc, req| {
let auth_header = req.headers().get("authorization").clone();
let authed = if let Some(auth_header) = auth_header {
auth_header == "Bearer some-secret-token"
} else {
false
};
let fut = svc.call(req);
async move {
if authed {
fut.await
} else {
// Cancel the inner future since we never await it
// the IO never gets registered.
drop(fut);
let res = http::Response::builder()
.header("grpc-status", "16")
.body(BoxBody::empty())
.unwrap();
Ok(res)
}
}
})
.add_service(pb::echo_server::EchoServer::new(server))
.serve(addr)
.await?;
Ok(())
}
+56
View File
@@ -0,0 +1,56 @@
use tokio::runtime::{Builder, Runtime};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
use hello_world::{greeter_client::GreeterClient, HelloReply, HelloRequest};
type StdError = Box<dyn std::error::Error + Send + Sync + 'static>;
type Result<T, E = StdError> = ::std::result::Result<T, E>;
// The order of the fields in this struct is important. The runtime must be the first field and the
// client must be the last field so that when `BlockingClient` is dropped the client is dropped
// before the runtime. Not doing this will result in a deadlock when dropped.
struct BlockingClient {
rt: Runtime,
client: GreeterClient<tonic::transport::Channel>,
}
impl BlockingClient {
pub fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: std::convert::TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let mut rt = Builder::new()
.basic_scheduler()
.enable_all()
.build()
.unwrap();
let client = rt.block_on(GreeterClient::connect(dst))?;
Ok(Self { rt, client })
}
pub fn say_hello(
&mut self,
request: impl tonic::IntoRequest<HelloRequest>,
) -> Result<tonic::Response<HelloReply>, tonic::Status> {
self.rt.block_on(self.client.say_hello(request))
}
}
fn main() -> Result<()> {
let mut client = BlockingClient::connect("http://[::1]:50051")?;
let request = tonic::Request::new(HelloRequest {
name: "Tonic".into(),
});
let response = client.say_hello(request)?;
println!("RESPONSE={:?}", response);
Ok(())
}
+21
View File
@@ -0,0 +1,21 @@
# Google Cloud Pubsub example
This example will attempt to fetch a list of topics using the google
gRPC protobuf specification. This will use an OAuth token and TLS to
fetch the list of topics.
First, you must generate a access token via the [OAuth playground]. From here
select the `Cloud Pub/Sub API v1` and its urls as the scope. This will start
the OAuth flow. Then you must hit the `Exchange authorization code for tokens`
button to generate an `access_token` which will show up in the HTTP response
to the right under the `access_token` field in the response json.
Once, you have this token you must fetch your GCP project id which can be found
from the main page on the dashboard. When you have both of these items you can
run the example like so:
```shell
GCP_AUTH_TOKEN="<access-token>" cargo run --bin gcp-client -- <project-id>
```
[OAuth playground]: https://developers.google.com/oauthplayground/
+55
View File
@@ -0,0 +1,55 @@
pub mod api {
tonic::include_proto!("google.pubsub.v1");
}
use api::{publisher_client::PublisherClient, ListTopicsRequest};
use http::header::HeaderValue;
use tonic::{
transport::{Certificate, Channel, ClientTlsConfig},
Request,
};
const ENDPOINT: &str = "https://pubsub.googleapis.com";
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let token = std::env::var("GCP_AUTH_TOKEN").map_err(|_| {
"Pass a valid 0Auth bearer token via `GCP_AUTH_TOKEN` environment variable.".to_string()
})?;
let project = std::env::args()
.skip(1)
.next()
.ok_or("Expected a project name as the first argument.".to_string())?;
let bearer_token = format!("Bearer {}", token);
let header_value = HeaderValue::from_str(&bearer_token)?;
let certs = tokio::fs::read("tonic-examples/data/gcp/roots.pem").await?;
let tls_config = ClientTlsConfig::with_rustls()
.ca_certificate(Certificate::from_pem(certs.as_slice()))
.domain_name("pubsub.googleapis.com");
let channel = Channel::from_static(ENDPOINT)
.intercept_headers(move |headers| {
headers.insert("authorization", header_value.clone());
})
.tls_config(tls_config)
.connect()
.await?;
let mut service = PublisherClient::new(channel);
let response = service
.list_topics(Request::new(ListTopicsRequest {
project: format!("projects/{0}", project),
page_size: 10,
..Default::default()
}))
.await?;
println!("RESPONSE={:?}", response);
Ok(())
}
+20
View File
@@ -0,0 +1,20 @@
pub mod hello_world {
tonic::include_proto!("helloworld");
}
use hello_world::{greeter_client::GreeterClient, HelloRequest};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let request = tonic::Request::new(HelloRequest {
name: "Tonic".into(),
});
let response = client.say_hello(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}
+41
View File
@@ -0,0 +1,41 @@
use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
use hello_world::{
greeter_server::{Greeter, GreeterServer},
HelloReply, HelloRequest,
};
#[derive(Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request: {:?}", request);
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
Server::builder()
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;
Ok(())
}
+29
View File
@@ -0,0 +1,29 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::Channel;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoints = ["http://[::1]:50051", "http://[::1]:50052"]
.into_iter()
.map(|a| Channel::from_static(a));
let channel = Channel::balance_list(endpoints);
let mut client = EchoClient::new(channel);
for _ in 0..12usize {
let request = tonic::Request::new(EchoRequest {
message: "hello".into(),
});
let response = client.unary_echo(request).await?;
println!("RESPONSE={:?}", response);
}
Ok(())
}
+82
View File
@@ -0,0 +1,82 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use futures::Stream;
use std::net::SocketAddr;
use std::pin::Pin;
use tokio::sync::mpsc;
use tonic::{transport::Server, Request, Response, Status, Streaming};
use pb::{EchoRequest, EchoResponse};
type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + Sync>>;
#[derive(Debug)]
pub struct EchoServer {
addr: SocketAddr,
}
#[tonic::async_trait]
impl pb::echo_server::Echo for EchoServer {
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
let message = format!("{} (from {})", request.into_inner().message, self.addr);
Ok(Response::new(EchoResponse { message }))
}
type ServerStreamingEchoStream = ResponseStream;
async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}
type BidirectionalStreamingEchoStream = ResponseStream;
async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addrs = ["[::1]:50051", "[::1]:50052"];
let (tx, mut rx) = mpsc::unbounded_channel();
for addr in &addrs {
let addr = addr.parse()?;
let tx = tx.clone();
let server = EchoServer { addr };
let serve = Server::builder()
.add_service(pb::echo_server::EchoServer::new(server))
.serve(addr);
tokio::spawn(async move {
if let Err(e) = serve.await {
eprintln!("Error = {:?}", e);
}
tx.send(()).unwrap();
});
}
rx.recv().await;
Ok(())
}
+39
View File
@@ -0,0 +1,39 @@
pub mod hello_world {
tonic::include_proto!("helloworld");
}
pub mod echo {
tonic::include_proto!("grpc.examples.echo");
}
use echo::{echo_client::EchoClient, EchoRequest};
use hello_world::{greeter_client::GreeterClient, HelloRequest};
use tonic::transport::Endpoint;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let channel = Endpoint::from_static("http://[::1]:50051")
.connect()
.await?;
let mut greeter_client = GreeterClient::new(channel.clone());
let mut echo_client = EchoClient::new(channel);
let request = tonic::Request::new(HelloRequest {
name: "Tonic".into(),
});
let response = greeter_client.say_hello(request).await?;
println!("GREETER RESPONSE={:?}", response);
let request = tonic::Request::new(EchoRequest {
message: "hello".into(),
});
let response = echo_client.unary_echo(request).await?;
println!("ECHO RESPONSE={:?}", response);
Ok(())
}
+72
View File
@@ -0,0 +1,72 @@
use futures::Stream;
use std::pin::Pin;
use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
pub mod echo {
tonic::include_proto!("grpc.examples.echo");
}
use hello_world::{
greeter_server::{Greeter, GreeterServer},
HelloReply, HelloRequest,
};
use echo::{
echo_server::{Echo, EchoServer},
EchoRequest, EchoResponse,
};
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + Sync>>;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = GreeterServer::new(MyGreeter::default());
let echo = EchoServer::new(MyEcho::default());
Server::builder()
.add_service(greeter)
.add_service(echo)
.serve(addr)
.await?;
Ok(())
}
#[derive(Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
};
Ok(Response::new(reply))
}
}
#[derive(Default)]
pub struct MyEcho;
#[tonic::async_trait]
impl Echo for MyEcho {
async fn unary_echo(
&self,
request: Request<EchoRequest>,
) -> Result<Response<EchoResponse>, Status> {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}
type ServerStreamingEchoStream = ResponseStream;
type BidirectionalStreamingEchoStream = ResponseStream;
}
+124
View File
@@ -0,0 +1,124 @@
use futures::stream;
use rand::rngs::ThreadRng;
use rand::Rng;
use route_guide::{Point, Rectangle, RouteNote};
use std::error::Error;
use std::time::Duration;
use tokio::time::Instant;
use tonic::transport::Channel;
use tonic::Request;
pub mod route_guide {
tonic::include_proto!("routeguide");
}
use route_guide::routeguide_client::RouteGuideClient;
async fn print_features(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let rectangle = Rectangle {
lo: Some(Point {
latitude: 400000000,
longitude: -750000000,
}),
hi: Some(Point {
latitude: 420000000,
longitude: -730000000,
}),
};
let mut stream = client
.list_features(Request::new(rectangle))
.await?
.into_inner();
while let Some(feature) = stream.message().await? {
println!("NOTE = {:?}", feature);
}
Ok(())
}
async fn run_record_route(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let mut rng = rand::thread_rng();
let point_count: i32 = rng.gen_range(2, 100);
let mut points = vec![];
for _ in 0..=point_count {
points.push(random_point(&mut rng))
}
println!("Traversing {} points", points.len());
let request = Request::new(stream::iter(points));
match client.record_route(request).await {
Ok(response) => println!("SUMMARY: {:?}", response.into_inner()),
Err(e) => println!("something went wrong: {:?}", e),
}
Ok(())
}
async fn run_route_chat(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let start = Instant::now();
let outbound = async_stream::stream! {
let mut interval = tokio::time::interval(Duration::from_secs(1));
while let time = interval.tick().await {
let elapsed = time.duration_since(start);
let note = RouteNote {
location: Some(Point {
latitude: 409146138 + elapsed.as_secs() as i32,
longitude: -746188906,
}),
message: format!("at {:?}", elapsed),
};
yield note;
}
};
let request = Request::new(outbound);
let response = client.route_chat(request).await?;
let mut inbound = response.into_inner();
while let Some(note) = inbound.message().await? {
println!("NOTE = {:?}", note);
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = RouteGuideClient::connect("http://[::1]:10000").await?;
println!("*** SIMPLE RPC ***");
let response = client
.get_feature(Request::new(Point {
latitude: 409146138,
longitude: -746188906,
}))
.await?;
println!("RESPONSE = {:?}", response);
println!("\n*** SERVER STREAMING ***");
print_features(&mut client).await?;
println!("\n*** CLIENT STREAMING ***");
run_record_route(&mut client).await?;
println!("\n*** BIDIRECTIONAL STREAMING ***");
run_route_chat(&mut client).await?;
Ok(())
}
fn random_point(rng: &mut ThreadRng) -> Point {
let latitude = (rng.gen_range(0, 180) - 90) * 10_000_000;
let longitude = (rng.gen_range(0, 360) - 180) * 10_000_000;
Point {
latitude,
longitude,
}
}
+34
View File
@@ -0,0 +1,34 @@
use serde::Deserialize;
use std::fs::File;
#[derive(Debug, Deserialize)]
struct Feature {
location: Location,
name: String,
}
#[derive(Debug, Deserialize)]
struct Location {
latitude: i32,
longitude: i32,
}
#[allow(dead_code)]
pub fn load() -> Vec<crate::routeguide::Feature> {
let file =
File::open("tonic-examples/data/route_guide_db.json").expect("failed to open data file");
let decoded: Vec<Feature> =
serde_json::from_reader(&file).expect("failed to deserialize features");
decoded
.into_iter()
.map(|feature| crate::routeguide::Feature {
name: feature.name,
location: Some(crate::routeguide::Point {
longitude: feature.location.longitude,
latitude: feature.location.latitude,
}),
})
.collect()
}
+217
View File
@@ -0,0 +1,217 @@
mod data;
use futures::{Stream, StreamExt};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::pin::Pin;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::mpsc;
use tonic::transport::Server;
use tonic::{Request, Response, Status};
pub mod routeguide {
tonic::include_proto!("routeguide");
}
use routeguide::{routeguide_server, Feature, Point, Rectangle, RouteNote, RouteSummary};
#[derive(Debug)]
pub struct RouteGuide {
features: Arc<Vec<Feature>>,
}
#[tonic::async_trait]
impl routeguide_server::RouteGuide for RouteGuide {
async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {
println!("GetFeature = {:?}", request);
for feature in &self.features[..] {
if feature.location.as_ref() == Some(request.get_ref()) {
return Ok(Response::new(feature.clone()));
}
}
let response = Response::new(Feature {
name: "".to_string(),
location: None,
});
Ok(response)
}
type ListFeaturesStream = mpsc::Receiver<Result<Feature, Status>>;
async fn list_features(
&self,
request: Request<Rectangle>,
) -> Result<Response<Self::ListFeaturesStream>, Status> {
println!("ListFeatures = {:?}", request);
let (mut tx, rx) = mpsc::channel(4);
let features = self.features.clone();
tokio::spawn(async move {
for feature in &features[..] {
if in_range(feature.location.as_ref().unwrap(), request.get_ref()) {
println!(" => send {:?}", feature);
tx.send(Ok(feature.clone())).await.unwrap();
}
}
println!(" /// done sending");
});
Ok(Response::new(rx))
}
async fn record_route(
&self,
request: Request<tonic::Streaming<Point>>,
) -> Result<Response<RouteSummary>, Status> {
println!("RecordRoute");
let stream = request.into_inner();
// Pin the inbound stream to the stack so that we can call next on it
futures::pin_mut!(stream);
let mut summary = RouteSummary::default();
let mut last_point = None;
let now = Instant::now();
while let Some(point) = stream.next().await {
let point = point?;
println!(" ==> Point = {:?}", point);
// Increment the point count
summary.point_count += 1;
// Find features
for feature in &self.features[..] {
if feature.location.as_ref() == Some(&point) {
summary.feature_count += 1;
}
}
// Calculate the distance
if let Some(ref last_point) = last_point {
summary.distance += calc_distance(last_point, &point);
}
last_point = Some(point);
}
summary.elapsed_time = now.elapsed().as_secs() as i32;
Ok(Response::new(summary))
}
type RouteChatStream =
Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + Sync + 'static>>;
async fn route_chat(
&self,
request: Request<tonic::Streaming<RouteNote>>,
) -> Result<Response<Self::RouteChatStream>, Status> {
println!("RouteChat");
let mut notes = HashMap::new();
let stream = request.into_inner();
let output = async_stream::try_stream! {
futures::pin_mut!(stream);
while let Some(note) = stream.next().await {
let note = note?;
let location = note.location.clone().unwrap();
let location_notes = notes.entry(location).or_insert(vec![]);
location_notes.push(note);
for note in location_notes {
yield note.clone();
}
}
};
Ok(Response::new(Box::pin(output)
as Pin<
Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + Sync + 'static>,
>))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:10000".parse().unwrap();
println!("Listening on: {}", addr);
let route_guide = RouteGuide {
features: Arc::new(data::load()),
};
let svc = routeguide_server::RouteGuideServer::new(route_guide);
Server::builder().add_service(svc).serve(addr).await?;
Ok(())
}
// Implement hash for Point
impl Hash for Point {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.latitude.hash(state);
self.longitude.hash(state);
}
}
impl Eq for Point {}
fn in_range(point: &Point, rect: &Rectangle) -> bool {
use std::cmp;
let lo = rect.lo.as_ref().unwrap();
let hi = rect.hi.as_ref().unwrap();
let left = cmp::min(lo.longitude, hi.longitude);
let right = cmp::max(lo.longitude, hi.longitude);
let top = cmp::max(lo.latitude, hi.latitude);
let bottom = cmp::min(lo.latitude, hi.latitude);
point.longitude >= left
&& point.longitude <= right
&& point.latitude >= bottom
&& point.latitude <= top
}
/// Calculates the distance between two points using the "haversine" formula.
/// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
fn calc_distance(p1: &Point, p2: &Point) -> i32 {
const CORD_FACTOR: f64 = 1e7;
const R: f64 = 6371000.0; // meters
let lat1 = p1.latitude as f64 / CORD_FACTOR;
let lat2 = p2.latitude as f64 / CORD_FACTOR;
let lng1 = p1.longitude as f64 / CORD_FACTOR;
let lng2 = p2.longitude as f64 / CORD_FACTOR;
let lat_rad1 = lat1.to_radians();
let lat_rad2 = lat2.to_radians();
let delta_lat = (lat2 - lat1).to_radians();
let delta_lng = (lng2 - lng1).to_radians();
let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin()
+ (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin();
let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt());
(R * c) as i32
}
+32
View File
@@ -0,0 +1,32 @@
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
}
use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::{Certificate, Channel, ClientTlsConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pem = tokio::fs::read("tonic-examples/data/tls/ca.pem").await?;
let ca = Certificate::from_pem(pem);
let tls = ClientTlsConfig::with_rustls()
.ca_certificate(ca)
.domain_name("example.com");
let channel = Channel::from_static("http://[::1]:50051")
.tls_config(tls)
.connect()
.await?;
let mut client = EchoClient::new(channel);
let request = tonic::Request::new(EchoRequest {
message: "hello".into(),
});
let response = client.unary_echo(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}
+69
View File
@@ -0,0 +1,69 @@
pub mod pb {
tonic::include_proto!("/grpc.examples.echo");
}
use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::{
transport::{Identity, Server, ServerTlsConfig},
Request, Response, Status, Streaming,
};
type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + Sync>>;
#[derive(Default)]
pub struct EchoServer;
#[tonic::async_trait]
impl pb::echo_server::Echo for EchoServer {
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}
type ServerStreamingEchoStream = ResponseStream;
async fn server_streaming_echo(
&self,
_: Request<EchoRequest>,
) -> EchoResult<Self::ServerStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
async fn client_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<EchoResponse> {
Err(Status::unimplemented("not implemented"))
}
type BidirectionalStreamingEchoStream = ResponseStream;
async fn bidirectional_streaming_echo(
&self,
_: Request<Streaming<EchoRequest>>,
) -> EchoResult<Self::BidirectionalStreamingEchoStream> {
Err(Status::unimplemented("not implemented"))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert = tokio::fs::read("tonic-examples/data/tls/server.pem").await?;
let key = tokio::fs::read("tonic-examples/data/tls/server.key").await?;
let identity = Identity::from_pem(cert, key);
let addr = "[::1]:50051".parse().unwrap();
let server = EchoServer::default();
Server::builder()
.tls_config(ServerTlsConfig::with_rustls().identity(identity))
.add_service(pb::echo_server::EchoServer::new(server))
.serve(addr)
.await?;
Ok(())
}
+37
View File
@@ -0,0 +1,37 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use pb::{echo_client::EchoClient, EchoRequest};
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server_root_ca_cert = tokio::fs::read("tonic-examples/data/tls/ca.pem").await?;
let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);
let client_cert = tokio::fs::read("tonic-examples/data/tls/client1.pem").await?;
let client_key = tokio::fs::read("tonic-examples/data/tls/client1.key").await?;
let client_identity = Identity::from_pem(client_cert, client_key);
let tls = ClientTlsConfig::with_rustls()
.domain_name("localhost")
.ca_certificate(server_root_ca_cert)
.identity(client_identity);
let channel = Channel::from_static("http://[::1]:50051")
.tls_config(tls)
.connect()
.await?;
let mut client = EchoClient::new(channel);
let request = tonic::Request::new(EchoRequest {
message: "hello".into(),
});
let response = client.unary_echo(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}
+51
View File
@@ -0,0 +1,51 @@
pub mod pb {
tonic::include_proto!("grpc.examples.echo");
}
use futures::Stream;
use pb::{EchoRequest, EchoResponse};
use std::pin::Pin;
use tonic::transport::{Certificate, Identity, Server, ServerTlsConfig};
use tonic::{Request, Response, Status};
type EchoResult<T> = Result<Response<T>, Status>;
type ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + Sync>>;
#[derive(Default)]
pub struct EchoServer;
#[tonic::async_trait]
impl pb::echo_server::Echo for EchoServer {
async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {
let message = request.into_inner().message;
Ok(Response::new(EchoResponse { message }))
}
type ServerStreamingEchoStream = ResponseStream;
type BidirectionalStreamingEchoStream = ResponseStream;
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert = tokio::fs::read("tonic-examples/data/tls/server.pem").await?;
let key = tokio::fs::read("tonic-examples/data/tls/server.key").await?;
let server_identity = Identity::from_pem(cert, key);
let client_ca_cert = tokio::fs::read("tonic-examples/data/tls/client_ca.pem").await?;
let client_ca_cert = Certificate::from_pem(client_ca_cert);
let addr = "[::1]:50051".parse().unwrap();
let server = EchoServer::default();
let tls = ServerTlsConfig::with_rustls()
.identity(server_identity)
.client_ca_root(client_ca_cert);
Server::builder()
.tls_config(tls)
.add_service(pb::echo_server::EchoServer::new(server))
.serve(addr)
.await?;
Ok(())
}
+38
View File
@@ -0,0 +1,38 @@
pub mod hello_world {
tonic::include_proto!("helloworld");
}
use hello_world::{greeter_client::GreeterClient, HelloRequest};
use tracing_attributes::instrument;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.init();
say_hi("Bob".into()).await?;
Ok(())
}
#[instrument]
async fn say_hi(name: String) -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let request = tonic::Request::new(HelloRequest { name });
tracing::info!(
message = "Sending request.",
request = %request.get_ref().name
);
let response = client.say_hello(request).await?;
tracing::info!(
message = "Got a response.",
response = %response.get_ref().message
);
Ok(())
}
+51
View File
@@ -0,0 +1,51 @@
use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
use hello_world::{
greeter_server::{Greeter, GreeterServer},
HelloReply, HelloRequest,
};
#[derive(Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
tracing::info!(message = "Inbound request.", metadata = ?request.metadata());
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
};
tracing::debug!(message = "Sending reply.", response = %reply.message);
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.init();
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
tracing::info!(message = "Starting server.", %addr);
Server::builder()
.trace_fn(|_| tracing::info_span!("helloworld_server"))
.add_service(GreeterServer::new(greeter))
.serve(addr)
.await?;
Ok(())
}