-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from hubertshelley/features/grpc_support
feat(grpc): grpc support
- Loading branch information
Showing
49 changed files
with
1,266 additions
and
348 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
[package] | ||
name = "example-grpc" | ||
edition.workspace = true | ||
authors.workspace = true | ||
homepage.workspace = true | ||
license.workspace = true | ||
readme.workspace = true | ||
repository.workspace = true | ||
version.workspace = true | ||
|
||
[[bin]] | ||
name = "example-grpc-client" | ||
path = "src/client.rs" | ||
|
||
[dependencies] | ||
tonic = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } | ||
tonic-reflection = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } | ||
prost = "0.12" | ||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } | ||
silent = { path = "../../silent", features = ["grpc"] } | ||
axum = "0.7" | ||
async-trait = "0.1.80" | ||
hyper = "1.3.1" | ||
hyper-util = "0.1.3" | ||
bytes = "1.6.0" | ||
pin-project-lite = "0.2.13" | ||
http-body = "1.0.0" | ||
http = "1.1.0" | ||
http-body-util = "0.1.1" | ||
|
||
[build-dependencies] | ||
tonic-build = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
### Run server | ||
|
||
```bash | ||
cargo run -p example-grpc --bin example-grpc | ||
``` | ||
|
||
### Run client | ||
|
||
```bash | ||
cargo run -p example-grpc --bin example-grpc-server | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
fn main() { | ||
tonic_build::configure() | ||
.compile(&["proto/helloworld.proto"], &["/proto"]) | ||
.unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2015 gRPC authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
syntax = "proto3"; | ||
|
||
option java_multiple_files = true; | ||
option java_package = "io.grpc.examples.helloworld"; | ||
option java_outer_classname = "HelloWorldProto"; | ||
|
||
package helloworld; | ||
|
||
// The greeting service definition. | ||
service Greeter { | ||
// Sends a greeting | ||
rpc SayHello (HelloRequest) returns (HelloReply) {} | ||
} | ||
|
||
// The request message containing the user's name. | ||
message HelloRequest { | ||
string name = 1; | ||
} | ||
|
||
// The response message containing the greetings | ||
message HelloReply { | ||
string message = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use hello_world::greeter_client::GreeterClient; | ||
use hello_world::HelloRequest; | ||
|
||
pub mod hello_world { | ||
tonic::include_proto!("helloworld"); | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let mut client = GreeterClient::connect("http://0.0.0.0:50051").await?; | ||
|
||
let request = tonic::Request::new(HelloRequest { | ||
name: "Tonic".into(), | ||
}); | ||
|
||
let response = client.say_hello(request).await?; | ||
|
||
println!("RESPONSE={:?}", response); | ||
|
||
println!("MESSAGE={:?}", response.into_inner()); | ||
|
||
let request = tonic::Request::new(HelloRequest { | ||
name: "Tonic".into(), | ||
}); | ||
|
||
let response = client.say_hello(request).await?; | ||
|
||
println!("RESPONSE={:?}", response); | ||
|
||
println!("MESSAGE={:?}", response.into_inner()); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use async_trait::async_trait; | ||
use hello_world::greeter_server::{Greeter, GreeterServer}; | ||
use hello_world::{HelloReply, HelloRequest}; | ||
use silent::prelude::{logger, HandlerAppend, Level, Route, RouteService, Server}; | ||
use tonic::{transport::Server as TonicServer, Request, Response, Status}; | ||
|
||
mod client; | ||
|
||
pub mod hello_world { | ||
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct MyGreeter {} | ||
|
||
#[async_trait] | ||
impl Greeter for MyGreeter { | ||
async fn say_hello( | ||
&self, | ||
request: Request<HelloRequest>, // Accept request of type HelloRequest | ||
) -> Result<Response<HelloReply>, Status> { | ||
// Return an instance of type HelloReply | ||
println!("Got a request: {:?}", request); | ||
|
||
let reply = HelloReply { | ||
message: format!("Hello {}!", request.into_inner().name), // We must use .into_inner() as the fields of gRPC requests and responses are private | ||
}; | ||
|
||
Ok(Response::new(reply)) // Send back our formatted greeting | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let greeter = MyGreeter::default(); | ||
logger::fmt().with_max_level(Level::INFO).init(); | ||
let greeter_server = GreeterServer::new(greeter); | ||
let grpc = TonicServer::builder() | ||
// Wrap all services in the middleware stack | ||
.add_service(greeter_server) | ||
.into_router(); | ||
let route = Route::new("").get(|_req| async { Ok("hello world") }); | ||
let root = route.route().with_grpc(grpc.into()); | ||
Server::new() | ||
.bind("0.0.0.0:50051".parse().unwrap()) | ||
.serve(root) | ||
.await; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[package] | ||
name = "example-grpc-h2c" | ||
edition.workspace = true | ||
authors.workspace = true | ||
homepage.workspace = true | ||
license.workspace = true | ||
readme.workspace = true | ||
repository.workspace = true | ||
version.workspace = true | ||
|
||
[[bin]] | ||
name = "example-grpc-client" | ||
path = "src/client.rs" | ||
|
||
[dependencies] | ||
tonic = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } | ||
tonic-reflection = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } | ||
prost = "0.12" | ||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } | ||
silent = { path = "../../silent", features = ["grpc"] } | ||
axum = "0.7" | ||
async-trait = "0.1.80" | ||
hyper = "1.3.1" | ||
hyper-util = "0.1.3" | ||
bytes = "1.6.0" | ||
pin-project-lite = "0.2.13" | ||
http-body = "1.0.0" | ||
http = "1.1.0" | ||
http-body-util = "0.1.1" | ||
tower = "0.4.13" | ||
|
||
[build-dependencies] | ||
tonic-build = { git = "https://github.com/alexrudy/tonic", branch = "hyper-1.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
### Run server | ||
|
||
```bash | ||
cargo run -p example-grpc --bin example-grpc | ||
``` | ||
|
||
### Run client | ||
|
||
```bash | ||
cargo run -p example-grpc --bin example-grpc-server | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use std::{env, path::PathBuf}; | ||
|
||
fn main() { | ||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); | ||
|
||
tonic_build::configure() | ||
.file_descriptor_set_path(out_dir.join("helloworld_descriptor.bin")) | ||
.compile(&["proto/helloworld.proto"], &["/proto"]) | ||
.unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2015 gRPC authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
syntax = "proto3"; | ||
|
||
option java_multiple_files = true; | ||
option java_package = "io.grpc.examples.helloworld"; | ||
option java_outer_classname = "HelloWorldProto"; | ||
|
||
package helloworld; | ||
|
||
// The greeting service definition. | ||
service Greeter { | ||
// Sends a greeting | ||
rpc SayHello (HelloRequest) returns (HelloReply) {} | ||
} | ||
|
||
// The request message containing the user's name. | ||
message HelloRequest { | ||
string name = 1; | ||
} | ||
|
||
// The response message containing the greetings | ||
message HelloReply { | ||
string message = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use hello_world::greeter_client::GreeterClient; | ||
use hello_world::HelloRequest; | ||
use http::Uri; | ||
use hyper_util::client::legacy::Client; | ||
use hyper_util::rt::TokioExecutor; | ||
|
||
pub mod hello_world { | ||
tonic::include_proto!("helloworld"); | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let origin = Uri::from_static("http://[::1]:50051"); | ||
let h2c_client = h2c::H2cChannel { | ||
client: Client::builder(TokioExecutor::new()).build_http(), | ||
}; | ||
|
||
let mut client = GreeterClient::with_origin(h2c_client, origin); | ||
|
||
let request = tonic::Request::new(HelloRequest { | ||
name: "Tonic".into(), | ||
}); | ||
|
||
let response = client.say_hello(request).await?; | ||
|
||
println!("RESPONSE={:?}", response); | ||
|
||
Ok(()) | ||
} | ||
|
||
mod h2c { | ||
use std::{ | ||
pin::Pin, | ||
task::{Context, Poll}, | ||
}; | ||
|
||
use hyper::body::Incoming; | ||
use hyper_util::{ | ||
client::legacy::{connect::HttpConnector, Client}, | ||
rt::TokioExecutor, | ||
}; | ||
use tonic::body::{empty_body, BoxBody}; | ||
use tower::Service; | ||
|
||
pub struct H2cChannel { | ||
pub client: Client<HttpConnector, BoxBody>, | ||
} | ||
|
||
impl Service<http::Request<BoxBody>> for H2cChannel { | ||
type Response = http::Response<Incoming>; | ||
type Error = hyper::Error; | ||
type Future = | ||
Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>; | ||
|
||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { | ||
Poll::Ready(Ok(())) | ||
} | ||
|
||
fn call(&mut self, request: http::Request<BoxBody>) -> Self::Future { | ||
let client = self.client.clone(); | ||
|
||
Box::pin(async move { | ||
let origin = request.uri(); | ||
|
||
let h2c_req = hyper::Request::builder() | ||
.uri(origin) | ||
.method(request.method()) | ||
.header(http::header::UPGRADE, "h2c") | ||
.body(empty_body()) | ||
.unwrap(); | ||
|
||
let res = client.request(h2c_req).await.unwrap(); | ||
|
||
if res.status() != http::StatusCode::SWITCHING_PROTOCOLS { | ||
panic!("Our server didn't upgrade: {}", res.status()); | ||
} | ||
|
||
let upgraded_io = hyper::upgrade::on(res).await.unwrap(); | ||
|
||
// In an ideal world you would somehow cache this connection | ||
let (mut h2_client, conn) = | ||
hyper::client::conn::http2::Builder::new(TokioExecutor::new()) | ||
.handshake(upgraded_io) | ||
.await | ||
.unwrap(); | ||
tokio::spawn(conn); | ||
|
||
h2_client.send_request(request).await | ||
}) | ||
} | ||
} | ||
} |
Oops, something went wrong.