├── .gitignore ├── tests ├── collide │ ├── proto │ │ ├── common │ │ │ ├── nested.proto │ │ │ └── common.proto │ │ ├── hello_nested.proto │ │ └── hello.proto │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs ├── name-case │ ├── src │ │ └── lib.rs │ ├── build.rs │ ├── Cargo.toml │ └── proto │ │ └── hello.proto ├── uses_empty │ ├── proto │ │ └── uses_empty.proto │ ├── build.rs │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── multifile │ ├── build.rs │ ├── proto │ │ ├── world.proto │ │ └── hello.proto │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── unused-imports │ ├── Cargo.toml │ ├── proto │ ├── bidi.proto │ ├── client_streaming.proto │ └── server_streaming.proto │ ├── build.rs │ └── src │ └── lib.rs ├── tower-grpc ├── CHANGELOG.md ├── src │ ├── generic │ │ ├── mod.rs │ │ ├── server │ │ │ ├── client_streaming.rs │ │ │ ├── streaming.rs │ │ │ ├── grpc.rs │ │ │ ├── unary.rs │ │ │ ├── server_streaming.rs │ │ │ └── mod.rs │ │ ├── client │ │ │ └── mod.rs │ │ └── codec.rs │ ├── error.rs │ ├── lib.rs │ ├── client │ │ ├── server_streaming.rs │ │ ├── unary.rs │ │ ├── streaming.rs │ │ ├── client_streaming.rs │ │ └── mod.rs │ ├── metadata │ │ ├── mod.rs │ │ ├── encoding.rs │ │ └── key.rs │ ├── server │ │ ├── unimplemented.rs │ │ ├── client_streaming.rs │ │ ├── server_streaming.rs │ │ ├── unary.rs │ │ ├── streaming.rs │ │ └── mod.rs │ ├── response.rs │ ├── codegen.rs │ ├── request.rs │ ├── body.rs │ └── codec.rs ├── README.md ├── LICENSE └── Cargo.toml ├── tower-grpc-interop ├── Dockerfile-client-tower ├── src │ ├── util.rs │ └── server.rs ├── Dockerfile-server-go ├── build.rs ├── docker-compose.yml ├── Cargo.toml ├── proto │ └── grpc │ │ └── testing │ │ ├── empty.proto │ │ ├── test.proto │ │ └── messages.proto ├── LICENSE ├── travis-interop.sh └── README.md ├── Cargo.toml ├── tower-grpc-build ├── README.md ├── Cargo.toml ├── LICENSE └── src │ ├── client.rs │ └── lib.rs ├── tower-grpc-examples ├── README.md ├── LICENSE ├── build.rs ├── src │ ├── routeguide │ │ ├── data.rs │ │ ├── client.rs │ │ └── server.rs │ ├── helloworld │ │ ├── server.rs │ │ └── client.rs │ └── metadata │ │ ├── client.rs │ │ └── server.rs ├── proto │ ├── helloworld │ │ └── helloworld.proto │ ├── metadata │ │ └── metadata.proto │ └── routeguide │ │ └── route_guide.proto ├── Cargo.toml └── data │ └── route_guide_db.json ├── README.md ├── LICENSE └── .travis.yml /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /tests/collide/proto/common/nested.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common.nested; 4 | 5 | // The response 6 | message HelloReply { 7 | string message = 1; 8 | } 9 | -------------------------------------------------------------------------------- /tests/name-case/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate bytes; 2 | extern crate prost; 3 | extern crate tower_grpc; 4 | extern crate tower_hyper; 5 | 6 | pub mod hello { 7 | include!(concat!(env!("OUT_DIR"), "/hello.rs")); 8 | } 9 | -------------------------------------------------------------------------------- /tests/collide/proto/common/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | // A basic message 6 | message HelloRequest { 7 | message Name { 8 | string name = 1; 9 | } 10 | 11 | Name name = 1; 12 | } 13 | -------------------------------------------------------------------------------- /tower-grpc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.1 (September 27, 2019) 2 | 3 | ## Fixed 4 | - Emit `grpc-status` in initial response headers on error [#206](https://github.com/tower-rs/tower-grpc/pull/206) 5 | 6 | # 0.1.0 (June 4, 2019) 7 | 8 | - Initial release 9 | -------------------------------------------------------------------------------- /tests/uses_empty/proto/uses_empty.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package uses_empty; 4 | 5 | import "google/protobuf/empty.proto"; 6 | 7 | service UsesEmpty { 8 | rpc DoCall(google.protobuf.Empty) returns (google.protobuf.Empty) {} 9 | } 10 | -------------------------------------------------------------------------------- /tower-grpc-interop/Dockerfile-client-tower: -------------------------------------------------------------------------------- 1 | FROM rust:1.33.0 2 | 3 | COPY Cargo.toml Cargo.lock /usr/src/tower-grpc/ 4 | COPY . /usr/src/tower-grpc/ 5 | WORKDIR /usr/src/tower-grpc 6 | 7 | RUN cargo build -p tower-grpc-interop 8 | ENTRYPOINT ["/usr/src/tower-grpc/target/debug/client"] 9 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/mod.rs: -------------------------------------------------------------------------------- 1 | //! gRPC generic over encoder / decoder. 2 | 3 | pub mod client; 4 | pub mod server; 5 | 6 | mod codec; 7 | 8 | pub(crate) use self::codec::Direction; 9 | 10 | pub use self::codec::{Codec, DecodeBuf, Decoder, Encode, EncodeBuf, Encoder, Streaming}; 11 | -------------------------------------------------------------------------------- /tower-grpc-interop/src/util.rs: -------------------------------------------------------------------------------- 1 | use crate::pb; 2 | 3 | use std::{default, iter}; 4 | 5 | pub fn client_payload(size: usize) -> pb::Payload { 6 | pb::Payload { 7 | r#type: default::Default::default(), 8 | body: iter::repeat(0u8).take(size).collect(), 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "tower-grpc", 4 | "tower-grpc-build", 5 | "tower-grpc-examples", 6 | "tower-grpc-interop", 7 | 8 | # For tests 9 | "tests/multifile", 10 | "tests/collide", 11 | "tests/name-case", 12 | "tests/unused-imports", 13 | "tests/uses_empty", 14 | ] -------------------------------------------------------------------------------- /tests/name-case/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | tower_grpc_build::Config::new() 5 | .enable_server(true) 6 | .enable_client(true) 7 | .build(&["proto/hello.proto"], &["proto"]) 8 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 9 | } 10 | -------------------------------------------------------------------------------- /tests/uses_empty/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | tower_grpc_build::Config::new() 5 | .enable_server(true) 6 | .enable_client(true) 7 | .build(&["proto/uses_empty.proto"], &["proto"]) 8 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 9 | } 10 | -------------------------------------------------------------------------------- /tests/collide/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "collide" 3 | version = "0.1.0" 4 | authors = ["Carl Lerche "] 5 | publish = false 6 | 7 | [dependencies] 8 | bytes = "0.4" 9 | prost = "0.5" 10 | tower-grpc = { path = "../../tower-grpc" } 11 | 12 | [build-dependencies] 13 | tower-grpc-build = { path = "../../tower-grpc-build" } 14 | -------------------------------------------------------------------------------- /tower-grpc/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | pub(crate) type Error = Box; 4 | 5 | #[derive(Debug)] 6 | pub enum Never {} 7 | 8 | impl fmt::Display for Never { 9 | fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { 10 | match *self {} 11 | } 12 | } 13 | 14 | impl std::error::Error for Never {} 15 | -------------------------------------------------------------------------------- /tests/multifile/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | // Build multifile 5 | tower_grpc_build::Config::new() 6 | .enable_server(true) 7 | .enable_client(true) 8 | .build(&["proto/hello.proto", "proto/world.proto"], &["proto"]) 9 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 10 | } 11 | -------------------------------------------------------------------------------- /tests/uses_empty/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uses_empty" 3 | version = "0.1.0" 4 | authors = ["Carl Lerche "] 5 | publish = false 6 | 7 | [dependencies] 8 | tower-grpc = { path = "../../tower-grpc", features = ["tower-hyper"] } 9 | 10 | [build-dependencies] 11 | tower-grpc-build = { path = "../../tower-grpc-build", features = ["tower-hyper"] } 12 | -------------------------------------------------------------------------------- /tests/name-case/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "name-case" 3 | version = "0.1.0" 4 | authors = ["Eliza Weisman "] 5 | publish = false 6 | 7 | [dependencies] 8 | bytes = "0.4" 9 | prost = "0.5" 10 | tower-hyper = "0.1" 11 | tower-grpc = { path = "../../tower-grpc" } 12 | 13 | [build-dependencies] 14 | tower-grpc-build = { path = "../../tower-grpc-build" } 15 | 16 | -------------------------------------------------------------------------------- /tests/unused-imports/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unused-imports" 3 | version = "0.1.0" 4 | authors = ["Eliza Weisman "] 5 | publish = false 6 | 7 | [dependencies] 8 | bytes = "0.4" 9 | prost = "0.5" 10 | tower-hyper = "0.1" 11 | tower-grpc = { path = "../../tower-grpc" } 12 | 13 | [build-dependencies] 14 | tower-grpc-build = { path = "../../tower-grpc-build" } 15 | -------------------------------------------------------------------------------- /tests/unused-imports/proto/bidi.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package bidi; 4 | 5 | // A basic message 6 | message HelloRequest { 7 | string name = 1; 8 | } 9 | 10 | // The response 11 | message HelloReply { 12 | string message = 1; 13 | } 14 | 15 | // The greeting service definition. 16 | service Hello { 17 | rpc SayHello (stream HelloRequest) returns (stream HelloReply) {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/multifile/proto/world.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package world; 4 | 5 | // A basic message 6 | message WorldRequest { 7 | string name = 1; 8 | } 9 | 10 | // The response 11 | message WorldReply { 12 | string message = 1; 13 | } 14 | 15 | // The greeting service definition. 16 | service World { 17 | // Sends a greeting 18 | rpc SayWorld (WorldRequest) returns (WorldReply) {} 19 | } 20 | -------------------------------------------------------------------------------- /tests/unused-imports/proto/client_streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package client_streaming; 4 | 5 | // A basic message 6 | message HelloRequest { 7 | string name = 1; 8 | } 9 | 10 | // The response 11 | message HelloReply { 12 | string message = 1; 13 | } 14 | 15 | // The greeting service definition. 16 | service Hello { 17 | rpc SayHello (stream HelloRequest) returns (HelloReply) {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/unused-imports/proto/server_streaming.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package server_streaming; 4 | 5 | // A basic message 6 | message HelloRequest { 7 | string name = 1; 8 | } 9 | 10 | // The response 11 | message HelloReply { 12 | string message = 1; 13 | } 14 | 15 | // The greeting service definition. 16 | service Hello { 17 | rpc SayHello (HelloRequest) returns (stream HelloReply) {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/collide/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | // Build multifile 5 | tower_grpc_build::Config::new() 6 | .enable_server(true) 7 | .enable_client(true) 8 | .build( 9 | &["proto/hello.proto", "proto/hello_nested.proto"], 10 | &["proto"], 11 | ) 12 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 13 | } 14 | -------------------------------------------------------------------------------- /tower-grpc-build/README.md: -------------------------------------------------------------------------------- 1 | # Tower gRPC build 2 | 3 | Generates code based on `.proto` definitions. 4 | 5 | ## License 6 | 7 | This project is licensed under the [MIT license](LICENSE). 8 | 9 | ### Contribution 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally submitted 12 | for inclusion in `tower-grpc` by you, shall be licensed as MIT, without any 13 | additional terms or conditions. 14 | 15 | -------------------------------------------------------------------------------- /tests/multifile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "multifile" 3 | version = "0.1.0" 4 | authors = ["Carl Lerche "] 5 | publish = false 6 | 7 | [dependencies] 8 | bytes = "0.4" 9 | prost = "0.5" 10 | tower-hyper = "0.1" 11 | tower-grpc = { path = "../../tower-grpc", features = ["tower-hyper"] } 12 | 13 | [build-dependencies] 14 | tower-grpc-build = { path = "../../tower-grpc-build", features = ["tower-hyper"] } 15 | -------------------------------------------------------------------------------- /tower-grpc-examples/README.md: -------------------------------------------------------------------------------- 1 | # Tower gRPC examples 2 | 3 | Demonstrates how to use Tower gRPC clients and servers with code generation. 4 | 5 | ## License 6 | 7 | This project is licensed under the [MIT license](LICENSE). 8 | 9 | ### Contribution 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally submitted 12 | for inclusion in `tower-grpc` by you, shall be licensed as MIT, without any 13 | additional terms or conditions. 14 | -------------------------------------------------------------------------------- /tests/collide/proto/hello_nested.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hello.nested; 4 | 5 | import "common/common.proto"; 6 | import "common/nested.proto"; 7 | 8 | // A different HelloRequest 9 | message HelloRequest { 10 | string name = 2; 11 | } 12 | 13 | // The greeting service definition. 14 | service Hello { 15 | // Sends a greeting 16 | rpc SayHello (common.HelloRequest) returns (common.nested.HelloReply) {} 17 | 18 | rpc SayHello2 (HelloRequest) returns (common.nested.HelloReply) {} 19 | } 20 | -------------------------------------------------------------------------------- /tests/multifile/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hello; 4 | 5 | // A basic message 6 | message HelloRequest { 7 | string name = 1; 8 | } 9 | 10 | // The response 11 | message HelloReply { 12 | string message = 1; 13 | } 14 | 15 | // The greeting service definition. 16 | service Hello { 17 | // Sends a greeting 18 | rpc SayHello (HelloRequest) returns (HelloReply) {} 19 | 20 | // Receive a streaming response 21 | rpc SayHello2 (HelloRequest) returns (stream HelloReply) {} 22 | } 23 | -------------------------------------------------------------------------------- /tests/unused-imports/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | // Build unused-imports 5 | tower_grpc_build::Config::new() 6 | .enable_server(true) 7 | .enable_client(true) 8 | .build( 9 | &[ 10 | "proto/client_streaming.proto", 11 | &"proto/server_streaming.proto", 12 | &"proto/bidi.proto", 13 | ], 14 | &["proto"], 15 | ) 16 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 17 | } 18 | -------------------------------------------------------------------------------- /tower-grpc/README.md: -------------------------------------------------------------------------------- 1 | # Tower gRPC 2 | 3 | A client and server gRPC implementation based on Tower. 4 | 5 | More information about this crate can be found in the [crate documentation][dox] 6 | 7 | [dox]: https://docs.rs/tower-grpc 8 | 9 | ## License 10 | 11 | This project is licensed under the [MIT license](LICENSE). 12 | 13 | ### Contribution 14 | 15 | Unless you explicitly state otherwise, any contribution intentionally 16 | submitted for inclusion in `tower-grpc` by you, shall be licensed as 17 | MIT, without any additional terms or conditions. 18 | -------------------------------------------------------------------------------- /tests/name-case/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hello; 4 | 5 | // A different HelloRequest 6 | message HelloAPIRequest { 7 | string name = 2; 8 | } 9 | 10 | // The response message containing the greetings 11 | message HellogRPCResponse { 12 | string message = 1; 13 | } 14 | 15 | 16 | // The greeting service definition. 17 | service HelloAPI { 18 | // Sends a greeting 19 | rpc SayHello (HelloAPIRequest) returns (HellogRPCResponse) {} 20 | 21 | rpc HelloAPICall (HelloAPIRequest) returns (HellogRPCResponse) {} 22 | } 23 | -------------------------------------------------------------------------------- /tower-grpc-interop/Dockerfile-server-go: -------------------------------------------------------------------------------- 1 | FROM golang:1.9 as build 2 | 3 | ENV PACKAGE google.golang.org/grpc/interop/server 4 | ENV PACKAGEDIR $GOPATH/src/$PACKAGE 5 | 6 | RUN go get -u $PACKAGE 7 | 8 | WORKDIR $PACKAGEDIR 9 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server . 10 | 11 | FROM alpine:latest 12 | 13 | ENV PACKAGE google.golang.org/grpc/interop/server 14 | ENV PACKAGEDIR $GOPATH/src/$PACKAGE 15 | 16 | WORKDIR /root/ 17 | COPY --from=build /go/src/google.golang.org/grpc/interop/server/server . 18 | 19 | ENTRYPOINT ["./server"] -------------------------------------------------------------------------------- /tower-grpc-build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-grpc-build" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Tower Maintainers "] 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/tower-rs/tower-grpc" 9 | homepage = "https://github.com/tower-rs/tower-grpc" 10 | documentation = "https://docs.rs/tower-grpc/0.1.0" 11 | description = """ 12 | Code generation for tower-grpc 13 | """ 14 | 15 | [dependencies] 16 | codegen = "0.1.1" 17 | prost-build = "0.5" 18 | heck = "0.3" 19 | 20 | [features] 21 | tower-hyper = [] 22 | -------------------------------------------------------------------------------- /tests/collide/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hello; 4 | 5 | import "common/common.proto"; 6 | import "common/nested.proto"; 7 | 8 | // A different HelloRequest 9 | message HelloRequest { 10 | string name = 2; 11 | } 12 | 13 | // The greeting service definition. 14 | service Hello { 15 | // Sends a greeting 16 | rpc SayHello (common.HelloRequest) returns (common.nested.HelloReply) {} 17 | 18 | rpc SayHello2 (HelloRequest) returns (common.nested.HelloReply) {} 19 | 20 | rpc NameOnly (common.HelloRequest.Name) returns (common.HelloRequest.Name) {} 21 | } 22 | -------------------------------------------------------------------------------- /tower-grpc-interop/build.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc_build; 2 | 3 | fn main() { 4 | let files = &["proto/grpc/testing/test.proto"]; 5 | let dirs = &["proto/grpc/testing"]; 6 | 7 | // Build grpc-interop 8 | tower_grpc_build::Config::new() 9 | .enable_server(true) 10 | .enable_client(true) 11 | .build(files, dirs) 12 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 13 | 14 | // prevent needing to rebuild if files (or deps) haven't changed 15 | for file in files { 16 | println!("cargo:rerun-if-changed={}", file); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tower-grpc-interop/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | server-go: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile-server-go 8 | ports: 9 | - "10000:10000" 10 | 11 | client-tower: 12 | build: 13 | context: .. 14 | dockerfile: tower-grpc-interop/Dockerfile-client-tower 15 | command: 16 | - --test_case=client_streaming,empty_stream,empty_unary,large_unary,ping_pong,server_streaming,status_code_and_message,unimplemented_method,unimplemented_service,special_status_message,custom_metadata 17 | - --server_host="server-go" 18 | depends_on: 19 | - server-go 20 | -------------------------------------------------------------------------------- /tests/collide/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate bytes; 2 | extern crate prost; 3 | extern crate tower_grpc; 4 | 5 | pub mod common { 6 | include!(concat!(env!("OUT_DIR"), "/common.rs")); 7 | 8 | pub mod nested { 9 | include!(concat!(env!("OUT_DIR"), "/common.nested.rs")); 10 | } 11 | } 12 | 13 | pub mod hello { 14 | include!(concat!(env!("OUT_DIR"), "/hello.rs")); 15 | 16 | pub mod nested { 17 | include!(concat!(env!("OUT_DIR"), "/hello.nested.rs")); 18 | } 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use std::mem; 24 | 25 | #[test] 26 | fn types_are_present() { 27 | mem::size_of::(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/uses_empty/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate tower_grpc; 2 | 3 | pub mod uses_empty { 4 | include!(concat!(env!("OUT_DIR"), "/uses_empty.rs")); 5 | } 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn can_call() { 11 | use crate::uses_empty::client::UsesEmpty; 12 | use tower_grpc::codegen::client::futures::Future; 13 | use tower_grpc::generic::client::GrpcService; 14 | use tower_grpc::BoxBody; 15 | 16 | #[allow(dead_code)] 17 | fn zomg(client: &mut UsesEmpty) 18 | where 19 | T: GrpcService, 20 | { 21 | let _ = client.do_call(tower_grpc::Request::new(())).map(|resp| { 22 | let inner: () = resp.into_inner(); 23 | inner 24 | }); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/unused-imports/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Reproduction for https://github.com/tower-rs/tower-grpc/issues/56 2 | #![deny(warnings)] 3 | 4 | extern crate bytes; 5 | extern crate prost; 6 | extern crate tower_grpc; 7 | extern crate tower_hyper; 8 | 9 | pub mod server_streaming { 10 | include!(concat!(env!("OUT_DIR"), "/server_streaming.rs")); 11 | } 12 | pub mod client_streaming { 13 | include!(concat!(env!("OUT_DIR"), "/client_streaming.rs")); 14 | } 15 | pub mod bidi { 16 | include!(concat!(env!("OUT_DIR"), "/bidi.rs")); 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use std::mem; 22 | 23 | #[test] 24 | fn types_are_present() { 25 | mem::size_of::(); 26 | mem::size_of::(); 27 | mem::size_of::(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tower-grpc-interop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-grpc-interop" 3 | version = "0.0.1" 4 | edition = "2018" 5 | authors = ["Eliza Weisman "] 6 | license = "MIT" 7 | publish = false 8 | 9 | [[bin]] 10 | name = "client" 11 | path = "src/client.rs" 12 | 13 | [[bin]] 14 | name = "server" 15 | path = "src/server.rs" 16 | 17 | [dependencies] 18 | futures = "0.1.23" 19 | bytes = "0.4" 20 | pretty_env_logger = "0.2" 21 | log = "0.4" 22 | http = "0.1" 23 | prost = "0.5" 24 | tokio-core = "0.1" 25 | tokio = "0.1" 26 | tower-hyper = "0.1" 27 | tower-request-modifier = { git = "https://github.com/tower-rs/tower-http" } 28 | tower-grpc = { path = "../tower-grpc" } 29 | tower = "0.1" 30 | http-connection = "0.1" 31 | 32 | clap = "2.33.0" 33 | console = "0.7" 34 | rustls = "0.15.0" 35 | domain = "0.2.2" 36 | 37 | [build-dependencies] 38 | tower-grpc-build = { path = "../tower-grpc-build", features = ["tower-hyper"] } 39 | -------------------------------------------------------------------------------- /tower-grpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "https://docs.rs/tower-grpc/0.1.1")] 2 | #![deny(missing_debug_implementations, rust_2018_idioms)] 3 | // TODO: enable when there actually are docs 4 | // #![deny(missing_docs)] 5 | #![cfg_attr(test, deny(warnings))] 6 | 7 | //! gRPC client and server implementation based on Tower. 8 | 9 | pub mod client; 10 | pub mod generic; 11 | pub mod metadata; 12 | 13 | mod body; 14 | mod error; 15 | mod request; 16 | mod response; 17 | mod status; 18 | 19 | pub use crate::body::{Body, BoxBody}; 20 | pub use crate::request::Request; 21 | pub use crate::response::Response; 22 | pub use crate::status::{Code, Status}; 23 | 24 | #[cfg(feature = "protobuf")] 25 | pub mod server; 26 | 27 | /// Type re-exports used by generated code 28 | #[cfg(feature = "protobuf")] 29 | pub mod codegen; 30 | 31 | #[cfg(feature = "protobuf")] 32 | mod codec; 33 | 34 | #[cfg(feature = "protobuf")] 35 | pub use crate::codec::{Encode, Streaming}; 36 | -------------------------------------------------------------------------------- /tower-grpc/src/client/server_streaming.rs: -------------------------------------------------------------------------------- 1 | use super::streaming; 2 | use crate::codec::Streaming; 3 | use crate::error::Error; 4 | use crate::Body; 5 | 6 | use futures::{Future, Poll}; 7 | use http::Response; 8 | use prost::Message; 9 | 10 | #[derive(Debug)] 11 | pub struct ResponseFuture { 12 | inner: streaming::ResponseFuture, 13 | } 14 | 15 | impl ResponseFuture { 16 | /// Create a new client-streaming response future. 17 | pub(crate) fn new(inner: streaming::ResponseFuture) -> Self { 18 | ResponseFuture { inner } 19 | } 20 | } 21 | 22 | impl Future for ResponseFuture 23 | where 24 | T: Message + Default, 25 | U: Future>, 26 | U::Error: Into, 27 | B: Body, 28 | { 29 | type Item = crate::Response>; 30 | type Error = crate::Status; 31 | 32 | fn poll(&mut self) -> Poll { 33 | self.inner.poll() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tower gRPC 2 | 3 | **NOTE**: This library will remain stable on a `0.1` release while continuing to support `futures 0.1` based libraries. If you are looking for a [`std::future::Future`] version please checkout [`tonic`] as it is the next generation of `tower-grpc`. 4 | 5 | [`tonic`]: https://github.com/hyperium/tonic 6 | [`std::future::Future`]: https://doc.rust-lang.org/std/future/trait.Future.html 7 | 8 | A client and server gRPC implementation based on Tower. 9 | 10 | [![Build Status](https://travis-ci.org/tower-rs/tower-grpc.svg?branch=master)](https://travis-ci.org/tower-rs/tower-grpc) 11 | 12 | More information about this crate can be found in the [crate documentation][dox] 13 | 14 | [dox]: https://tower-rs.github.io/tower-grpc/tower_grpc 15 | 16 | ## License 17 | 18 | This project is licensed under the [MIT license](LICENSE). 19 | 20 | ### Contribution 21 | 22 | Unless you explicitly state otherwise, any contribution intentionally submitted 23 | for inclusion in `tower-grpc` by you, shall be licensed as MIT, without any 24 | additional terms or conditions. 25 | -------------------------------------------------------------------------------- /tower-grpc-interop/proto/grpc/testing/empty.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015 gRPC authors. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | syntax = "proto3"; 17 | 18 | package grpc.testing; 19 | 20 | // An empty message that you can re-use to avoid defining duplicated empty 21 | // messages in your project. A typical example is to use it as argument or the 22 | // return value of a service API. For instance: 23 | // 24 | // service Foo { 25 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 26 | // }; 27 | // 28 | message Empty {} 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 tower-grpc authors. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-grpc/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 tower-grpc authors. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-grpc-build/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 tower-grpc authors. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-grpc-examples/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 tower-grpc authors. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-grpc-interop/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 tower-grpc authors. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-grpc-examples/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Build helloworld 3 | tower_grpc_build::Config::new() 4 | .enable_server(true) 5 | .enable_client(true) 6 | .build( 7 | &["proto/helloworld/helloworld.proto"], 8 | &["proto/helloworld"], 9 | ) 10 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 11 | println!("cargo:rerun-if-changed=proto/helloworld/helloworld.proto"); 12 | 13 | // Build metadata 14 | tower_grpc_build::Config::new() 15 | .enable_server(true) 16 | .enable_client(true) 17 | .build(&["proto/metadata/metadata.proto"], &["proto/metadata"]) 18 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 19 | println!("cargo:rerun-if-changed=proto/metadata/metadata.proto"); 20 | 21 | // Build routeguide 22 | tower_grpc_build::Config::new() 23 | .enable_server(true) 24 | .enable_client(true) 25 | .build( 26 | &["proto/routeguide/route_guide.proto"], 27 | &["proto/routeguide"], 28 | ) 29 | .unwrap_or_else(|e| panic!("protobuf compilation failed: {}", e)); 30 | println!("cargo:rerun-if-changed=proto/routeguide/route_guide.proto"); 31 | } 32 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/routeguide/data.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use std::env; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | 6 | #[derive(Debug, Deserialize)] 7 | struct Feature { 8 | location: Location, 9 | name: String, 10 | } 11 | 12 | #[derive(Debug, Deserialize)] 13 | struct Location { 14 | latitude: i32, 15 | longitude: i32, 16 | } 17 | 18 | #[allow(dead_code)] 19 | pub fn load() -> Vec { 20 | let args: Vec<_> = env::args().collect(); 21 | 22 | assert_eq!(args.len(), 2, "unexpected arguments"); 23 | 24 | let mut file = File::open(&args[1]).ok().expect("failed to open data file"); 25 | let mut data = String::new(); 26 | file.read_to_string(&mut data) 27 | .ok() 28 | .expect("failed to read data file"); 29 | 30 | let decoded: Vec = serde_json::from_str(&data).unwrap(); 31 | 32 | decoded 33 | .into_iter() 34 | .map(|feature| crate::routeguide::Feature { 35 | name: feature.name, 36 | location: Some(crate::routeguide::Point { 37 | longitude: feature.location.longitude, 38 | latitude: feature.location.latitude, 39 | }), 40 | }) 41 | .collect() 42 | } 43 | -------------------------------------------------------------------------------- /tests/multifile/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate bytes; 2 | extern crate prost; 3 | extern crate tower_grpc; 4 | extern crate tower_hyper; 5 | 6 | pub mod hello { 7 | include!(concat!(env!("OUT_DIR"), "/hello.rs")); 8 | } 9 | 10 | pub mod world { 11 | include!(concat!(env!("OUT_DIR"), "/world.rs")); 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use std::mem; 17 | 18 | #[test] 19 | fn types_are_present() { 20 | mem::size_of::(); 21 | mem::size_of::(); 22 | } 23 | 24 | #[test] 25 | fn can_call() { 26 | use crate::hello::client::Hello; 27 | use crate::hello::HelloRequest; 28 | use tower_grpc::codegen::client::*; 29 | use tower_grpc::BoxBody; 30 | 31 | #[allow(dead_code)] 32 | fn zomg(client: &mut Hello) 33 | where 34 | T: ::tower_grpc::generic::client::GrpcService, 35 | { 36 | let request = HelloRequest { 37 | name: "hello".to_string(), 38 | }; 39 | 40 | let _ = client.say_hello(grpc::Request::new(request.clone())); 41 | let _ = client.say_hello2(grpc::Request::new(request.clone())); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tower-grpc-examples/proto/helloworld/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | 21 | package helloworld; 22 | 23 | // The greeting service definition. 24 | service Greeter { 25 | // Sends a greeting 26 | rpc SayHello (HelloRequest) returns (HelloReply) {} 27 | } 28 | 29 | // The request message containing the user's name. 30 | message HelloRequest { 31 | string name = 1; 32 | } 33 | 34 | // The response message containing the greetings 35 | message HelloReply { 36 | string message = 1; 37 | } 38 | -------------------------------------------------------------------------------- /tower-grpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-grpc" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update html_root_url. 6 | # - Update doc url 7 | # - Cargo.toml 8 | # - README.md 9 | # - Update CHANGELOG.md. 10 | # - Create "v0.1.x" git tag. 11 | version = "0.1.1" 12 | edition = "2018" 13 | authors = ["Tower Maintainers "] 14 | license = "MIT" 15 | readme = "README.md" 16 | repository = "https://github.com/tower-rs/tower-grpc" 17 | homepage = "https://github.com/tower-rs/tower-grpc" 18 | documentation = "https://docs.rs/tower-grpc/0.1.0" 19 | description = """ 20 | A client and server gRPC implementation based on Tower. 21 | """ 22 | 23 | [features] 24 | default = ["protobuf"] 25 | protobuf = ["prost"] 26 | 27 | [dependencies] 28 | base64 = "0.10" 29 | bytes = "0.4.7" 30 | futures = "0.1" 31 | http = "0.1.14" 32 | h2 = "0.1.11" 33 | log = "0.4" 34 | percent-encoding = "1.0.1" 35 | tower-hyper = { version = "0.1", optional = true } 36 | http-body = "0.1" 37 | tower-service = "0.2" 38 | tower-util = "0.1" 39 | 40 | # For protobuf 41 | prost = { version = "0.5", optional = true } 42 | 43 | [dev-dependencies] 44 | env_logger = { version = "0.5", default-features = false } 45 | tokio-core = "0.1" 46 | 47 | # For examples 48 | prost = "0.5" 49 | -------------------------------------------------------------------------------- /tower-grpc-examples/proto/metadata/metadata.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.metadata"; 19 | option java_outer_classname = "MetadataProto"; 20 | 21 | package metadata; 22 | 23 | // The doorman service definition. 24 | service Doorman { 25 | // Ask for permission to enter 26 | rpc AskToEnter (EnterRequest) returns (EnterReply) {} 27 | } 28 | 29 | // The request message containing a greeting. 30 | message EnterRequest { 31 | string message = 1; 32 | } 33 | 34 | // The response message containing approval to enter 35 | message EnterReply { 36 | string message = 1; 37 | } 38 | -------------------------------------------------------------------------------- /tower-grpc-examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-grpc-examples" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Carl Lerche "] 6 | publish = false 7 | 8 | [[bin]] 9 | name = "helloworld-server" 10 | path = "src/helloworld/server.rs" 11 | 12 | [[bin]] 13 | name = "helloworld-client" 14 | path = "src/helloworld/client.rs" 15 | 16 | [[bin]] 17 | name = "metadata-server" 18 | path = "src/metadata/server.rs" 19 | 20 | [[bin]] 21 | name = "metadata-client" 22 | path = "src/metadata/client.rs" 23 | 24 | [[bin]] 25 | name = "route-guide-server" 26 | path = "src/routeguide/server.rs" 27 | 28 | [[bin]] 29 | name = "route-guide-client" 30 | path = "src/routeguide/client.rs" 31 | 32 | [dependencies] 33 | futures = "0.1" 34 | bytes = "0.4" 35 | env_logger = { version = "0.5", default-features = false } 36 | log = "0.4" 37 | http = "0.1" 38 | prost = "0.5" 39 | tokio = "0.1" 40 | tower-request-modifier = { git = "https://github.com/tower-rs/tower-http" } 41 | tower-hyper = "0.1" 42 | hyper = "0.12" 43 | tower-grpc = { path = "../tower-grpc", features = ["tower-hyper"] } 44 | tower-service = "0.2" 45 | tower-util = "0.1" 46 | 47 | # For the routeguide example 48 | serde = { version = "1.0.91", features = ["derive"] } 49 | serde_json = "1.0.39" 50 | 51 | [build-dependencies] 52 | tower-grpc-build = { path = "../tower-grpc-build", features = ["tower-hyper"] } 53 | -------------------------------------------------------------------------------- /tower-grpc/src/metadata/mod.rs: -------------------------------------------------------------------------------- 1 | //! The metadata module contains data structures and utilities for handling 2 | //! gRPC custom metadata. 3 | 4 | mod encoding; 5 | mod key; 6 | mod map; 7 | mod value; 8 | 9 | pub use self::encoding::Ascii; 10 | pub use self::encoding::Binary; 11 | pub use self::key::AsciiMetadataKey; 12 | pub use self::key::BinaryMetadataKey; 13 | pub use self::key::MetadataKey; 14 | pub use self::map::Entry; 15 | pub use self::map::GetAll; 16 | pub use self::map::Iter; 17 | pub use self::map::KeyAndMutValueRef; 18 | pub use self::map::KeyAndValueRef; 19 | pub use self::map::KeyRef; 20 | pub use self::map::Keys; 21 | pub use self::map::MetadataMap; 22 | pub use self::map::OccupiedEntry; 23 | pub use self::map::VacantEntry; 24 | pub use self::map::ValueDrain; 25 | pub use self::map::ValueIter; 26 | pub use self::map::ValueRef; 27 | pub use self::map::ValueRefMut; 28 | pub use self::map::Values; 29 | pub use self::value::AsciiMetadataValue; 30 | pub use self::value::BinaryMetadataValue; 31 | pub use self::value::MetadataValue; 32 | 33 | /// The metadata::errors module contains types for errors that can occur 34 | /// while handling gRPC custom metadata. 35 | pub mod errors { 36 | pub use super::encoding::InvalidMetadataValue; 37 | pub use super::encoding::InvalidMetadataValueBytes; 38 | pub use super::key::InvalidMetadataKey; 39 | pub use super::value::ToStrError; 40 | } 41 | -------------------------------------------------------------------------------- /tower-grpc/src/server/unimplemented.rs: -------------------------------------------------------------------------------- 1 | use crate::{Code, Status}; 2 | 3 | use futures::{Future, Poll}; 4 | use http::header; 5 | 6 | #[derive(Debug)] 7 | pub struct ResponseFuture { 8 | status: Option, 9 | } 10 | 11 | impl ResponseFuture { 12 | pub(crate) fn new(msg: String) -> Self { 13 | ResponseFuture { 14 | status: Some(Status::new(Code::Unimplemented, msg)), 15 | } 16 | } 17 | } 18 | 19 | impl Future for ResponseFuture { 20 | type Item = http::Response<()>; 21 | type Error = crate::error::Never; 22 | 23 | fn poll(&mut self) -> Poll { 24 | let status = self.status.take().expect("polled after complete"); 25 | 26 | // Construct http response 27 | let mut response = http::Response::new(()); 28 | 29 | // Set the content type 30 | // As the rpc is unimplemented we don't care about 31 | // specifying the encoding (+proto, +json, +...) 32 | // so we can just return a dummy "application/grpc" 33 | response.headers_mut().insert( 34 | header::CONTENT_TYPE, 35 | header::HeaderValue::from_static("application/grpc"), 36 | ); 37 | 38 | status 39 | .add_header(response.headers_mut()) 40 | .expect("generated unimplemented message should be valid"); 41 | Ok(response.into()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tower-grpc/src/client/unary.rs: -------------------------------------------------------------------------------- 1 | use super::client_streaming; 2 | use crate::error::Error; 3 | use crate::Body; 4 | 5 | use futures::{stream, Future, Poll}; 6 | use http::Response; 7 | use prost::Message; 8 | use std::fmt; 9 | 10 | pub struct ResponseFuture { 11 | inner: client_streaming::ResponseFuture, 12 | } 13 | 14 | pub type Once = stream::Once; 15 | 16 | impl ResponseFuture { 17 | /// Create a new client-streaming response future. 18 | pub(crate) fn new(inner: client_streaming::ResponseFuture) -> Self { 19 | ResponseFuture { inner } 20 | } 21 | } 22 | 23 | impl Future for ResponseFuture 24 | where 25 | T: Message + Default, 26 | U: Future>, 27 | U::Error: Into, 28 | B: Body, 29 | B::Error: Into, 30 | { 31 | type Item = crate::Response; 32 | type Error = crate::Status; 33 | 34 | fn poll(&mut self) -> Poll { 35 | self.inner.poll() 36 | } 37 | } 38 | 39 | impl fmt::Debug for ResponseFuture 40 | where 41 | T: fmt::Debug, 42 | U: fmt::Debug, 43 | B: Body + fmt::Debug, 44 | B::Data: fmt::Debug, 45 | { 46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 47 | f.debug_struct("ResponseFuture") 48 | .field("inner", &self.inner) 49 | .finish() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/client_streaming.rs: -------------------------------------------------------------------------------- 1 | use super::streaming; 2 | use super::unary::Once; 3 | use crate::generic::{Encode, Encoder}; 4 | use crate::Response; 5 | 6 | use futures::{try_ready, Future, Poll}; 7 | 8 | #[derive(Debug)] 9 | pub struct ResponseFuture { 10 | inner: streaming::ResponseFuture, E>, 11 | } 12 | 13 | #[derive(Debug)] 14 | struct Inner { 15 | inner: T, 16 | } 17 | 18 | // ===== impl ResponseFuture ====== 19 | 20 | impl ResponseFuture 21 | where 22 | T: Future, Error = crate::Status>, 23 | E: Encoder, 24 | { 25 | pub fn new(inner: T, encoder: E) -> Self { 26 | let inner = Inner { inner }; 27 | let inner = streaming::ResponseFuture::new(inner, encoder); 28 | ResponseFuture { inner } 29 | } 30 | } 31 | 32 | impl Future for ResponseFuture 33 | where 34 | T: Future, Error = crate::Status>, 35 | E: Encoder, 36 | { 37 | type Item = http::Response>>; 38 | type Error = crate::error::Never; 39 | 40 | fn poll(&mut self) -> Poll { 41 | self.inner.poll() 42 | } 43 | } 44 | 45 | // ===== impl Inner ====== 46 | 47 | impl Future for Inner 48 | where 49 | T: Future, Error = crate::Status>, 50 | { 51 | type Item = Response>; 52 | type Error = crate::Status; 53 | 54 | fn poll(&mut self) -> Poll { 55 | let response = try_ready!(self.inner.poll()); 56 | Ok(Once::map(response).into()) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: rust 3 | sudo: false 4 | 5 | cache: cargo 6 | 7 | matrix: 8 | include: 9 | - rust: nightly 10 | - rust: stable 11 | env: RUSTFMT=1 12 | before_deploy: cargo doc --no-deps 13 | allow_failures: 14 | - rust: nightly 15 | 16 | before_script: 17 | - if [ "$RUSTFMT" = 1 ]; then rustup component add rustfmt; fi 18 | 19 | script: 20 | - if [ "$RUSTFMT" = 1 ]; then cargo fmt -- --check; fi 21 | # build test crates 22 | - cargo build --all 23 | # run unit tests 24 | - cargo test --all 25 | # run interop tests 26 | - ./tower-grpc-interop/travis-interop.sh 27 | 28 | deploy: 29 | provider: pages 30 | skip_cleanup: true 31 | github_token: $GH_TOKEN 32 | target_branch: gh-pages 33 | local_dir: target/doc 34 | on: 35 | branch: master 36 | repo: tower-rs/tower-grpc 37 | rust: stable 38 | 39 | env: 40 | global: 41 | secure: gEJMZkeE3BnKvKl4kN7YTvxBWJ2YyKqLjPf1qMUZ2ONsnsNRWHhxUambupWXoiql6Pvtr8D8uSuwNt46Ry9tH8EZq5FBh/zPt7s79d3prJMNQtICc8VLDrZQ52hYrmVoKkSQtfXL6KskCsM9IeyLUaZyOsJAjM524C2OfAlS4DBgWz/G9mBSCBvxc5GATpCl1X4kt4a8fd+q5ERjr5qIxxRiLtjH3nv/QW6IfSgbDyFt3eJa2cuYHNp6YLIikAqa6dhVKRavJEuPdQ0Z6vCX4NmYW/ncxc1FF43EPdwkD/UaF7okPhmfWaw0Lu5vauKV45xfake1dppY3b7Qfeh8uy1Pn7JEwp40chKdetOvReehS7o1Ehwzw0YOy03PYfk54WSs/SI7syrlU+0rF8wDf2lbgk61hSHVqdYbv2J6i7YdC8l1l8ouZ6X7dkuJ8T4jQx7d4CBsejbipICi8cMvu9nm8zbvL97hu2SBYM/mLS+zwz0EDEaNqQ3fh5PwtKQrSRvjL+h1sfm51akhC8/P8chwT694E4OgrRMHsq0COvz4WkoSN1+aOg4kO9iAjrvFhgOxTBsuiPkCb1u6tCnQDwJ8mst91GLmiZFIcpW8n1SmGxk7CN/d2SpscSHiAZMDsY0C2NIfWWKXE3lkuACOHHt1W3usEdp4QJrOzdjYCxI= 42 | 43 | notifications: 44 | email: 45 | on_success: never 46 | -------------------------------------------------------------------------------- /tower-grpc-interop/travis-interop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # script to run interop tests on CI. 3 | set -eu 4 | set -o pipefail 5 | 6 | # test the tower-grpc interop server first 7 | cargo build -p tower-grpc-interop --bin server 8 | ./target/debug/server & 9 | TOWER_SERVER_PID=$! 10 | echo ":; started tower-grpc test server." 11 | 12 | # run the interop test client against the server. 13 | cargo run -p tower-grpc-interop --bin client -- \ 14 | --test_case=empty_stream,empty_unary,large_unary,ping_pong,status_code_and_message,unimplemented_method,unimplemented_service,special_status_message 15 | 16 | echo ":; killing tower-grpc test server"; 17 | kill ${TOWER_SERVER_PID}; 18 | 19 | SERVER="interop-server-go-linux-amd64" 20 | SERVER_ZIP_URL="https://github.com/tower-rs/tower-grpc/files/1616271/interop-server-go-linux-amd64.zip" 21 | 22 | # download test server from grpc-go 23 | if ! [ -e "${SERVER}" ] ; then 24 | echo ":; downloading grpc-go test server" 25 | wget -O "${SERVER}.zip" "${SERVER_ZIP_URL}" 26 | unzip "${SERVER}.zip" 27 | fi 28 | 29 | # run the test server 30 | ./"${SERVER}" & 31 | SERVER_PID=$! 32 | echo ":; started grpc-go test server." 33 | 34 | # trap exits to make sure we kill the server process when the script exits, 35 | # regardless of why (errors, SIGTERM, etc). 36 | trap 'echo ":; killing test server"; kill ${SERVER_PID};' EXIT 37 | 38 | # run the interop test client against the server. 39 | cargo run -p tower-grpc-interop --bin client -- \ 40 | --test_case=client_streaming,empty_stream,empty_unary,large_unary,ping_pong,server_streaming,status_code_and_message,unimplemented_method,unimplemented_service,special_status_message,custom_metadata 41 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/helloworld/server.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | use crate::hello_world::{server, HelloReply, HelloRequest}; 4 | 5 | use futures::{future, Future, Stream}; 6 | use log::error; 7 | use tokio::net::TcpListener; 8 | use tower_grpc::{Request, Response}; 9 | use tower_hyper::server::{Http, Server}; 10 | 11 | pub mod hello_world { 12 | include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); 13 | } 14 | 15 | #[derive(Clone, Debug)] 16 | struct Greet; 17 | 18 | impl server::Greeter for Greet { 19 | type SayHelloFuture = future::FutureResult, tower_grpc::Status>; 20 | 21 | fn say_hello(&mut self, request: Request) -> Self::SayHelloFuture { 22 | println!("REQUEST = {:?}", request); 23 | 24 | let response = Response::new(HelloReply { 25 | message: "Zomg, it works!".to_string(), 26 | }); 27 | 28 | future::ok(response) 29 | } 30 | } 31 | 32 | pub fn main() { 33 | let _ = ::env_logger::init(); 34 | 35 | let new_service = server::GreeterServer::new(Greet); 36 | 37 | let mut server = Server::new(new_service); 38 | 39 | let http = Http::new().http2_only(true).clone(); 40 | 41 | let addr = "[::1]:50051".parse().unwrap(); 42 | let bind = TcpListener::bind(&addr).expect("bind"); 43 | 44 | let serve = bind 45 | .incoming() 46 | .for_each(move |sock| { 47 | if let Err(e) = sock.set_nodelay(true) { 48 | return Err(e); 49 | } 50 | 51 | let serve = server.serve_with(sock, http.clone()); 52 | tokio::spawn(serve.map_err(|e| error!("hyper error: {:?}", e))); 53 | 54 | Ok(()) 55 | }) 56 | .map_err(|e| eprintln!("accept error: {}", e)); 57 | 58 | tokio::run(serve) 59 | } 60 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/helloworld/client.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | use futures::Future; 4 | use hyper::client::connect::{Destination, HttpConnector}; 5 | use tower_grpc::Request; 6 | use tower_hyper::{client, util}; 7 | use tower_util::MakeService; 8 | 9 | pub mod hello_world { 10 | include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); 11 | } 12 | 13 | pub fn main() { 14 | let _ = ::env_logger::init(); 15 | 16 | let uri: http::Uri = format!("http://[::1]:50051").parse().unwrap(); 17 | 18 | let dst = Destination::try_from_uri(uri.clone()).unwrap(); 19 | let connector = util::Connector::new(HttpConnector::new(4)); 20 | let settings = client::Builder::new().http2_only(true).clone(); 21 | let mut make_client = client::Connect::with_builder(connector, settings); 22 | 23 | let say_hello = make_client 24 | .make_service(dst) 25 | .map_err(|e| panic!("connect error: {:?}", e)) 26 | .and_then(move |conn| { 27 | use crate::hello_world::client::Greeter; 28 | 29 | let conn = tower_request_modifier::Builder::new() 30 | .set_origin(uri) 31 | .build(conn) 32 | .unwrap(); 33 | 34 | // Wait until the client is ready... 35 | Greeter::new(conn).ready() 36 | }) 37 | .and_then(|mut client| { 38 | use crate::hello_world::HelloRequest; 39 | 40 | client.say_hello(Request::new(HelloRequest { 41 | name: "What is in a name?".to_string(), 42 | })) 43 | }) 44 | .and_then(|response| { 45 | println!("RESPONSE = {:?}", response); 46 | Ok(()) 47 | }) 48 | .map_err(|e| { 49 | println!("ERR = {:?}", e); 50 | }); 51 | 52 | tokio::run(say_hello); 53 | } 54 | -------------------------------------------------------------------------------- /tower-grpc/src/server/client_streaming.rs: -------------------------------------------------------------------------------- 1 | use crate::codec::{Encode, Encoder}; 2 | use crate::generic::server::{client_streaming, unary, ClientStreamingService}; 3 | 4 | use futures::{try_ready, Future, Poll, Stream}; 5 | use std::fmt; 6 | 7 | pub struct ResponseFuture 8 | where 9 | T: ClientStreamingService, 10 | S: Stream, 11 | { 12 | inner: Inner, 13 | } 14 | 15 | type Inner = client_streaming::ResponseFuture>; 16 | 17 | impl ResponseFuture 18 | where 19 | T: ClientStreamingService, 20 | S: Stream, 21 | S::Item: prost::Message + Default, 22 | T::Response: prost::Message, 23 | { 24 | pub(crate) fn new(inner: Inner) -> Self { 25 | ResponseFuture { inner } 26 | } 27 | } 28 | 29 | impl Future for ResponseFuture 30 | where 31 | T: ClientStreamingService, 32 | S: Stream, 33 | S::Item: prost::Message + Default, 34 | T::Response: prost::Message, 35 | { 36 | type Item = http::Response>>; 37 | type Error = crate::error::Never; 38 | 39 | fn poll(&mut self) -> Poll { 40 | let response = try_ready!(self.inner.poll()); 41 | let response = response.map(Encode::new); 42 | Ok(response.into()) 43 | } 44 | } 45 | 46 | impl fmt::Debug for ResponseFuture 47 | where 48 | T: ClientStreamingService + fmt::Debug, 49 | S: Stream + fmt::Debug, 50 | T::Response: fmt::Debug, 51 | T::Future: fmt::Debug, 52 | { 53 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 54 | fmt.debug_struct("client_streaming::ResponseFuture") 55 | .field("inner", &self.inner) 56 | .finish() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tower-grpc/src/server/server_streaming.rs: -------------------------------------------------------------------------------- 1 | use crate::codec::{Encode, Encoder, Streaming}; 2 | use crate::generic::server::{server_streaming, ServerStreamingService}; 3 | use crate::Body; 4 | 5 | use futures::{try_ready, Future, Poll}; 6 | use std::fmt; 7 | 8 | pub struct ResponseFuture 9 | where 10 | T: ServerStreamingService, 11 | B: Body, 12 | R: prost::Message + Default, 13 | { 14 | inner: Inner, 15 | } 16 | 17 | type Inner = server_streaming::ResponseFuture, Streaming>; 18 | 19 | impl ResponseFuture 20 | where 21 | T: ServerStreamingService, 22 | R: prost::Message + Default, 23 | T::Response: prost::Message, 24 | B: Body, 25 | { 26 | pub(crate) fn new(inner: Inner) -> Self { 27 | ResponseFuture { inner } 28 | } 29 | } 30 | 31 | impl Future for ResponseFuture 32 | where 33 | T: ServerStreamingService, 34 | R: prost::Message + Default, 35 | T::Response: prost::Message, 36 | B: Body, 37 | { 38 | type Item = http::Response>; 39 | type Error = crate::error::Never; 40 | 41 | fn poll(&mut self) -> Poll { 42 | let response = try_ready!(self.inner.poll()); 43 | let response = response.map(Encode::new); 44 | Ok(response.into()) 45 | } 46 | } 47 | 48 | impl fmt::Debug for ResponseFuture 49 | where 50 | T: ServerStreamingService + fmt::Debug, 51 | T::Response: fmt::Debug, 52 | T::ResponseStream: fmt::Debug, 53 | T::Future: fmt::Debug, 54 | B: Body + fmt::Debug, 55 | B::Data: fmt::Debug, 56 | R: prost::Message + Default, 57 | { 58 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 59 | fmt.debug_struct("server_streaming::ResponseFuture") 60 | .field("inner", &self.inner) 61 | .finish() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/metadata/client.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | use futures::Future; 4 | use hyper::client::connect::{Destination, HttpConnector}; 5 | use tower_grpc::Request; 6 | use tower_hyper::{client, util}; 7 | use tower_util::MakeService; 8 | 9 | pub mod metadata { 10 | include!(concat!(env!("OUT_DIR"), "/metadata.rs")); 11 | } 12 | 13 | pub fn main() { 14 | let _ = ::env_logger::init(); 15 | 16 | let uri: http::Uri = format!("http://[::1]:50051").parse().unwrap(); 17 | 18 | let dst = Destination::try_from_uri(uri.clone()).unwrap(); 19 | let connector = util::Connector::new(HttpConnector::new(4)); 20 | let settings = client::Builder::new().http2_only(true).clone(); 21 | let mut make_client = client::Connect::with_builder(connector, settings); 22 | 23 | let doorman = make_client 24 | .make_service(dst) 25 | .map_err(|e| panic!("connect error: {:?}", e)) 26 | .and_then(move |conn| { 27 | use crate::metadata::client::Doorman; 28 | 29 | let conn = tower_request_modifier::Builder::new() 30 | .set_origin(uri) 31 | .build(conn) 32 | .unwrap(); 33 | 34 | // Wait until the client is ready... 35 | Doorman::new(conn).ready() 36 | }) 37 | .and_then(|mut client| { 38 | use crate::metadata::EnterRequest; 39 | 40 | let mut request = Request::new(EnterRequest { 41 | message: "Hello! Can I come in?".to_string(), 42 | }); 43 | 44 | request 45 | .metadata_mut() 46 | .insert("metadata", "Here is a cookie".parse().unwrap()); 47 | 48 | client.ask_to_enter(request) 49 | }) 50 | .map(|response| { 51 | println!("RESPONSE = {:?}", response); 52 | }) 53 | .map_err(|e| { 54 | println!("ERR = {:?}", e); 55 | }); 56 | 57 | tokio::run(doorman); 58 | } 59 | -------------------------------------------------------------------------------- /tower-grpc/src/server/unary.rs: -------------------------------------------------------------------------------- 1 | pub use crate::generic::server::unary::Once; 2 | 3 | use crate::codec::{Decoder, Encode, Encoder}; 4 | use crate::generic::server::{unary, UnaryService}; 5 | use crate::generic::Streaming; 6 | use crate::Body; 7 | 8 | use futures::{try_ready, Future, Poll}; 9 | use std::fmt; 10 | 11 | pub struct ResponseFuture 12 | where 13 | T: UnaryService, 14 | R: prost::Message + Default, 15 | T::Response: prost::Message, 16 | B: Body, 17 | { 18 | inner: Inner, 19 | } 20 | 21 | type Inner = unary::ResponseFuture, Streaming, B>>; 22 | 23 | impl ResponseFuture 24 | where 25 | T: UnaryService, 26 | R: prost::Message + Default, 27 | T::Response: prost::Message, 28 | B: Body, 29 | { 30 | pub(crate) fn new(inner: Inner) -> Self { 31 | ResponseFuture { inner } 32 | } 33 | } 34 | 35 | impl Future for ResponseFuture 36 | where 37 | T: UnaryService, 38 | R: prost::Message + Default, 39 | T::Response: prost::Message, 40 | B: Body, 41 | { 42 | type Item = http::Response>>; 43 | type Error = crate::error::Never; 44 | 45 | fn poll(&mut self) -> Poll { 46 | let response = try_ready!(self.inner.poll()); 47 | let response = response.map(Encode::new); 48 | Ok(response.into()) 49 | } 50 | } 51 | 52 | impl fmt::Debug for ResponseFuture 53 | where 54 | T: UnaryService + fmt::Debug, 55 | R: prost::Message + Default + fmt::Debug, 56 | T::Response: prost::Message + fmt::Debug, 57 | T::Future: fmt::Debug, 58 | B: Body + fmt::Debug, 59 | B::Data: fmt::Debug, 60 | { 61 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 62 | fmt.debug_struct("unary::ResponseFuture") 63 | .field("inner", &self.inner) 64 | .finish() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tower-grpc/src/server/streaming.rs: -------------------------------------------------------------------------------- 1 | use crate::codec::{Encode, Encoder}; 2 | use crate::generic::server::{streaming, StreamingService}; 3 | 4 | use futures::{try_ready, Future, Poll, Stream}; 5 | use std::fmt; 6 | 7 | pub struct ResponseFuture 8 | where 9 | T: StreamingService, 10 | S: Stream, 11 | S::Item: prost::Message + Default, 12 | T::Response: prost::Message, 13 | { 14 | inner: Inner, 15 | } 16 | 17 | type Inner = streaming::ResponseFuture>; 18 | 19 | impl ResponseFuture 20 | where 21 | T: StreamingService, 22 | S: Stream, 23 | S::Item: prost::Message + Default, 24 | T::Response: prost::Message, 25 | { 26 | pub(crate) fn new(inner: Inner) -> Self { 27 | ResponseFuture { inner } 28 | } 29 | } 30 | 31 | impl Future for ResponseFuture 32 | where 33 | T: StreamingService, 34 | S: Stream, 35 | S::Item: prost::Message + Default, 36 | T::Response: prost::Message, 37 | { 38 | type Item = http::Response>; 39 | type Error = crate::error::Never; 40 | 41 | fn poll(&mut self) -> Poll { 42 | let response = try_ready!(self.inner.poll()); 43 | let response = response.map(Encode::new); 44 | Ok(response.into()) 45 | } 46 | } 47 | 48 | impl fmt::Debug for ResponseFuture 49 | where 50 | T: StreamingService + fmt::Debug, 51 | S: Stream + fmt::Debug, 52 | S::Item: prost::Message + Default + fmt::Debug, 53 | T::Response: prost::Message + fmt::Debug, 54 | T::ResponseStream: fmt::Debug, 55 | T::Future: fmt::Debug, 56 | { 57 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 58 | fmt.debug_struct("streaming::ResponseFuture") 59 | .field("inner", &self.inner) 60 | .finish() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tower-grpc/src/response.rs: -------------------------------------------------------------------------------- 1 | use crate::metadata::MetadataMap; 2 | 3 | /// A gRPC response and metadata from an RPC call. 4 | #[derive(Debug)] 5 | pub struct Response { 6 | metadata: MetadataMap, 7 | message: T, 8 | } 9 | 10 | impl Response { 11 | /// Create a new gRPC response. 12 | pub fn new(message: T) -> Self { 13 | Response { 14 | metadata: MetadataMap::new(), 15 | message, 16 | } 17 | } 18 | 19 | /// Get a reference to the message 20 | pub fn get_ref(&self) -> &T { 21 | &self.message 22 | } 23 | 24 | /// Get a mutable reference to the message 25 | pub fn get_mut(&mut self) -> &mut T { 26 | &mut self.message 27 | } 28 | 29 | /// Get a reference to the custom response metadata. 30 | pub fn metadata(&self) -> &MetadataMap { 31 | &self.metadata 32 | } 33 | 34 | /// Get a mutable reference to the response metadata. 35 | pub fn metadata_mut(&mut self) -> &mut MetadataMap { 36 | &mut self.metadata 37 | } 38 | 39 | /// Consumes `self`, returning the message 40 | pub fn into_inner(self) -> T { 41 | self.message 42 | } 43 | 44 | pub(crate) fn from_http(res: http::Response) -> Self { 45 | let (head, message) = res.into_parts(); 46 | Response { 47 | metadata: MetadataMap::from_headers(head.headers), 48 | message, 49 | } 50 | } 51 | 52 | pub fn into_http(self) -> http::Response { 53 | let mut res = http::Response::new(self.message); 54 | 55 | *res.version_mut() = http::Version::HTTP_2; 56 | *res.headers_mut() = self.metadata.into_headers(); 57 | 58 | res 59 | } 60 | 61 | pub fn map(self, f: F) -> Response 62 | where 63 | F: FnOnce(T) -> U, 64 | { 65 | let message = f(self.message); 66 | Response { 67 | metadata: self.metadata, 68 | message, 69 | } 70 | } 71 | 72 | // pub fn metadata() 73 | // pub fn metadata_bin() 74 | } 75 | -------------------------------------------------------------------------------- /tower-grpc/src/codegen.rs: -------------------------------------------------------------------------------- 1 | /// Type re-exports used by generated server code 2 | pub mod server { 3 | /// Re-export types from this crate 4 | pub mod grpc { 5 | pub use crate::codec::{Encode, Streaming}; 6 | pub use crate::generic::server::{ 7 | ClientStreamingService, ServerStreamingService, StreamingService, UnaryService, 8 | }; 9 | pub use crate::server::{ 10 | client_streaming, server_streaming, streaming, unary, unimplemented, 11 | }; 12 | pub use crate::{error::Never, Body, BoxBody, Code, Request, Response, Status}; 13 | } 14 | 15 | /// Re-export types from the `future` crate. 16 | pub mod futures { 17 | pub use futures::future::{ok, FutureResult}; 18 | pub use futures::{Async, Future, Poll, Stream}; 19 | } 20 | 21 | /// Re-exported types from the `http` crate. 22 | pub mod http { 23 | pub use http::{HeaderMap, Request, Response}; 24 | } 25 | 26 | /// Re-exported types from the `tower` crate. 27 | pub mod tower { 28 | pub use http_body::Body as HttpBody; 29 | pub use tower_service::Service; 30 | pub use tower_util::MakeService; 31 | } 32 | 33 | #[cfg(feature = "tower-hyper")] 34 | /// Re-exported types from `tower-hyper` crate. 35 | pub mod tower_hyper { 36 | pub use tower_hyper::Body; 37 | } 38 | } 39 | 40 | pub mod client { 41 | /// Re-export types from this crate 42 | pub mod grpc { 43 | pub use crate::client::{ 44 | client_streaming, server_streaming, streaming, unary, Encodable, Grpc, 45 | }; 46 | pub use crate::generic::client::GrpcService; 47 | pub use crate::{Body, Code, Request, Response, Status}; 48 | } 49 | 50 | pub mod http { 51 | pub use http::uri::{PathAndQuery, Uri}; 52 | } 53 | 54 | /// Re-export types from the `future` crate. 55 | pub mod futures { 56 | pub use futures::{Future, Poll, Stream}; 57 | } 58 | 59 | pub mod tower { 60 | pub use http_body::Body as HttpBody; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/metadata/server.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | use crate::metadata::{server, EnterReply, EnterRequest}; 4 | 5 | use futures::{future, Future, Stream}; 6 | use log::error; 7 | use tokio::net::TcpListener; 8 | use tower_grpc::{Request, Response}; 9 | use tower_hyper::server::{Http, Server}; 10 | 11 | pub mod metadata { 12 | include!(concat!(env!("OUT_DIR"), "/metadata.rs")); 13 | } 14 | 15 | #[derive(Clone, Debug)] 16 | struct Door; 17 | 18 | impl server::Doorman for Door { 19 | type AskToEnterFuture = future::FutureResult, tower_grpc::Status>; 20 | 21 | fn ask_to_enter(&mut self, request: Request) -> Self::AskToEnterFuture { 22 | println!("REQUEST = {:?}", request); 23 | 24 | let metadata = request 25 | .metadata() 26 | .get("metadata") 27 | .and_then(|header| header.to_str().ok()); 28 | 29 | let message = match metadata { 30 | Some("Here is a cookie") => "Yummy! Please come in.".to_string(), 31 | _ => "You cannot come in!".to_string(), 32 | }; 33 | 34 | let response = Response::new(EnterReply { message }); 35 | 36 | future::ok(response) 37 | } 38 | } 39 | 40 | pub fn main() { 41 | let _ = ::env_logger::init(); 42 | 43 | let new_service = server::DoormanServer::new(Door); 44 | 45 | let mut server = Server::new(new_service); 46 | 47 | let http = Http::new().http2_only(true).clone(); 48 | 49 | let addr = "[::1]:50051".parse().unwrap(); 50 | let bind = TcpListener::bind(&addr).expect("bind"); 51 | 52 | let serve = bind 53 | .incoming() 54 | .for_each(move |sock| { 55 | if let Err(e) = sock.set_nodelay(true) { 56 | return Err(e); 57 | } 58 | 59 | let serve = server.serve_with(sock, http.clone()); 60 | tokio::spawn(serve.map_err(|e| error!("h2 error: {:?}", e))); 61 | 62 | Ok(()) 63 | }) 64 | .map_err(|e| eprintln!("accept error: {}", e)); 65 | 66 | tokio::run(serve); 67 | } 68 | -------------------------------------------------------------------------------- /tower-grpc/src/request.rs: -------------------------------------------------------------------------------- 1 | use crate::metadata::MetadataMap; 2 | 3 | #[derive(Debug)] 4 | pub struct Request { 5 | metadata: MetadataMap, 6 | message: T, 7 | } 8 | 9 | impl Request { 10 | /// Create a new gRPC request 11 | pub fn new(message: T) -> Self { 12 | Request { 13 | metadata: MetadataMap::new(), 14 | message, 15 | } 16 | } 17 | 18 | /// Get a reference to the message 19 | pub fn get_ref(&self) -> &T { 20 | &self.message 21 | } 22 | 23 | /// Get a mutable reference to the message 24 | pub fn get_mut(&mut self) -> &mut T { 25 | &mut self.message 26 | } 27 | 28 | /// Get a reference to the custom request metadata. 29 | pub fn metadata(&self) -> &MetadataMap { 30 | &self.metadata 31 | } 32 | 33 | /// Get a mutable reference to the request metadata. 34 | pub fn metadata_mut(&mut self) -> &mut MetadataMap { 35 | &mut self.metadata 36 | } 37 | 38 | /// Consumes `self`, returning the message 39 | pub fn into_inner(self) -> T { 40 | self.message 41 | } 42 | 43 | /// Convert an HTTP request to a gRPC request 44 | pub fn from_http(http: http::Request) -> Self { 45 | let (head, message) = http.into_parts(); 46 | Request { 47 | metadata: MetadataMap::from_headers(head.headers), 48 | message, 49 | } 50 | } 51 | 52 | pub fn into_http(self, uri: http::Uri) -> http::Request { 53 | let mut request = http::Request::new(self.message); 54 | 55 | *request.version_mut() = http::Version::HTTP_2; 56 | *request.method_mut() = http::Method::POST; 57 | *request.uri_mut() = uri; 58 | *request.headers_mut() = self.metadata.into_headers(); 59 | 60 | request 61 | } 62 | 63 | pub fn map(self, f: F) -> Request 64 | where 65 | F: FnOnce(T) -> U, 66 | { 67 | let message = f(self.message); 68 | 69 | Request { 70 | metadata: self.metadata, 71 | message, 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tower-grpc/src/client/streaming.rs: -------------------------------------------------------------------------------- 1 | use crate::codec::{Direction, Streaming}; 2 | use crate::error::Error; 3 | use crate::Body; 4 | use crate::Code; 5 | 6 | use futures::{try_ready, Future, Poll}; 7 | use http::Response; 8 | use prost::Message; 9 | use std::marker::PhantomData; 10 | 11 | #[derive(Debug)] 12 | pub struct ResponseFuture { 13 | inner: U, 14 | _m: PhantomData, 15 | } 16 | 17 | impl ResponseFuture { 18 | /// Create a new client-streaming response future. 19 | pub(super) fn new(inner: U) -> Self { 20 | ResponseFuture { 21 | inner, 22 | _m: PhantomData, 23 | } 24 | } 25 | } 26 | 27 | impl Future for ResponseFuture 28 | where 29 | T: Message + Default, 30 | U: Future>, 31 | U::Error: Into, 32 | B: Body, 33 | { 34 | type Item = crate::Response>; 35 | type Error = crate::Status; 36 | 37 | fn poll(&mut self) -> Poll { 38 | use crate::codec::Decoder; 39 | use crate::generic::Streaming; 40 | 41 | // Get the response 42 | let response = try_ready!(self 43 | .inner 44 | .poll() 45 | .map_err(|err| crate::Status::from_error(&*(err.into())))); 46 | 47 | let status_code = response.status(); 48 | 49 | // Check the headers for `grpc-status`, in which case we should not parse the body. 50 | let trailers_only_status = crate::Status::from_header_map(response.headers()); 51 | let expect_additional_trailers = trailers_only_status.is_none(); 52 | if let Some(status) = trailers_only_status { 53 | if status.code() != Code::Ok { 54 | return Err(status); 55 | } 56 | } 57 | 58 | let streaming_direction = if expect_additional_trailers { 59 | Direction::Response(status_code) 60 | } else { 61 | Direction::EmptyResponse 62 | }; 63 | 64 | let response = 65 | response.map(move |body| Streaming::new(Decoder::new(), body, streaming_direction)); 66 | 67 | Ok(crate::Response::from_http(response).into()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tower-grpc/src/server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client_streaming; 2 | pub mod server_streaming; 3 | pub mod streaming; 4 | pub mod unary; 5 | pub mod unimplemented; 6 | 7 | use crate::codec::{Codec, Streaming}; 8 | use crate::generic::server::{ 9 | ClientStreamingService, Grpc, ServerStreamingService, StreamingService, UnaryService, 10 | }; 11 | use crate::Body; 12 | 13 | pub fn unary(service: T, request: http::Request) -> unary::ResponseFuture 14 | where 15 | T: UnaryService, 16 | R: prost::Message + Default, 17 | T::Response: prost::Message, 18 | B: Body, 19 | { 20 | let mut grpc = Grpc::new(Codec::new()); 21 | let inner = grpc.unary(service, request); 22 | unary::ResponseFuture::new(inner) 23 | } 24 | 25 | pub fn client_streaming( 26 | service: &mut T, 27 | request: http::Request, 28 | ) -> client_streaming::ResponseFuture> 29 | where 30 | T: ClientStreamingService>, 31 | R: prost::Message + Default, 32 | T::Response: prost::Message, 33 | B: Body, 34 | { 35 | let mut grpc = Grpc::new(Codec::new()); 36 | let inner = grpc.client_streaming(service, request); 37 | client_streaming::ResponseFuture::new(inner) 38 | } 39 | 40 | pub fn server_streaming( 41 | service: T, 42 | request: http::Request, 43 | ) -> server_streaming::ResponseFuture 44 | where 45 | T: ServerStreamingService, 46 | R: prost::Message + Default, 47 | T::Response: prost::Message, 48 | B: Body, 49 | { 50 | let mut grpc = Grpc::new(Codec::new()); 51 | let inner = grpc.server_streaming(service, request); 52 | server_streaming::ResponseFuture::new(inner) 53 | } 54 | 55 | pub fn streaming( 56 | service: &mut T, 57 | request: http::Request, 58 | ) -> streaming::ResponseFuture> 59 | where 60 | T: StreamingService>, 61 | R: prost::Message + Default, 62 | T::Response: prost::Message, 63 | B: Body, 64 | { 65 | let mut grpc = Grpc::new(Codec::new()); 66 | let inner = grpc.streaming(service, request); 67 | streaming::ResponseFuture::new(inner) 68 | } 69 | 70 | pub fn unimplemented(message: String) -> unimplemented::ResponseFuture { 71 | unimplemented::ResponseFuture::new(message) 72 | } 73 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/streaming.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Error, Never}; 2 | use crate::generic::{Encode, Encoder}; 3 | use crate::Response; 4 | 5 | use futures::{Async, Future, Poll, Stream}; 6 | use http::header; 7 | 8 | #[derive(Debug)] 9 | pub struct ResponseFuture { 10 | inner: T, 11 | encoder: Option, 12 | } 13 | 14 | // ===== impl ResponseFuture ===== 15 | 16 | impl ResponseFuture 17 | where 18 | T: Future, Error = crate::Status>, 19 | E: Encoder, 20 | S: Stream, 21 | { 22 | pub fn new(inner: T, encoder: E) -> Self { 23 | ResponseFuture { 24 | inner, 25 | encoder: Some(encoder), 26 | } 27 | } 28 | } 29 | 30 | impl Future for ResponseFuture 31 | where 32 | T: Future, Error = crate::Status>, 33 | E: Encoder, 34 | S: Stream, 35 | S::Error: Into, 36 | { 37 | type Item = http::Response>; 38 | type Error = Never; 39 | 40 | fn poll(&mut self) -> Poll { 41 | // Get the gRPC response 42 | let response = match self.inner.poll() { 43 | Ok(Async::Ready(response)) => response, 44 | Ok(Async::NotReady) => return Ok(Async::NotReady), 45 | Err(status) => { 46 | // Construct http response 47 | let mut response = Response::new(Encode::empty()).into_http(); 48 | 49 | // Set the content type and add the gRPC error codes 50 | response.headers_mut().insert( 51 | header::CONTENT_TYPE, 52 | header::HeaderValue::from_static(E::CONTENT_TYPE), 53 | ); 54 | status.add_header(response.headers_mut()).unwrap(); 55 | 56 | // Early return 57 | return Ok(response.into()); 58 | } 59 | }; 60 | 61 | // Convert to an HTTP response 62 | let mut response = response.into_http(); 63 | // Set the content type 64 | response.headers_mut().insert( 65 | header::CONTENT_TYPE, 66 | header::HeaderValue::from_static(E::CONTENT_TYPE), 67 | ); 68 | 69 | // Get the encoder 70 | let encoder = self.encoder.take().expect("encoder consumed"); 71 | 72 | // Map the response body 73 | let response = response.map(move |body| Encode::response(encoder, body)); 74 | 75 | Ok(response.into()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/grpc.rs: -------------------------------------------------------------------------------- 1 | use super::{client_streaming, server_streaming, streaming, unary}; 2 | use crate::generic::server::{ 3 | ClientStreamingService, ServerStreamingService, StreamingService, UnaryService, 4 | }; 5 | use crate::generic::{Codec, Direction, Streaming}; 6 | use crate::{Body, Request}; 7 | 8 | #[derive(Debug, Clone)] 9 | pub(crate) struct Grpc { 10 | codec: T, 11 | } 12 | 13 | // ===== impl Grpc ===== 14 | 15 | impl Grpc 16 | where 17 | T: Codec, 18 | { 19 | pub(crate) fn new(codec: T) -> Self { 20 | Grpc { codec } 21 | } 22 | 23 | pub(crate) fn unary( 24 | &mut self, 25 | service: S, 26 | request: http::Request, 27 | ) -> unary::ResponseFuture> 28 | where 29 | S: UnaryService, 30 | B: Body, 31 | { 32 | let request = self.map_request(request); 33 | unary::ResponseFuture::new(service, request, self.codec.encoder()) 34 | } 35 | 36 | pub(crate) fn client_streaming( 37 | &mut self, 38 | service: &mut S, 39 | request: http::Request, 40 | ) -> client_streaming::ResponseFuture 41 | where 42 | S: ClientStreamingService, Response = T::Encode>, 43 | B: Body, 44 | { 45 | let response = service.call(self.map_request(request)); 46 | client_streaming::ResponseFuture::new(response, self.codec.encoder()) 47 | } 48 | 49 | pub(crate) fn server_streaming( 50 | &mut self, 51 | service: S, 52 | request: http::Request, 53 | ) -> server_streaming::ResponseFuture> 54 | where 55 | S: ServerStreamingService, 56 | B: Body, 57 | { 58 | let request = self.map_request(request); 59 | server_streaming::ResponseFuture::new(service, request, self.codec.encoder()) 60 | } 61 | 62 | pub(crate) fn streaming( 63 | &mut self, 64 | service: &mut S, 65 | request: http::Request, 66 | ) -> streaming::ResponseFuture 67 | where 68 | S: StreamingService, Response = T::Encode>, 69 | B: Body, 70 | { 71 | let response = service.call(self.map_request(request)); 72 | streaming::ResponseFuture::new(response, self.codec.encoder()) 73 | } 74 | 75 | /// Map an inbound HTTP request to a streaming decoded request 76 | fn map_request(&mut self, request: http::Request) -> Request> 77 | where 78 | B: Body, 79 | { 80 | Request::from_http( 81 | request.map(|body| Streaming::new(self.codec.decoder(), body, Direction::Request)), 82 | ) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/client/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::body::{Body, HttpBody}; 2 | use crate::error::Error; 3 | 4 | use futures::{Future, Poll}; 5 | use http::{Request, Response}; 6 | use tower_service::Service; 7 | 8 | /// A specialization of tower_service::Service. 9 | /// 10 | /// Existing tower_service::Service implementations with the correct form will 11 | /// automatically implement `GrpcService`. 12 | pub trait GrpcService { 13 | /// Response body type 14 | type ResponseBody: Body + HttpBody; 15 | 16 | /// Response future 17 | type Future: Future, Error = Self::Error>; 18 | 19 | /// Error type 20 | type Error: Into; 21 | 22 | /// Poll that this service is ready. 23 | fn poll_ready(&mut self) -> Poll<(), Self::Error>; 24 | 25 | /// Call the service. 26 | fn call(&mut self, request: Request) -> Self::Future; 27 | 28 | /// Helper when needing to pass this type to bounds needing `Service`. 29 | fn into_service(self) -> IntoService 30 | where 31 | Self: Sized, 32 | { 33 | IntoService(self) 34 | } 35 | 36 | /// Helper when needing to pass this type to bounds needing `Service`. 37 | fn as_service(&mut self) -> AsService<'_, Self> 38 | where 39 | Self: Sized, 40 | { 41 | AsService(self) 42 | } 43 | } 44 | 45 | impl GrpcService for T 46 | where 47 | T: Service, Response = Response>, 48 | T::Error: Into, 49 | ResBody: Body + HttpBody, 50 | { 51 | type ResponseBody = ResBody; 52 | type Future = T::Future; 53 | type Error = T::Error; 54 | 55 | fn poll_ready(&mut self) -> Poll<(), Self::Error> { 56 | Service::poll_ready(self) 57 | } 58 | 59 | fn call(&mut self, request: Request) -> Self::Future { 60 | Service::call(self, request) 61 | } 62 | } 63 | 64 | /// Helper when needing to pass a `GrpcService` to bounds needing `Service`. 65 | #[derive(Debug)] 66 | pub struct AsService<'a, T>(&'a mut T); 67 | 68 | impl<'a, T, ReqBody> Service> for AsService<'a, T> 69 | where 70 | T: GrpcService + 'a, 71 | { 72 | type Response = Response; 73 | type Future = T::Future; 74 | type Error = T::Error; 75 | 76 | fn poll_ready(&mut self) -> Poll<(), Self::Error> { 77 | GrpcService::poll_ready(self.0) 78 | } 79 | 80 | fn call(&mut self, request: Request) -> Self::Future { 81 | GrpcService::call(self.0, request) 82 | } 83 | } 84 | 85 | /// Helper when needing to pass a `GrpcService` to bounds needing `Service`. 86 | #[derive(Debug)] 87 | pub struct IntoService(pub(crate) T); 88 | 89 | impl Service> for IntoService 90 | where 91 | T: GrpcService, 92 | { 93 | type Response = Response; 94 | type Future = T::Future; 95 | type Error = T::Error; 96 | 97 | fn poll_ready(&mut self) -> Poll<(), Self::Error> { 98 | GrpcService::poll_ready(&mut self.0) 99 | } 100 | 101 | fn call(&mut self, request: Request) -> Self::Future { 102 | GrpcService::call(&mut self.0, request) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tower-grpc-interop/proto/grpc/testing/test.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015-2016 gRPC authors. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | // An integration test service that covers all the method signature permutations 17 | // of unary/streaming requests/responses. 18 | 19 | syntax = "proto3"; 20 | 21 | import "empty.proto"; 22 | import "messages.proto"; 23 | 24 | package grpc.testing; 25 | 26 | // A simple service to test the various types of RPCs and experiment with 27 | // performance with various types of payload. 28 | service TestService { 29 | // One empty request followed by one empty response. 30 | rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); 31 | 32 | // One request followed by one response. 33 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 34 | 35 | // One request followed by one response. Response has cache control 36 | // headers set such that a caching HTTP proxy (such as GFE) can 37 | // satisfy subsequent requests. 38 | rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); 39 | 40 | // One request followed by a sequence of responses (streamed download). 41 | // The server returns the payload with client desired type and sizes. 42 | rpc StreamingOutputCall(StreamingOutputCallRequest) 43 | returns (stream StreamingOutputCallResponse); 44 | 45 | // A sequence of requests followed by one response (streamed upload). 46 | // The server returns the aggregated size of client payload as the result. 47 | rpc StreamingInputCall(stream StreamingInputCallRequest) 48 | returns (StreamingInputCallResponse); 49 | 50 | // A sequence of requests with each request served by the server immediately. 51 | // As one request could lead to multiple responses, this interface 52 | // demonstrates the idea of full duplexing. 53 | rpc FullDuplexCall(stream StreamingOutputCallRequest) 54 | returns (stream StreamingOutputCallResponse); 55 | 56 | // A sequence of requests followed by a sequence of responses. 57 | // The server buffers all the client requests and then serves them in order. A 58 | // stream of responses are returned to the client when the server starts with 59 | // first request. 60 | rpc HalfDuplexCall(stream StreamingOutputCallRequest) 61 | returns (stream StreamingOutputCallResponse); 62 | 63 | // The test server will not implement this method. It will be used 64 | // to test the behavior when clients call unimplemented methods. 65 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 66 | } 67 | 68 | // A simple service NOT implemented at servers so clients can test for 69 | // that case. 70 | service UnimplementedService { 71 | // A call that no server should implement 72 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 73 | } 74 | 75 | // A service used to control reconnect server. 76 | service ReconnectService { 77 | rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); 78 | rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); 79 | } 80 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/unary.rs: -------------------------------------------------------------------------------- 1 | use super::server_streaming; 2 | use crate::generic::server::UnaryService; 3 | use crate::generic::{Encode, Encoder}; 4 | use crate::{Request, Response}; 5 | 6 | use futures::{try_ready, Future, Poll, Stream}; 7 | use std::fmt; 8 | use tower_service::Service; 9 | 10 | pub struct ResponseFuture 11 | where 12 | T: UnaryService, 13 | S: Stream, 14 | { 15 | inner: server_streaming::ResponseFuture, E, S>, 16 | } 17 | 18 | // TODO: Use type in futures-rs instead 19 | #[derive(Debug)] 20 | pub struct Once { 21 | inner: Option, 22 | } 23 | 24 | /// Maps inbound requests 25 | #[derive(Debug, Clone)] 26 | struct Inner(pub T); 27 | 28 | #[derive(Debug)] 29 | struct InnerFuture(T); 30 | 31 | // ===== impl ResponseFuture ====== 32 | 33 | impl ResponseFuture 34 | where 35 | T: UnaryService, 36 | E: Encoder, 37 | S: Stream, 38 | { 39 | pub fn new(inner: T, request: Request, encoder: E) -> Self { 40 | let inner = server_streaming::ResponseFuture::new(Inner(inner), request, encoder); 41 | ResponseFuture { inner } 42 | } 43 | } 44 | 45 | impl Future for ResponseFuture 46 | where 47 | T: UnaryService, 48 | E: Encoder, 49 | S: Stream, 50 | { 51 | type Item = http::Response>>; 52 | type Error = crate::error::Never; 53 | 54 | fn poll(&mut self) -> Poll { 55 | self.inner.poll() 56 | } 57 | } 58 | 59 | // ===== impl Inner ===== 60 | 61 | impl Service> for Inner 62 | where 63 | T: UnaryService, 64 | { 65 | type Response = Response>; 66 | type Error = crate::Status; 67 | type Future = InnerFuture; 68 | 69 | fn poll_ready(&mut self) -> Poll<(), Self::Error> { 70 | Ok(().into()) 71 | } 72 | 73 | fn call(&mut self, request: Request) -> Self::Future { 74 | let inner = self.0.call(request); 75 | InnerFuture(inner) 76 | } 77 | } 78 | 79 | // ===== impl InnerFuture ====== 80 | 81 | impl Future for InnerFuture 82 | where 83 | T: Future, Error = crate::Status>, 84 | { 85 | type Item = Response>; 86 | type Error = crate::Status; 87 | 88 | fn poll(&mut self) -> Poll { 89 | let response = try_ready!(self.0.poll()); 90 | Ok(Once::map(response).into()) 91 | } 92 | } 93 | 94 | // ===== impl Once ===== 95 | 96 | impl Once { 97 | /// Map a response to a response of a `Once` stream 98 | pub(super) fn map(response: Response) -> Response { 99 | response.map(|body| Once { inner: Some(body) }) 100 | } 101 | } 102 | 103 | impl Stream for Once { 104 | type Item = T; 105 | type Error = crate::Status; 106 | 107 | fn poll(&mut self) -> Poll, Self::Error> { 108 | Ok(self.inner.take().into()) 109 | } 110 | } 111 | 112 | impl fmt::Debug for ResponseFuture 113 | where 114 | T: UnaryService + fmt::Debug, 115 | T::Response: fmt::Debug, 116 | T::Future: fmt::Debug, 117 | E: fmt::Debug, 118 | S: Stream + fmt::Debug, 119 | { 120 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 121 | fmt.debug_struct("unary::ResponseFuture") 122 | .field("inner", &self.inner) 123 | .finish() 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tower-grpc/src/body.rs: -------------------------------------------------------------------------------- 1 | use self::sealed::Sealed; 2 | use crate::error::Error; 3 | use crate::Status; 4 | 5 | use bytes::{Buf, Bytes, IntoBuf}; 6 | use futures::{try_ready, Poll}; 7 | pub use http_body::Body as HttpBody; 8 | use std::fmt; 9 | 10 | type BytesBuf = ::Buf; 11 | 12 | /// A "trait alias" for `tower_http_service::Body` with bounds required by 13 | /// tower-grpc. 14 | /// 15 | /// Not to be implemented directly, but instead useful for reducing bounds 16 | /// boilerplate. 17 | pub trait Body: Sealed { 18 | type Data: Buf; 19 | type Error: Into; 20 | 21 | fn is_end_stream(&self) -> bool; 22 | 23 | fn poll_data(&mut self) -> Poll, Self::Error>; 24 | 25 | fn poll_trailers(&mut self) -> Poll, Self::Error>; 26 | } 27 | 28 | impl Body for T 29 | where 30 | T: HttpBody, 31 | T::Error: Into, 32 | { 33 | type Data = T::Data; 34 | type Error = T::Error; 35 | 36 | fn is_end_stream(&self) -> bool { 37 | HttpBody::is_end_stream(self) 38 | } 39 | 40 | fn poll_data(&mut self) -> Poll, Self::Error> { 41 | HttpBody::poll_data(self) 42 | } 43 | 44 | fn poll_trailers(&mut self) -> Poll, Self::Error> { 45 | HttpBody::poll_trailers(self) 46 | } 47 | } 48 | 49 | impl Sealed for T 50 | where 51 | T: HttpBody, 52 | T::Error: Into, 53 | { 54 | } 55 | 56 | /// Dynamic `Send` body object. 57 | pub struct BoxBody { 58 | inner: Box + Send>, 59 | } 60 | 61 | struct MapBody(B); 62 | 63 | // ===== impl BoxBody ===== 64 | 65 | impl BoxBody { 66 | /// Create a new `BoxBody` backed by `inner`. 67 | pub fn new(inner: Box + Send>) -> Self { 68 | BoxBody { inner } 69 | } 70 | 71 | /// Create a new `BoxBody` mapping item and error to the default types. 72 | pub fn map_from(inner: B) -> Self 73 | where 74 | B: Body + Send + 'static, 75 | B::Data: Into, 76 | { 77 | BoxBody::new(Box::new(MapBody(inner))) 78 | } 79 | } 80 | 81 | impl HttpBody for BoxBody { 82 | type Data = BytesBuf; 83 | type Error = Status; 84 | 85 | fn is_end_stream(&self) -> bool { 86 | self.inner.is_end_stream() 87 | } 88 | 89 | fn poll_data(&mut self) -> Poll, Self::Error> { 90 | self.inner.poll_data() 91 | } 92 | 93 | fn poll_trailers(&mut self) -> Poll, Self::Error> { 94 | self.inner.poll_trailers() 95 | } 96 | } 97 | 98 | impl fmt::Debug for BoxBody { 99 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 100 | f.debug_struct("BoxBody").finish() 101 | } 102 | } 103 | 104 | // ===== impl MapBody ===== 105 | 106 | impl HttpBody for MapBody 107 | where 108 | B: Body, 109 | B::Data: Into, 110 | { 111 | type Data = BytesBuf; 112 | type Error = Status; 113 | 114 | fn is_end_stream(&self) -> bool { 115 | self.0.is_end_stream() 116 | } 117 | 118 | fn poll_data(&mut self) -> Poll, Self::Error> { 119 | let item = try_ready!(self.0.poll_data().map_err(Status::map_error)); 120 | Ok(item.map(|buf| buf.into().into_buf()).into()) 121 | } 122 | 123 | fn poll_trailers(&mut self) -> Poll, Self::Error> { 124 | self.0.poll_trailers().map_err(Status::map_error) 125 | } 126 | } 127 | 128 | mod sealed { 129 | pub trait Sealed {} 130 | } 131 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/routeguide/client.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | mod data; 4 | 5 | use crate::routeguide::{Point, RouteNote}; 6 | 7 | use futures::{Future, Stream}; 8 | use hyper::client::connect::{Destination, HttpConnector}; 9 | use std::time::{Duration, Instant}; 10 | use tokio::timer::Interval; 11 | use tower_grpc::Request; 12 | use tower_hyper::{client, util}; 13 | use tower_util::MakeService; 14 | 15 | pub mod routeguide { 16 | include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); 17 | } 18 | 19 | pub fn main() { 20 | let _ = ::env_logger::init(); 21 | 22 | let uri: http::Uri = format!("http://localhost:10000").parse().unwrap(); 23 | 24 | let dst = Destination::try_from_uri(uri.clone()).unwrap(); 25 | let connector = util::Connector::new(HttpConnector::new(4)); 26 | let settings = client::Builder::new().http2_only(true).clone(); 27 | let mut make_client = client::Connect::with_builder(connector, settings); 28 | 29 | let rg = make_client 30 | .make_service(dst) 31 | .map_err(|e| { 32 | panic!("HTTP/2 connection failed; err={:?}", e); 33 | }) 34 | .and_then(move |conn| { 35 | use crate::routeguide::client::RouteGuide; 36 | 37 | let conn = tower_request_modifier::Builder::new() 38 | .set_origin(uri) 39 | .build(conn) 40 | .unwrap(); 41 | 42 | RouteGuide::new(conn) 43 | // Wait until the client is ready... 44 | .ready() 45 | .map_err(|e| eprintln!("client closed: {:?}", e)) 46 | }) 47 | .and_then(|mut client| { 48 | let start = Instant::now(); 49 | client 50 | .get_feature(Request::new(Point { 51 | latitude: 409146138, 52 | longitude: -746188906, 53 | })) 54 | .map_err(|e| eprintln!("GetFeature request failed; err={:?}", e)) 55 | .and_then(move |response| { 56 | println!("FEATURE = {:?}", response); 57 | 58 | // Wait for the client to be ready again... 59 | client 60 | .ready() 61 | .map_err(|e| eprintln!("client closed: {:?}", e)) 62 | }) 63 | .map(move |client| (client, start)) 64 | }) 65 | .and_then(|(mut client, start)| { 66 | let outbound = Interval::new_interval(Duration::from_secs(1)) 67 | .map(move |t| { 68 | let elapsed = t.duration_since(start); 69 | RouteNote { 70 | location: Some(Point { 71 | latitude: 409146138 + elapsed.as_secs() as i32, 72 | longitude: -746188906, 73 | }), 74 | message: format!("at {:?}", elapsed), 75 | } 76 | }) 77 | .map_err(|e| panic!("timer error: {:?}", e)); 78 | 79 | client 80 | .route_chat(Request::new(outbound)) 81 | .map_err(|e| { 82 | eprintln!("RouteChat request failed; err={:?}", e); 83 | }) 84 | .and_then(|response| { 85 | let inbound = response.into_inner(); 86 | inbound 87 | .for_each(|note| { 88 | println!("NOTE = {:?}", note); 89 | Ok(()) 90 | }) 91 | .map_err(|e| eprintln!("gRPC inbound stream error: {:?}", e)) 92 | }) 93 | }); 94 | 95 | tokio::run(rg); 96 | } 97 | -------------------------------------------------------------------------------- /tower-grpc/src/client/client_streaming.rs: -------------------------------------------------------------------------------- 1 | use super::streaming; 2 | use crate::codec::Streaming; 3 | use crate::error::Error; 4 | use crate::Body; 5 | 6 | use futures::{try_ready, Future, Poll, Stream}; 7 | use http::{response, Response}; 8 | use prost::Message; 9 | use std::fmt; 10 | 11 | pub struct ResponseFuture { 12 | state: State, 13 | } 14 | 15 | enum State { 16 | /// Waiting for the HTTP response 17 | WaitResponse(streaming::ResponseFuture), 18 | /// Waiting for the gRPC Proto message in the Response body 19 | WaitMessage { 20 | head: Option, 21 | stream: Streaming, 22 | }, 23 | } 24 | 25 | impl ResponseFuture { 26 | /// Create a new client-streaming response future. 27 | pub(super) fn new(inner: streaming::ResponseFuture) -> Self { 28 | let state = State::WaitResponse(inner); 29 | ResponseFuture { state } 30 | } 31 | } 32 | 33 | impl Future for ResponseFuture 34 | where 35 | T: Message + Default, 36 | U: Future>, 37 | U::Error: Into, 38 | B: Body, 39 | B::Error: Into, 40 | { 41 | type Item = crate::Response; 42 | type Error = crate::Status; 43 | 44 | fn poll(&mut self) -> Poll { 45 | loop { 46 | let response = match self.state { 47 | State::WaitResponse(ref mut inner) => try_ready!(inner.poll()), 48 | State::WaitMessage { 49 | ref mut head, 50 | ref mut stream, 51 | } => { 52 | let message = match try_ready!(stream.poll()) { 53 | Some(message) => message, 54 | None => { 55 | return Err(crate::Status::new( 56 | crate::Code::Internal, 57 | "Missing response message.", 58 | )); 59 | } 60 | }; 61 | 62 | let head = head.take().unwrap(); 63 | let response = Response::from_parts(head, message); 64 | 65 | return Ok(crate::Response::from_http(response).into()); 66 | } 67 | }; 68 | 69 | let (head, body) = response.into_http().into_parts(); 70 | 71 | self.state = State::WaitMessage { 72 | head: Some(head), 73 | stream: body, 74 | }; 75 | } 76 | } 77 | } 78 | 79 | impl fmt::Debug for ResponseFuture 80 | where 81 | T: fmt::Debug, 82 | U: fmt::Debug, 83 | B: Body + fmt::Debug, 84 | B::Data: fmt::Debug, 85 | { 86 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 87 | f.debug_struct("ResponseFuture") 88 | .field("state", &self.state) 89 | .finish() 90 | } 91 | } 92 | 93 | impl fmt::Debug for State 94 | where 95 | T: fmt::Debug, 96 | U: fmt::Debug, 97 | B: Body + fmt::Debug, 98 | B::Data: fmt::Debug, 99 | { 100 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 101 | match *self { 102 | State::WaitResponse(ref future) => f.debug_tuple("WaitResponse").field(future).finish(), 103 | State::WaitMessage { 104 | ref head, 105 | ref stream, 106 | } => f 107 | .debug_struct("WaitMessage") 108 | .field("head", head) 109 | .field("stream", stream) 110 | .finish(), 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tower-grpc-examples/proto/routeguide/route_guide.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.routeguide"; 19 | option java_outer_classname = "RouteGuideProto"; 20 | 21 | package routeguide; 22 | 23 | // Interface exported by the server. 24 | service RouteGuide { 25 | // A simple RPC. 26 | // 27 | // Obtains the feature at a given position. 28 | // 29 | // A feature with an empty name is returned if there's no feature at the given 30 | // position. 31 | rpc GetFeature(Point) returns (Feature) {} 32 | 33 | // A server-to-client streaming RPC. 34 | // 35 | // Obtains the Features available within the given Rectangle. Results are 36 | // streamed rather than returned at once (e.g. in a response message with a 37 | // repeated field), as the rectangle may cover a large area and contain a 38 | // huge number of features. 39 | rpc ListFeatures(Rectangle) returns (stream Feature) {} 40 | 41 | // A client-to-server streaming RPC. 42 | // 43 | // Accepts a stream of Points on a route being traversed, returning a 44 | // RouteSummary when traversal is completed. 45 | rpc RecordRoute(stream Point) returns (RouteSummary) {} 46 | 47 | // A Bidirectional streaming RPC. 48 | // 49 | // Accepts a stream of RouteNotes sent while a route is being traversed, 50 | // while receiving other RouteNotes (e.g. from other users). 51 | rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 52 | } 53 | 54 | // Points are represented as latitude-longitude pairs in the E7 representation 55 | // (degrees multiplied by 10**7 and rounded to the nearest integer). 56 | // Latitudes should be in the range +/- 90 degrees and longitude should be in 57 | // the range +/- 180 degrees (inclusive). 58 | message Point { 59 | int32 latitude = 1; 60 | int32 longitude = 2; 61 | } 62 | 63 | // A latitude-longitude rectangle, represented as two diagonally opposite 64 | // points "lo" and "hi". 65 | message Rectangle { 66 | // One corner of the rectangle. 67 | Point lo = 1; 68 | 69 | // The other corner of the rectangle. 70 | Point hi = 2; 71 | } 72 | 73 | // A feature names something at a given point. 74 | // 75 | // If a feature could not be named, the name is empty. 76 | message Feature { 77 | // The name of the feature. 78 | string name = 1; 79 | 80 | // The point where the feature is detected. 81 | Point location = 2; 82 | } 83 | 84 | // A RouteNote is a message sent while at a given point. 85 | message RouteNote { 86 | // The location from which the message is sent. 87 | Point location = 1; 88 | 89 | // The message to be sent. 90 | string message = 2; 91 | } 92 | 93 | // A RouteSummary is received in response to a RecordRoute rpc. 94 | // 95 | // It contains the number of individual points received, the number of 96 | // detected features, and the total distance covered as the cumulative sum of 97 | // the distance between each point. 98 | message RouteSummary { 99 | // The number of points received. 100 | int32 point_count = 1; 101 | 102 | // The number of known features passed while traversing the route. 103 | int32 feature_count = 2; 104 | 105 | // The distance covered in metres. 106 | int32 distance = 3; 107 | 108 | // The duration of the traversal in seconds. 109 | int32 elapsed_time = 4; 110 | } 111 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/server_streaming.rs: -------------------------------------------------------------------------------- 1 | use super::streaming; 2 | use crate::generic::server::ServerStreamingService; 3 | use crate::generic::{Encode, Encoder}; 4 | use crate::{Request, Response}; 5 | 6 | use futures::{try_ready, Future, Poll, Stream}; 7 | use std::fmt; 8 | 9 | /// A server streaming response future 10 | pub struct ResponseFuture 11 | where 12 | T: ServerStreamingService, 13 | S: Stream, 14 | { 15 | inner: streaming::ResponseFuture, E>, 16 | } 17 | 18 | struct Inner 19 | where 20 | T: ServerStreamingService, 21 | S: Stream, 22 | { 23 | inner: T, 24 | state: Option>, 25 | } 26 | 27 | #[derive(Debug)] 28 | enum State { 29 | /// Waiting for the request to be received 30 | Requesting(Request), 31 | 32 | /// Waiting for the response future to resolve 33 | Responding(T), 34 | } 35 | 36 | // ===== impl ResponseFuture ====== 37 | 38 | impl ResponseFuture 39 | where 40 | T: ServerStreamingService, 41 | E: Encoder, 42 | S: Stream, 43 | { 44 | pub fn new(inner: T, request: Request, encoder: E) -> Self { 45 | let inner = Inner { 46 | inner, 47 | state: Some(State::Requesting(request)), 48 | }; 49 | 50 | let inner = streaming::ResponseFuture::new(inner, encoder); 51 | ResponseFuture { inner } 52 | } 53 | } 54 | 55 | impl Future for ResponseFuture 56 | where 57 | T: ServerStreamingService, 58 | E: Encoder, 59 | S: Stream, 60 | { 61 | type Item = http::Response>; 62 | type Error = crate::error::Never; 63 | 64 | fn poll(&mut self) -> Poll { 65 | self.inner.poll() 66 | } 67 | } 68 | 69 | // ===== impl Inner ===== 70 | 71 | impl Future for Inner 72 | where 73 | T: ServerStreamingService, 74 | S: Stream, 75 | { 76 | type Item = Response; 77 | type Error = crate::Status; 78 | 79 | fn poll(&mut self) -> Poll { 80 | use self::State::*; 81 | 82 | loop { 83 | let msg = match *self.state.as_mut().unwrap() { 84 | Requesting(ref mut request) => try_ready!(request.get_mut().poll()), 85 | Responding(ref mut fut) => { 86 | return fut.poll(); 87 | } 88 | }; 89 | 90 | match msg { 91 | Some(msg) => match self.state.take().unwrap() { 92 | Requesting(request) => { 93 | let request = request.map(|_| msg); 94 | let response = self.inner.call(request); 95 | 96 | self.state = Some(Responding(response)); 97 | } 98 | _ => unreachable!(), 99 | }, 100 | None => { 101 | return Err(crate::Status::new( 102 | crate::Code::Internal, 103 | "Missing request message.", 104 | )) 105 | } 106 | } 107 | } 108 | } 109 | } 110 | 111 | impl fmt::Debug for ResponseFuture 112 | where 113 | T: ServerStreamingService + fmt::Debug, 114 | T::Response: fmt::Debug, 115 | T::ResponseStream: fmt::Debug, 116 | T::Future: fmt::Debug, 117 | E: fmt::Debug, 118 | S: Stream + fmt::Debug, 119 | { 120 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 121 | fmt.debug_struct("server_streaming::ResponseFuture") 122 | .field("inner", &self.inner) 123 | .finish() 124 | } 125 | } 126 | 127 | impl fmt::Debug for Inner 128 | where 129 | T: ServerStreamingService + fmt::Debug, 130 | T::Response: fmt::Debug, 131 | T::ResponseStream: fmt::Debug, 132 | T::Future: fmt::Debug, 133 | S: Stream + fmt::Debug, 134 | { 135 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 136 | fmt.debug_struct("Inner") 137 | .field("inner", &self.inner) 138 | .field("state", &self.state) 139 | .finish() 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/server/mod.rs: -------------------------------------------------------------------------------- 1 | mod grpc; 2 | 3 | pub(crate) mod client_streaming; 4 | pub(crate) mod server_streaming; 5 | pub(crate) mod streaming; 6 | pub(crate) mod unary; 7 | 8 | pub(crate) use self::grpc::Grpc; 9 | 10 | use crate::{Request, Response}; 11 | 12 | use futures::{Future, Stream}; 13 | use tower_service::Service; 14 | 15 | /// A specialization of tower_service::Service. 16 | /// 17 | /// Existing tower_service::Service implementations with the correct form will 18 | /// automatically implement `GrpcService`. 19 | pub trait StreamingService { 20 | /// Protobuf response message type 21 | type Response; 22 | 23 | /// Stream of outbound response messages 24 | type ResponseStream: Stream; 25 | 26 | /// Response future 27 | type Future: Future, Error = crate::Status>; 28 | 29 | /// Call the service 30 | fn call(&mut self, request: Request) -> Self::Future; 31 | } 32 | 33 | impl StreamingService for T 34 | where 35 | T: Service, Response = Response, Error = crate::Status>, 36 | S1: Stream, 37 | S2: Stream, 38 | { 39 | type Response = S2::Item; 40 | type ResponseStream = S2; 41 | type Future = T::Future; 42 | 43 | fn call(&mut self, request: Request) -> Self::Future { 44 | Service::call(self, request) 45 | } 46 | } 47 | 48 | /// A specialization of tower_service::Service. 49 | /// 50 | /// Existing tower_service::Service implementations with the correct form will 51 | /// automatically implement `UnaryService`. 52 | pub trait UnaryService { 53 | /// Protobuf response message type 54 | type Response; 55 | 56 | /// Response future 57 | type Future: Future, Error = crate::Status>; 58 | 59 | /// Call the service 60 | fn call(&mut self, request: Request) -> Self::Future; 61 | } 62 | 63 | impl UnaryService for T 64 | where 65 | T: Service, Response = Response, Error = crate::Status>, 66 | { 67 | type Response = M2; 68 | type Future = T::Future; 69 | 70 | fn call(&mut self, request: Request) -> Self::Future { 71 | Service::call(self, request) 72 | } 73 | } 74 | 75 | /// A specialization of tower_service::Service. 76 | /// 77 | /// Existing tower_service::Service implementations with the correct form will 78 | /// automatically implement `UnaryService`. 79 | pub trait ClientStreamingService { 80 | /// Protobuf response message type 81 | type Response; 82 | 83 | /// Response future 84 | type Future: Future, Error = crate::Status>; 85 | 86 | /// Call the service 87 | fn call(&mut self, request: Request) -> Self::Future; 88 | } 89 | 90 | impl ClientStreamingService for T 91 | where 92 | T: Service, Response = Response, Error = crate::Status>, 93 | S: Stream, 94 | { 95 | type Response = M; 96 | type Future = T::Future; 97 | 98 | fn call(&mut self, request: Request) -> Self::Future { 99 | Service::call(self, request) 100 | } 101 | } 102 | 103 | /// A specialization of tower_service::Service. 104 | /// 105 | /// Existing tower_service::Service implementations with the correct form will 106 | /// automatically implement `UnaryService`. 107 | pub trait ServerStreamingService { 108 | /// Protobuf response message type 109 | type Response; 110 | 111 | /// Stream of outbound response messages 112 | type ResponseStream: Stream; 113 | 114 | /// Response future 115 | type Future: Future, Error = crate::Status>; 116 | 117 | /// Call the service 118 | fn call(&mut self, request: Request) -> Self::Future; 119 | } 120 | 121 | impl ServerStreamingService for T 122 | where 123 | T: Service, Response = Response, Error = crate::Status>, 124 | S: Stream, 125 | { 126 | type Response = S::Item; 127 | type ResponseStream = S; 128 | type Future = T::Future; 129 | 130 | fn call(&mut self, request: Request) -> Self::Future { 131 | Service::call(self, request) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /tower-grpc-interop/README.md: -------------------------------------------------------------------------------- 1 | # tower-grpc-interop 2 | 3 | The [gRPC interoperability test cases](https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md) for `tower-grpc`. 4 | 5 | ## Checklist 6 | 7 | Note that currently, only the interop test client is implemented. The `docker-compose.yml` in this directory will run the `tower-grpc` interop client against the test server from `grpc-go`. 8 | 9 | - [x] `empty_unary`: implemented in client 10 | - [ ] `cacheable_unary`: started, requires request context implementation to set cacheable flag 11 | - [x] `large_unary`: implemented in client 12 | - [ ] ~`client_compressed_unary`~: requires gRPC compression, NYI 13 | - [ ] ~`server_compressed_unary`~: requires gRPC compression, NYI 14 | - [x] `client_streaming`: implemented in client 15 | - [ ] ~`client_compressed_streaming`~: requires gRPC compression, NYI 16 | - [x] `server_streaming` 17 | - [ ] ~`server_compressed_streaming`~: requires gRPC compression, NYI 18 | - [x] `ping_pong` 19 | - [x] `empty_stream` 20 | - [ ] ~`compute_engine_creds`~ requires auth, NYI 21 | - [ ] ~`jwt_token_creds`~ requires auth, NYI 22 | - [ ] ~`oauth2_auth_token`~ requires auth, NYI 23 | - [ ] ~`per_rpc_creds`~ requires auth, NYI 24 | - [ ] `custom_metadata` 25 | - [x] `status_code_and_message` 26 | - [x] `special_status_message` 27 | - [x] `unimplemented_method` 28 | - [x] `unimplemented_service` 29 | - [ ] `cancel_after_begin` 30 | - [ ] `cancel_after_first_response` 31 | - [ ] `timeout_on_sleeping_server` 32 | - [ ] `concurrent_large_unary` 33 | 34 | ## Running 35 | 36 | Run the test client: 37 | 38 | ```bash 39 | $ cargo run -p tower-grpc-interop --bin client -- --help 40 | interop-client 41 | Eliza Weisman 42 | 43 | USAGE: 44 | client [FLAGS] [OPTIONS] 45 | 46 | FLAGS: 47 | -h, --help Prints help information 48 | --use_test_ca Whether to replace platform root CAs with ca.pem as the CA root. 49 | -V, --version Prints version information 50 | 51 | OPTIONS: 52 | --ca_file The file containing the CA root cert file [default: ca.pem] 53 | --default_service_account Email of the GCE default service account. 54 | --oauth_scope 55 | The scope for OAuth2 tokens. For example, "https://www.googleapis.com/auth/xapi.zoo". 56 | 57 | --server_host 58 | The server host to connect to. For example, "localhost" or "127.0.0.1" [default: 127.0.0.1] 59 | 60 | --server_host_override 61 | The server host to claim to be connecting to, for use in TLS and HTTP/2 :authority header. If unspecified, 62 | the value of `--server_host` will be used 63 | --server_port 64 | The server port to connect to. For example, "8080". [default: 10000] 65 | 66 | --service_account_key_file 67 | The path to the service account JSON key file generated from GCE developer console. 68 | 69 | --test_case 70 | The name of the test case to execute. For example, 71 | "empty_unary". [default: large_unary] [values: empty_unary, cacheable_unary, large_unary, 72 | client_compressed_unary, server_compressed_unary, client_streaming, client_compressed_streaming, 73 | server_streaming, server_compressed_streaming, ping_pong, empty_stream, compute_engine_creds, 74 | jwt_token_creds, oauth2_auth_token, per_rpc_creds, custom_metadata, status_code_and_message, 75 | special_status_message, unimplemented_method, unimplemented_service, cancel_after_begin, 76 | cancel_after_first_response, timeout_on_sleeping_server, concurrent_large_unary] 77 | --use_tls 78 | Whether to use a plaintext or encrypted connection. [default: false] [values: true, false] 79 | ``` 80 | 81 | Run the test server (currently not yet implemented): 82 | 83 | ```bash 84 | $ cargo run -p tower-grpc-interop --bin server 85 | ``` 86 | 87 | The `docker-compose.yml` in this directory can also be used to run the `tower-grpc` test client against `grpc-go`'s test server. From the repository root directory: 88 | 89 | ```bash 90 | $ docker-compose --file=tower-grpc-interop/docker-compose.yml up --exit-code-from client-tower 91 | ``` 92 | 93 | ## License 94 | 95 | This project is licensed under the [MIT license](LICENSE). 96 | 97 | ### Contribution 98 | 99 | Unless you explicitly state otherwise, any contribution intentionally submitted 100 | for inclusion in `tower-grpc` by you, shall be licensed as MIT, without any 101 | additional terms or conditions. 102 | -------------------------------------------------------------------------------- /tower-grpc/src/codec.rs: -------------------------------------------------------------------------------- 1 | use crate::body::{BoxBody, HttpBody}; 2 | use crate::generic::{DecodeBuf, EncodeBuf}; 3 | 4 | use bytes::BufMut; 5 | use futures::{Poll, Stream}; 6 | use prost::DecodeError; 7 | use prost::Message; 8 | 9 | use std::fmt; 10 | use std::marker::PhantomData; 11 | 12 | /// Protobuf codec 13 | #[derive(Debug)] 14 | pub struct Codec(PhantomData<(T, U)>); 15 | 16 | #[derive(Debug)] 17 | pub struct Encoder(PhantomData); 18 | 19 | #[derive(Debug)] 20 | pub struct Decoder(PhantomData); 21 | 22 | /// A stream of inbound gRPC messages 23 | pub type Streaming = crate::generic::Streaming, B>; 24 | 25 | pub(crate) use crate::generic::Direction; 26 | 27 | /// A protobuf encoded gRPC response body 28 | pub struct Encode 29 | where 30 | T: Stream, 31 | { 32 | inner: crate::generic::Encode, T>, 33 | } 34 | 35 | // ===== impl Codec ===== 36 | 37 | impl Codec 38 | where 39 | T: Message, 40 | U: Message + Default, 41 | { 42 | /// Create a new protobuf codec 43 | pub fn new() -> Self { 44 | Codec(PhantomData) 45 | } 46 | } 47 | 48 | impl crate::generic::Codec for Codec 49 | where 50 | T: Message, 51 | U: Message + Default, 52 | { 53 | type Encode = T; 54 | type Encoder = Encoder; 55 | type Decode = U; 56 | type Decoder = Decoder; 57 | 58 | fn encoder(&mut self) -> Self::Encoder { 59 | Encoder(PhantomData) 60 | } 61 | 62 | fn decoder(&mut self) -> Self::Decoder { 63 | Decoder(PhantomData) 64 | } 65 | } 66 | 67 | impl Clone for Codec { 68 | fn clone(&self) -> Self { 69 | Codec(PhantomData) 70 | } 71 | } 72 | 73 | // ===== impl Encoder ===== 74 | 75 | impl Encoder 76 | where 77 | T: Message, 78 | { 79 | pub fn new() -> Self { 80 | Encoder(PhantomData) 81 | } 82 | } 83 | 84 | impl crate::generic::Encoder for Encoder 85 | where 86 | T: Message, 87 | { 88 | type Item = T; 89 | 90 | /// Protocol buffer gRPC content type 91 | const CONTENT_TYPE: &'static str = "application/grpc+proto"; 92 | 93 | fn encode(&mut self, item: T, buf: &mut EncodeBuf<'_>) -> Result<(), crate::Status> { 94 | let len = item.encoded_len(); 95 | 96 | if buf.remaining_mut() < len { 97 | buf.reserve(len); 98 | } 99 | 100 | item.encode(buf) 101 | .map_err(|_| unreachable!("Message only errors if not enough space")) 102 | } 103 | } 104 | 105 | impl Clone for Encoder { 106 | fn clone(&self) -> Self { 107 | Encoder(PhantomData) 108 | } 109 | } 110 | 111 | // ===== impl Decoder ===== 112 | 113 | impl Decoder 114 | where 115 | T: Message + Default, 116 | { 117 | /// Returns a new decoder 118 | pub fn new() -> Self { 119 | Decoder(PhantomData) 120 | } 121 | } 122 | 123 | fn from_decode_error(error: DecodeError) -> crate::Status { 124 | // Map Protobuf parse errors to an INTERNAL status code, as per 125 | // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md 126 | crate::Status::new(crate::Code::Internal, error.to_string()) 127 | } 128 | 129 | impl crate::generic::Decoder for Decoder 130 | where 131 | T: Message + Default, 132 | { 133 | type Item = T; 134 | 135 | fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result { 136 | Message::decode(buf).map_err(from_decode_error) 137 | } 138 | } 139 | 140 | impl Clone for Decoder { 141 | fn clone(&self) -> Self { 142 | Decoder(PhantomData) 143 | } 144 | } 145 | 146 | // ===== impl Encode ===== 147 | 148 | impl Encode 149 | where 150 | T: Stream, 151 | T::Item: ::prost::Message, 152 | { 153 | pub(crate) fn new(inner: crate::generic::Encode, T>) -> Self { 154 | Encode { inner } 155 | } 156 | } 157 | 158 | impl HttpBody for Encode 159 | where 160 | T: Stream, 161 | T::Item: ::prost::Message, 162 | { 163 | type Data = , T> as HttpBody>::Data; 164 | type Error = , T> as HttpBody>::Error; 165 | 166 | fn is_end_stream(&self) -> bool { 167 | self.inner.is_end_stream() 168 | } 169 | 170 | fn poll_data(&mut self) -> Poll, Self::Error> { 171 | self.inner.poll_data() 172 | } 173 | 174 | fn poll_trailers(&mut self) -> Poll, Self::Error> { 175 | self.inner.poll_trailers() 176 | } 177 | } 178 | 179 | impl fmt::Debug for Encode 180 | where 181 | T: Stream + fmt::Debug, 182 | T::Item: fmt::Debug, 183 | T::Error: fmt::Debug, 184 | { 185 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 186 | fmt.debug_struct("Encode") 187 | .field("inner", &self.inner) 188 | .finish() 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /tower-grpc/src/client/mod.rs: -------------------------------------------------------------------------------- 1 | //! gRPC client 2 | 3 | pub mod client_streaming; 4 | pub mod server_streaming; 5 | pub mod streaming; 6 | pub mod unary; 7 | 8 | use crate::body::BoxBody; 9 | use crate::generic::client::{GrpcService, IntoService}; 10 | 11 | use futures::{stream, Future, Poll, Stream}; 12 | use http::{uri, Uri}; 13 | use prost::Message; 14 | 15 | /// gRPC client handle. 16 | /// 17 | /// Takes an HTTP service and adds the gRPC protocol. 18 | #[derive(Debug, Clone)] 19 | pub struct Grpc { 20 | /// The inner HTTP/2.0 service. 21 | inner: T, 22 | } 23 | 24 | /// Convert a stream of protobuf messages to an HTTP body payload. 25 | pub trait Encodable { 26 | fn into_encode(self) -> T; 27 | } 28 | 29 | // ===== impl Grpc ===== 30 | 31 | impl Grpc { 32 | /// Create a new `Grpc` instance backed by the given HTTP service. 33 | pub fn new(inner: T) -> Self { 34 | Grpc { inner } 35 | } 36 | 37 | /// Returns `Ready` when the service is ready to accept a request. 38 | pub fn poll_ready(&mut self) -> Poll<(), crate::Status> 39 | where 40 | T: GrpcService, 41 | { 42 | self.inner 43 | .poll_ready() 44 | .map_err(|err| crate::Status::from_error(&*(err.into()))) 45 | } 46 | 47 | /// Consumes `self`, returning a future that yields `self` back once it is ready to accept a 48 | /// request. 49 | pub fn ready(self) -> impl Future 50 | where 51 | T: GrpcService, 52 | { 53 | use tower_util::Ready; 54 | Ready::new(self.inner.into_service()) 55 | .map(|IntoService(inner)| Grpc { inner }) 56 | .map_err(|err| crate::Status::from_error(&*(err.into()))) 57 | } 58 | 59 | /// Send a unary gRPC request. 60 | pub fn unary( 61 | &mut self, 62 | request: crate::Request, 63 | path: uri::PathAndQuery, 64 | ) -> unary::ResponseFuture 65 | where 66 | T: GrpcService, 67 | unary::Once: Encodable, 68 | { 69 | let request = request.map(|v| stream::once(Ok(v))); 70 | let response = self.client_streaming(request, path); 71 | 72 | unary::ResponseFuture::new(response) 73 | } 74 | 75 | /// Send a client streaing gRPC request. 76 | pub fn client_streaming( 77 | &mut self, 78 | request: crate::Request, 79 | path: uri::PathAndQuery, 80 | ) -> client_streaming::ResponseFuture 81 | where 82 | T: GrpcService, 83 | B: Encodable, 84 | { 85 | let response = self.streaming(request, path); 86 | client_streaming::ResponseFuture::new(response) 87 | } 88 | 89 | /// Send a server streaming gRPC request. 90 | pub fn server_streaming( 91 | &mut self, 92 | request: crate::Request, 93 | path: uri::PathAndQuery, 94 | ) -> server_streaming::ResponseFuture 95 | where 96 | T: GrpcService, 97 | unary::Once: Encodable, 98 | { 99 | let request = request.map(|v| stream::once(Ok(v))); 100 | let response = self.streaming(request, path); 101 | 102 | server_streaming::ResponseFuture::new(response) 103 | } 104 | 105 | /// Initiate a full streaming gRPC request 106 | /// 107 | /// # Generics 108 | /// 109 | /// **B**: The request stream of gRPC message values. 110 | /// **M**: The response **message** (not stream) type. 111 | /// **R**: The type of the request body. 112 | pub fn streaming( 113 | &mut self, 114 | request: crate::Request, 115 | path: uri::PathAndQuery, 116 | ) -> streaming::ResponseFuture 117 | where 118 | T: GrpcService, 119 | B: Encodable, 120 | { 121 | use http::header::{self, HeaderValue}; 122 | 123 | // TODO: validate the path 124 | 125 | // Get the gRPC's method URI 126 | let mut parts = uri::Parts::default(); 127 | parts.path_and_query = Some(path); 128 | 129 | // Get the URI; 130 | let uri = Uri::from_parts(parts).expect("path_and_query only is valid Uri"); 131 | 132 | // Convert the request body 133 | let request = request.map(Encodable::into_encode); 134 | 135 | // Convert to an HTTP request 136 | let mut request = request.into_http(uri); 137 | 138 | // Add the gRPC related HTTP headers 139 | request 140 | .headers_mut() 141 | .insert(header::TE, HeaderValue::from_static("trailers")); 142 | 143 | // Set the content type 144 | // TODO: Don't hard code this here 145 | let content_type = "application/grpc+proto"; 146 | request 147 | .headers_mut() 148 | .insert(header::CONTENT_TYPE, HeaderValue::from_static(content_type)); 149 | 150 | // Call the inner HTTP service 151 | let response = self.inner.call(request); 152 | 153 | streaming::ResponseFuture::new(response) 154 | } 155 | } 156 | 157 | // ===== impl Encodable ===== 158 | 159 | impl Encodable for T 160 | where 161 | T: Stream + Send + 'static, 162 | U: Message + 'static, 163 | { 164 | fn into_encode(self) -> BoxBody { 165 | use crate::codec::Encoder; 166 | use crate::generic::Encode; 167 | 168 | let encode = Encode::request(Encoder::new(), self); 169 | BoxBody::new(Box::new(encode)) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /tower-grpc-interop/proto/grpc/testing/messages.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015-2016 gRPC authors. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | // Message definitions to be used by integration test service definitions. 17 | 18 | syntax = "proto3"; 19 | 20 | package grpc.testing; 21 | 22 | // TODO(dgq): Go back to using well-known types once 23 | // https://github.com/grpc/grpc/issues/6980 has been fixed. 24 | // import "google/protobuf/wrappers.proto"; 25 | message BoolValue { 26 | // The bool value. 27 | bool value = 1; 28 | } 29 | 30 | // DEPRECATED, don't use. To be removed shortly. 31 | // The type of payload that should be returned. 32 | enum PayloadType { 33 | // Compressable text format. 34 | COMPRESSABLE = 0; 35 | } 36 | 37 | // A block of data, to simply increase gRPC message size. 38 | message Payload { 39 | // DEPRECATED, don't use. To be removed shortly. 40 | // The type of data in body. 41 | PayloadType type = 1; 42 | // Primary contents of payload. 43 | bytes body = 2; 44 | } 45 | 46 | // A protobuf representation for grpc status. This is used by test 47 | // clients to specify a status that the server should attempt to return. 48 | message EchoStatus { 49 | int32 code = 1; 50 | string message = 2; 51 | } 52 | 53 | // Unary request. 54 | message SimpleRequest { 55 | // DEPRECATED, don't use. To be removed shortly. 56 | // Desired payload type in the response from the server. 57 | // If response_type is RANDOM, server randomly chooses one from other formats. 58 | PayloadType response_type = 1; 59 | 60 | // Desired payload size in the response from the server. 61 | int32 response_size = 2; 62 | 63 | // Optional input payload sent along with the request. 64 | Payload payload = 3; 65 | 66 | // Whether SimpleResponse should include username. 67 | bool fill_username = 4; 68 | 69 | // Whether SimpleResponse should include OAuth scope. 70 | bool fill_oauth_scope = 5; 71 | 72 | // Whether to request the server to compress the response. This field is 73 | // "nullable" in order to interoperate seamlessly with clients not able to 74 | // implement the full compression tests by introspecting the call to verify 75 | // the response's compression status. 76 | BoolValue response_compressed = 6; 77 | 78 | // Whether server should return a given status 79 | EchoStatus response_status = 7; 80 | 81 | // Whether the server should expect this request to be compressed. 82 | BoolValue expect_compressed = 8; 83 | } 84 | 85 | // Unary response, as configured by the request. 86 | message SimpleResponse { 87 | // Payload to increase message size. 88 | Payload payload = 1; 89 | // The user the request came from, for verifying authentication was 90 | // successful when the client expected it. 91 | string username = 2; 92 | // OAuth scope. 93 | string oauth_scope = 3; 94 | } 95 | 96 | // Client-streaming request. 97 | message StreamingInputCallRequest { 98 | // Optional input payload sent along with the request. 99 | Payload payload = 1; 100 | 101 | // Whether the server should expect this request to be compressed. This field 102 | // is "nullable" in order to interoperate seamlessly with servers not able to 103 | // implement the full compression tests by introspecting the call to verify 104 | // the request's compression status. 105 | BoolValue expect_compressed = 2; 106 | 107 | // Not expecting any payload from the response. 108 | } 109 | 110 | // Client-streaming response. 111 | message StreamingInputCallResponse { 112 | // Aggregated size of payloads received from the client. 113 | int32 aggregated_payload_size = 1; 114 | } 115 | 116 | // Configuration for a particular response. 117 | message ResponseParameters { 118 | // Desired payload sizes in responses from the server. 119 | int32 size = 1; 120 | 121 | // Desired interval between consecutive responses in the response stream in 122 | // microseconds. 123 | int32 interval_us = 2; 124 | 125 | // Whether to request the server to compress the response. This field is 126 | // "nullable" in order to interoperate seamlessly with clients not able to 127 | // implement the full compression tests by introspecting the call to verify 128 | // the response's compression status. 129 | BoolValue compressed = 3; 130 | } 131 | 132 | // Server-streaming request. 133 | message StreamingOutputCallRequest { 134 | // DEPRECATED, don't use. To be removed shortly. 135 | // Desired payload type in the response from the server. 136 | // If response_type is RANDOM, the payload from each response in the stream 137 | // might be of different types. This is to simulate a mixed type of payload 138 | // stream. 139 | PayloadType response_type = 1; 140 | 141 | // Configuration for each expected response message. 142 | repeated ResponseParameters response_parameters = 2; 143 | 144 | // Optional input payload sent along with the request. 145 | Payload payload = 3; 146 | 147 | // Whether server should return a given status 148 | EchoStatus response_status = 7; 149 | } 150 | 151 | // Server-streaming response, as configured by the request and parameters. 152 | message StreamingOutputCallResponse { 153 | // Payload to increase response size. 154 | Payload payload = 1; 155 | } 156 | 157 | // For reconnect interop test only. 158 | // Client tells server what reconnection parameters it used. 159 | message ReconnectParams { 160 | int32 max_reconnect_backoff_ms = 1; 161 | } 162 | 163 | // For reconnect interop test only. 164 | // Server tells client whether its reconnects are following the spec and the 165 | // reconnect backoffs it saw. 166 | message ReconnectInfo { 167 | bool passed = 1; 168 | repeated int32 backoff_ms = 2; 169 | } 170 | -------------------------------------------------------------------------------- /tower-grpc-build/src/client.rs: -------------------------------------------------------------------------------- 1 | use super::ImportType; 2 | use crate::comments_to_rustdoc; 3 | 4 | /// Generates service code 5 | pub struct ServiceGenerator; 6 | 7 | // ===== impl ServiceGenerator ===== 8 | 9 | impl ServiceGenerator { 10 | pub fn generate(&self, service: &prost_build::Service, scope: &mut codegen::Scope) { 11 | self.define(service, scope); 12 | } 13 | 14 | fn define(&self, service: &prost_build::Service, scope: &mut codegen::Scope) { 15 | // Create scope that contains the generated client code. 16 | let scope = scope 17 | .get_or_new_module("client") 18 | .vis("pub") 19 | .import("::tower_grpc::codegen::client", "*") 20 | .scope(); 21 | 22 | self.import_message_types(service, scope); 23 | self.define_client_struct(service, scope); 24 | self.define_client_impl(service, scope); 25 | } 26 | 27 | fn import_message_types(&self, service: &prost_build::Service, scope: &mut codegen::Scope) { 28 | for method in &service.methods { 29 | scope.import_type(&method.input_type, 1); 30 | scope.import_type(&method.output_type, 1); 31 | } 32 | } 33 | 34 | fn define_client_struct(&self, service: &prost_build::Service, scope: &mut codegen::Scope) { 35 | scope 36 | .new_struct(&service.name) 37 | .vis("pub") 38 | .generic("T") 39 | .derive("Debug") 40 | .derive("Clone") 41 | .doc(&comments_to_rustdoc(&service.comments)) 42 | .field("inner", "grpc::Grpc"); 43 | } 44 | 45 | fn define_client_impl(&self, service: &prost_build::Service, scope: &mut codegen::Scope) { 46 | let imp = scope 47 | .new_impl(&service.name) 48 | .generic("T") 49 | .target_generic("T"); 50 | 51 | // TODO: figure out what to do about potential conflicts with these 52 | // "inherent" methods and those from the gRPC service methods. 53 | // 54 | // For instance, if the service had a method named "new". 55 | 56 | imp.new_fn("new") 57 | .vis("pub") 58 | .arg("inner", "T") 59 | .ret("Self") 60 | .line("let inner = grpc::Grpc::new(inner);") 61 | .line("Self { inner }"); 62 | 63 | imp.new_fn("poll_ready") 64 | .doc("Poll whether this client is ready to send another request.") 65 | .generic("R") 66 | .bound("T", "grpc::GrpcService") 67 | .vis("pub") 68 | .arg_mut_self() 69 | .ret("futures::Poll<(), grpc::Status>") 70 | .line("self.inner.poll_ready()"); 71 | 72 | imp.new_fn("ready") 73 | .doc("Get a `Future` of when this client is ready to send another request.") 74 | .generic("R") 75 | .bound("T", "grpc::GrpcService") 76 | .vis("pub") 77 | .arg_self() 78 | .ret("impl futures::Future") 79 | .line("futures::Future::map(self.inner.ready(), |inner| Self { inner })"); 80 | 81 | for method in &service.methods { 82 | let name = &method.name; 83 | let path = crate::method_path(service, method); 84 | let input_type = crate::unqualified(&method.input_type, &method.input_proto_type, 1); 85 | let output_type = crate::unqualified(&method.output_type, &method.output_proto_type, 1); 86 | 87 | let func = imp 88 | .new_fn(&name) 89 | .vis("pub") 90 | .generic("R") 91 | .bound("T", "grpc::GrpcService") 92 | .arg_mut_self() 93 | .line(format!( 94 | "let path = http::PathAndQuery::from_static({});", 95 | path 96 | )) 97 | .doc(&comments_to_rustdoc(&service.comments)); 98 | 99 | let mut request = codegen::Type::new("grpc::Request"); 100 | 101 | let req_body = match (method.client_streaming, method.server_streaming) { 102 | (false, false) => { 103 | let ret = format!( 104 | "grpc::unary::ResponseFuture<{}, T::Future, T::ResponseBody>", 105 | output_type 106 | ); 107 | 108 | request.generic(&input_type); 109 | 110 | func.ret(ret).line("self.inner.unary(request, path)"); 111 | 112 | format!("grpc::unary::Once<{}>", input_type) 113 | } 114 | (false, true) => { 115 | let ret = format!( 116 | "grpc::server_streaming::ResponseFuture<{}, T::Future>", 117 | output_type 118 | ); 119 | 120 | request.generic(&input_type); 121 | 122 | func.ret(ret) 123 | .line("self.inner.server_streaming(request, path)"); 124 | 125 | format!("grpc::unary::Once<{}>", input_type) 126 | } 127 | (true, false) => { 128 | let ret = format!( 129 | "grpc::client_streaming::ResponseFuture<{}, T::Future, T::ResponseBody>", 130 | output_type 131 | ); 132 | 133 | request.generic("B"); 134 | 135 | func.generic("B") 136 | .bound("B", &format!("futures::Stream", input_type,)) 137 | .ret(ret) 138 | .line("self.inner.client_streaming(request, path)"); 139 | 140 | "B".to_string() 141 | } 142 | (true, true) => { 143 | let ret = format!( 144 | "grpc::streaming::ResponseFuture<{}, T::Future>", 145 | output_type 146 | ); 147 | 148 | request.generic("B"); 149 | 150 | func.generic("B") 151 | .bound("B", &format!("futures::Stream", input_type,)) 152 | .ret(ret) 153 | .line("self.inner.streaming(request, path)"); 154 | 155 | "B".to_string() 156 | } 157 | }; 158 | 159 | func.arg("request", request) 160 | .bound(&req_body, "grpc::Encodable"); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tower-grpc/src/metadata/encoding.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use http::header::HeaderValue; 3 | use std::error::Error; 4 | use std::fmt; 5 | use std::hash::Hash; 6 | 7 | /// A possible error when converting a `MetadataValue` from a string or byte 8 | /// slice. 9 | #[derive(Debug)] 10 | pub struct InvalidMetadataValue { 11 | _priv: (), 12 | } 13 | 14 | mod value_encoding { 15 | use super::InvalidMetadataValueBytes; 16 | use bytes::Bytes; 17 | use http::header::HeaderValue; 18 | use std::fmt; 19 | 20 | pub trait Sealed { 21 | #[doc(hidden)] 22 | fn is_empty(value: &[u8]) -> bool; 23 | 24 | #[doc(hidden)] 25 | fn from_bytes(value: &[u8]) -> Result; 26 | 27 | #[doc(hidden)] 28 | fn from_shared(value: Bytes) -> Result; 29 | 30 | #[doc(hidden)] 31 | fn from_static(value: &'static str) -> HeaderValue; 32 | 33 | #[doc(hidden)] 34 | fn decode(value: &[u8]) -> Result; 35 | 36 | #[doc(hidden)] 37 | fn equals(a: &HeaderValue, b: &[u8]) -> bool; 38 | 39 | #[doc(hidden)] 40 | fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool; 41 | 42 | #[doc(hidden)] 43 | fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result; 44 | } 45 | } 46 | 47 | pub trait ValueEncoding: Clone + Eq + PartialEq + Hash + self::value_encoding::Sealed { 48 | /// Returns true if the provided key is valid for this ValueEncoding type. 49 | /// For example, `Ascii::is_valid_key("a") == true`, 50 | /// `Ascii::is_valid_key("a-bin") == false`. 51 | fn is_valid_key(key: &str) -> bool; 52 | } 53 | 54 | #[derive(Clone, Debug, Eq, PartialEq, Hash)] 55 | pub enum Ascii {} 56 | #[derive(Clone, Debug, Eq, PartialEq, Hash)] 57 | pub enum Binary {} 58 | 59 | // ===== impl ValueEncoding ===== 60 | 61 | impl self::value_encoding::Sealed for Ascii { 62 | fn is_empty(value: &[u8]) -> bool { 63 | value.is_empty() 64 | } 65 | 66 | fn from_bytes(value: &[u8]) -> Result { 67 | HeaderValue::from_bytes(value).map_err(|_| InvalidMetadataValueBytes::new()) 68 | } 69 | 70 | fn from_shared(value: Bytes) -> Result { 71 | HeaderValue::from_shared(value).map_err(|_| InvalidMetadataValueBytes::new()) 72 | } 73 | 74 | fn from_static(value: &'static str) -> HeaderValue { 75 | HeaderValue::from_static(value) 76 | } 77 | 78 | fn decode(value: &[u8]) -> Result { 79 | Ok(Bytes::from(value)) 80 | } 81 | 82 | fn equals(a: &HeaderValue, b: &[u8]) -> bool { 83 | a.as_bytes() == b 84 | } 85 | 86 | fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool { 87 | a == b 88 | } 89 | 90 | fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { 91 | fmt::Debug::fmt(value, f) 92 | } 93 | } 94 | 95 | impl ValueEncoding for Ascii { 96 | fn is_valid_key(key: &str) -> bool { 97 | !Binary::is_valid_key(key) 98 | } 99 | } 100 | 101 | impl self::value_encoding::Sealed for Binary { 102 | fn is_empty(value: &[u8]) -> bool { 103 | for c in value { 104 | if *c != b'=' { 105 | return false; 106 | } 107 | } 108 | true 109 | } 110 | 111 | fn from_bytes(value: &[u8]) -> Result { 112 | let encoded_value: String = base64::encode_config(value, base64::STANDARD_NO_PAD); 113 | HeaderValue::from_shared(encoded_value.into()).map_err(|_| InvalidMetadataValueBytes::new()) 114 | } 115 | 116 | fn from_shared(value: Bytes) -> Result { 117 | Self::from_bytes(value.as_ref()) 118 | } 119 | 120 | fn from_static(value: &'static str) -> HeaderValue { 121 | if !base64::decode(value).is_ok() { 122 | panic!("Invalid base64 passed to from_static: {}", value); 123 | } 124 | unsafe { 125 | // Because this is valid base64 this must be a valid HTTP header value, 126 | // no need to check again by calling from_shared. 127 | HeaderValue::from_shared_unchecked(Bytes::from_static(value.as_ref())) 128 | } 129 | } 130 | 131 | fn decode(value: &[u8]) -> Result { 132 | base64::decode(value) 133 | .map(|bytes_vec| bytes_vec.into()) 134 | .map_err(|_| InvalidMetadataValueBytes::new()) 135 | } 136 | 137 | fn equals(a: &HeaderValue, b: &[u8]) -> bool { 138 | if let Ok(decoded) = base64::decode(a.as_bytes()) { 139 | decoded == b 140 | } else { 141 | a.as_bytes() == b 142 | } 143 | } 144 | 145 | fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool { 146 | let decoded_a = Self::decode(a.as_bytes()); 147 | let decoded_b = Self::decode(b.as_bytes()); 148 | if decoded_a.is_ok() && decoded_b.is_ok() { 149 | decoded_a.unwrap() == decoded_b.unwrap() 150 | } else { 151 | !decoded_a.is_ok() && !decoded_b.is_ok() 152 | } 153 | } 154 | 155 | fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { 156 | if let Ok(decoded) = Self::decode(value.as_bytes()) { 157 | write!(f, "{:?}", decoded) 158 | } else { 159 | write!(f, "b[invalid]{:?}", value) 160 | } 161 | } 162 | } 163 | 164 | impl ValueEncoding for Binary { 165 | fn is_valid_key(key: &str) -> bool { 166 | key.ends_with("-bin") 167 | } 168 | } 169 | 170 | // ===== impl InvalidMetadataValue ===== 171 | 172 | impl InvalidMetadataValue { 173 | pub(crate) fn new() -> Self { 174 | InvalidMetadataValue { _priv: () } 175 | } 176 | } 177 | 178 | impl fmt::Display for InvalidMetadataValue { 179 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 180 | self.description().fmt(f) 181 | } 182 | } 183 | 184 | impl Error for InvalidMetadataValue { 185 | fn description(&self) -> &str { 186 | "failed to parse metadata value" 187 | } 188 | } 189 | 190 | /// A possible error when converting a `MetadataValue` from a string or byte 191 | /// slice. 192 | #[derive(Debug)] 193 | pub struct InvalidMetadataValueBytes(InvalidMetadataValue); 194 | 195 | // ===== impl InvalidMetadataValueBytes ===== 196 | 197 | impl InvalidMetadataValueBytes { 198 | pub(crate) fn new() -> Self { 199 | InvalidMetadataValueBytes(InvalidMetadataValue::new()) 200 | } 201 | } 202 | 203 | impl fmt::Display for InvalidMetadataValueBytes { 204 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 205 | self.0.fmt(f) 206 | } 207 | } 208 | 209 | impl Error for InvalidMetadataValueBytes { 210 | fn description(&self) -> &str { 211 | self.0.description() 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /tower-grpc-build/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "https://docs.rs/tower-grpc-build/0.1.0")] 2 | #![deny(rust_2018_idioms)] 3 | #![cfg_attr(test, deny(warnings))] 4 | 5 | mod client; 6 | mod server; 7 | 8 | use heck::CamelCase; 9 | use std::io; 10 | use std::path::Path; 11 | 12 | /// Code generation configuration 13 | pub struct Config { 14 | prost: prost_build::Config, 15 | build_client: bool, 16 | build_server: bool, 17 | } 18 | 19 | struct ServiceGenerator { 20 | client: Option, 21 | server: Option, 22 | root_scope: codegen::Scope, 23 | } 24 | 25 | impl Config { 26 | /// Returns a new `Config` with pre-configured prost. 27 | /// 28 | /// You can tweak the configuration how the proto buffers are generated and use this config. 29 | pub fn from_prost(prost: prost_build::Config) -> Self { 30 | Config { 31 | prost, 32 | // Enable client code gen by default 33 | build_client: true, 34 | 35 | // Disable server code gen by default 36 | build_server: false, 37 | } 38 | } 39 | 40 | /// Returns a new `Config` with default values. 41 | pub fn new() -> Self { 42 | Self::from_prost(prost_build::Config::new()) 43 | } 44 | 45 | /// Enable gRPC client code generation 46 | pub fn enable_client(&mut self, enable: bool) -> &mut Self { 47 | self.build_client = enable; 48 | self 49 | } 50 | 51 | /// Enable gRPC server code generation 52 | pub fn enable_server(&mut self, enable: bool) -> &mut Self { 53 | self.build_server = enable; 54 | self 55 | } 56 | 57 | /// Generate code 58 | pub fn build

(&mut self, protos: &[P], includes: &[P]) -> io::Result<()> 59 | where 60 | P: AsRef, 61 | { 62 | let client = if self.build_client { 63 | Some(client::ServiceGenerator) 64 | } else { 65 | None 66 | }; 67 | let server = if self.build_server { 68 | Some(server::ServiceGenerator) 69 | } else { 70 | None 71 | }; 72 | 73 | // Set or reset the service generator. 74 | self.prost.service_generator(Box::new(ServiceGenerator { 75 | client, 76 | server, 77 | root_scope: codegen::Scope::new(), 78 | })); 79 | 80 | self.prost.compile_protos(protos, includes) 81 | } 82 | } 83 | 84 | impl prost_build::ServiceGenerator for ServiceGenerator { 85 | fn generate(&mut self, service: prost_build::Service, _buf: &mut String) { 86 | // Note that neither this implementation of `generate` nor the 87 | // implementations for `client::ServiceGenerator` and 88 | // `server::ServiceGenerator` will actually output any code to the 89 | // buffer; all code is written out in the implementation of the 90 | // `ServiceGenerator::finalize` function on this type. 91 | if let Some(ref mut client_generator) = self.client { 92 | client_generator.generate(&service, &mut self.root_scope); 93 | } 94 | if let Some(ref mut server_generator) = self.server { 95 | server_generator.generate(&service, &mut self.root_scope); 96 | } 97 | } 98 | 99 | fn finalize(&mut self, buf: &mut String) { 100 | // Rather than outputting each service to the buffer as it's generated, 101 | // we generate the code in our root `codegen::Scope`, which is shared 102 | // between the generation of each service in the proto file. Unlike a 103 | // string, codegen provides us with something not unlike a simplified 104 | // Rust AST, making it easier for us to add new items to modules 105 | // defined by previous service generator invocations. As we want to 106 | // output the client and server implementations for each service in the 107 | // proto file in one `client` or `server` module in the generated code, 108 | // we wait until all the services have been generated before actually 109 | // outputting to the buffer. 110 | let mut fmt = codegen::Formatter::new(buf); 111 | self.root_scope 112 | .fmt(&mut fmt) 113 | .expect("formatting root scope failed!"); 114 | // Reset the root scope so that the service generator is ready to 115 | // generate another file. this prevents the code generated for *this* 116 | // file being present in the next file. 117 | self.root_scope = codegen::Scope::new(); 118 | } 119 | } 120 | 121 | /// Extension trait for importing generated types into `codegen::Scope`s. 122 | trait ImportType { 123 | fn import_type(&mut self, ty: &str, level: usize); 124 | } 125 | 126 | // ===== impl ImportType ===== 127 | 128 | impl ImportType for codegen::Scope { 129 | fn import_type(&mut self, ty: &str, level: usize) { 130 | if !is_imported_type(ty) && !is_native_type(ty) { 131 | let (path, ty) = super_import(ty, level); 132 | 133 | self.import(&path, &ty); 134 | } 135 | } 136 | } 137 | 138 | impl ImportType for codegen::Module { 139 | fn import_type(&mut self, ty: &str, level: usize) { 140 | self.scope().import_type(ty, level); 141 | } 142 | } 143 | 144 | // ===== utility fns ===== 145 | 146 | fn method_path(service: &prost_build::Service, method: &prost_build::Method) -> String { 147 | format!( 148 | "\"/{}.{}/{}\"", 149 | service.package, service.proto_name, method.proto_name 150 | ) 151 | } 152 | 153 | fn lower_name(name: &str) -> String { 154 | let mut ret = String::new(); 155 | 156 | for (i, ch) in name.chars().enumerate() { 157 | if ch.is_uppercase() { 158 | if i != 0 { 159 | ret.push('_'); 160 | } 161 | 162 | ret.push(ch.to_ascii_lowercase()); 163 | } else { 164 | ret.push(ch); 165 | } 166 | } 167 | 168 | ret 169 | } 170 | 171 | fn should_import(ty: &str) -> bool { 172 | !is_imported_type(ty) && !is_native_type(ty) 173 | } 174 | 175 | fn is_imported_type(ty: &str) -> bool { 176 | ty.split("::").map(|t| t == "super").next().unwrap() 177 | } 178 | 179 | fn is_native_type(ty: &str) -> bool { 180 | match ty { 181 | "()" => true, 182 | _ => false, 183 | } 184 | } 185 | 186 | fn super_import(ty: &str, level: usize) -> (String, String) { 187 | let mut v: Vec<&str> = ty.split("::").collect(); 188 | 189 | assert!(!is_imported_type(ty)); 190 | assert!(!is_native_type(ty)); 191 | 192 | for _ in 0..level { 193 | v.insert(0, "super"); 194 | } 195 | 196 | let ty = v.pop().unwrap_or(ty); 197 | 198 | (v.join("::"), ty.to_string()) 199 | } 200 | 201 | fn unqualified(ty: &str, proto_ty: &str, level: usize) -> String { 202 | if proto_ty == ".google.protobuf.Empty" { 203 | return "()".to_string(); 204 | } 205 | 206 | if !is_imported_type(ty) { 207 | return ty.to_string(); 208 | } 209 | 210 | let mut v: Vec<&str> = ty.split("::").collect(); 211 | 212 | for _ in 0..level { 213 | v.insert(0, "super"); 214 | } 215 | 216 | v.join("::") 217 | } 218 | 219 | /// Converts a `snake_case` identifier to an `UpperCamel` case Rust type 220 | /// identifier. 221 | /// 222 | /// This is identical to the same [function] in `prost-build`, however, we 223 | /// reproduce it here as `prost` does not publically export it. 224 | /// 225 | /// We need this as `prost-build` will only give us the snake-case transformed 226 | /// names for gRPC methods, but we need to use method names in types as well. 227 | /// 228 | /// [function]: https://github.com/danburkert/prost/blob/d3b971ccd90df35d16069753d52289c0c85014e4/prost-build/src/ident.rs#L28-L38 229 | fn to_upper_camel(s: &str) -> String { 230 | let mut ident = s.to_camel_case(); 231 | 232 | // Add a trailing underscore if the identifier matches a Rust keyword 233 | // (https://doc.rust-lang.org/grammar.html#keywords). 234 | if ident == "Self" { 235 | ident.push('_'); 236 | } 237 | ident 238 | } 239 | 240 | /// This function takes a `&prost_build::Comments` and formats them as a 241 | /// `String` to be used as a RustDoc comment. 242 | fn comments_to_rustdoc(comments: &prost_build::Comments) -> String { 243 | comments 244 | .leading 245 | .iter() 246 | .fold(String::new(), |acc, s| acc + s.trim_start() + "\n") 247 | } 248 | -------------------------------------------------------------------------------- /tower-grpc-interop/src/server.rs: -------------------------------------------------------------------------------- 1 | use clap::value_t; 2 | use futures::{future, stream, Future, Stream}; 3 | use log::error; 4 | use tokio::net::TcpListener; 5 | use tower_grpc::{Code, Request, Response, Status}; 6 | use tower_hyper::server::{Http, Server}; 7 | 8 | mod pb { 9 | #![allow(dead_code)] 10 | #![allow(unused_imports)] 11 | include!(concat!(env!("OUT_DIR"), "/grpc.testing.rs")); 12 | } 13 | 14 | type GrpcFut = 15 | Box, Error = tower_grpc::Status> + Send>; 16 | type GrpcStream = Box + Send>; 17 | 18 | macro_rules! todo { 19 | ($($piece:tt)+) => ({ 20 | let msg = format!( 21 | "server test case is not supported yet: {}", 22 | format_args!($($piece)+), 23 | ); 24 | eprintln!("TODO! {}", msg); 25 | return Box::new(future::err(tower_grpc::Status::new( 26 | tower_grpc::Code::Unknown, 27 | msg, 28 | ))); 29 | }) 30 | } 31 | 32 | #[derive(Clone)] 33 | struct Test; 34 | 35 | impl pb::server::TestService for Test { 36 | type EmptyCallFuture = GrpcFut; 37 | type UnaryCallFuture = GrpcFut; 38 | type CacheableUnaryCallFuture = GrpcFut; 39 | type StreamingOutputCallStream = GrpcStream; 40 | type StreamingOutputCallFuture = GrpcFut; 41 | type StreamingInputCallFuture = GrpcFut; 42 | type FullDuplexCallStream = GrpcStream; 43 | type FullDuplexCallFuture = GrpcFut; 44 | type HalfDuplexCallStream = GrpcStream; 45 | type HalfDuplexCallFuture = GrpcFut; 46 | type UnimplementedCallFuture = GrpcFut; 47 | 48 | /// One empty request followed by one empty response. 49 | fn empty_call(&mut self, _request: Request) -> Self::EmptyCallFuture { 50 | eprintln!("empty_call"); 51 | Box::new(future::ok(Response::new(pb::Empty::default()))) 52 | } 53 | 54 | /// One request followed by one response. 55 | fn unary_call(&mut self, request: Request) -> Self::UnaryCallFuture { 56 | eprintln!("unary_call"); 57 | let req = request.into_inner(); 58 | 59 | // EchoStatus 60 | if let Some(echo_status) = req.response_status { 61 | let status = Status::new(Code::from_i32(echo_status.code), echo_status.message); 62 | return Box::new(future::err(status)); 63 | } 64 | 65 | let res_size = if req.response_size >= 0 { 66 | req.response_size as usize 67 | } else { 68 | let status = Status::new(Code::InvalidArgument, "response_size cannot be negative"); 69 | return Box::new(future::err(status)); 70 | }; 71 | 72 | let res = pb::SimpleResponse { 73 | payload: Some(pb::Payload { 74 | body: vec![0; res_size], 75 | ..Default::default() 76 | }), 77 | ..Default::default() 78 | }; 79 | Box::new(future::ok(Response::new(res))) 80 | } 81 | 82 | /// One request followed by one response. Response has cache control 83 | /// headers set such that a caching HTTP proxy (such as GFE) can 84 | /// satisfy subsequent requests. 85 | fn cacheable_unary_call( 86 | &mut self, 87 | _request: Request, 88 | ) -> Self::CacheableUnaryCallFuture { 89 | todo!("cacheable_unary_call"); 90 | } 91 | 92 | /// One request followed by a sequence of responses (streamed download). 93 | /// The server returns the payload with client desired type and sizes. 94 | fn streaming_output_call( 95 | &mut self, 96 | _request: Request, 97 | ) -> Self::StreamingOutputCallFuture { 98 | todo!("streaming_output_call"); 99 | } 100 | 101 | /// A sequence of requests followed by one response (streamed upload). 102 | /// The server returns the aggregated size of client payload as the result. 103 | fn streaming_input_call( 104 | &mut self, 105 | _request: Request>, 106 | ) -> Self::StreamingInputCallFuture { 107 | todo!("streaming_input_call"); 108 | } 109 | 110 | /// A sequence of requests with each request served by the server immediately. 111 | /// As one request could lead to multiple responses, this interface 112 | /// demonstrates the idea of full duplexing. 113 | fn full_duplex_call( 114 | &mut self, 115 | request: Request>, 116 | ) -> Self::FullDuplexCallFuture { 117 | eprintln!("full_duplex_call"); 118 | let rx = request 119 | .into_inner() 120 | .and_then(|req| { 121 | // EchoStatus 122 | if let Some(echo_status) = req.response_status { 123 | let status = Status::new(Code::from_i32(echo_status.code), echo_status.message); 124 | return Err(status); 125 | } 126 | 127 | let mut resps = Vec::new(); 128 | 129 | for params in req.response_parameters { 130 | let res_size = if params.size >= 0 { 131 | params.size as usize 132 | } else { 133 | let status = tower_grpc::Status::new( 134 | tower_grpc::Code::InvalidArgument, 135 | "response_size cannot be negative", 136 | ); 137 | return Err(status); 138 | }; 139 | 140 | resps.push(pb::StreamingOutputCallResponse { 141 | payload: Some(pb::Payload { 142 | body: vec![0; res_size], 143 | ..Default::default() 144 | }), 145 | ..Default::default() 146 | }); 147 | } 148 | 149 | Ok(stream::iter_ok(resps)) 150 | }) 151 | .flatten(); 152 | 153 | let res = Response::new(Box::new(rx) as Self::FullDuplexCallStream); 154 | Box::new(future::ok(res)) 155 | } 156 | 157 | /// A sequence of requests followed by a sequence of responses. 158 | /// The server buffers all the client requests and then serves them in order. A 159 | /// stream of responses are returned to the client when the server starts with 160 | /// first request. 161 | fn half_duplex_call( 162 | &mut self, 163 | _request: Request>, 164 | ) -> Self::HalfDuplexCallFuture { 165 | todo!("half_duplex_call"); 166 | } 167 | 168 | /// The test server will not implement this method. It will be used 169 | /// to test the behavior when clients call unimplemented methods. 170 | fn unimplemented_call( 171 | &mut self, 172 | _request: Request, 173 | ) -> Self::UnimplementedCallFuture { 174 | eprintln!("unimplemented_call"); 175 | Box::new(future::err(tower_grpc::Status::new( 176 | tower_grpc::Code::Unimplemented, 177 | "explicitly unimplemented_call", 178 | ))) 179 | } 180 | } 181 | 182 | fn main() { 183 | use clap::{App, Arg}; 184 | let _ = ::pretty_env_logger::init(); 185 | 186 | let matches = App::new("interop-server") 187 | .arg( 188 | Arg::with_name("port") 189 | .long("port") 190 | .value_name("PORT") 191 | .help("The server port to listen on. For example, \"8080\".") 192 | .takes_value(true) 193 | .default_value("10000"), 194 | ) 195 | .get_matches(); 196 | 197 | let port = value_t!(matches, "port", u16).expect("port argument"); 198 | 199 | let new_service = pb::server::TestServiceServer::new(Test); 200 | 201 | let mut server = Server::new(new_service); 202 | 203 | let addr = format!("0.0.0.0:{}", port).parse().unwrap(); 204 | let bind = TcpListener::bind(&addr).expect("bind"); 205 | let http = Http::new().http2_only(true).clone(); 206 | 207 | let serve = bind 208 | .incoming() 209 | .for_each(move |sock| { 210 | if let Err(e) = sock.set_nodelay(true) { 211 | return Err(e); 212 | } 213 | 214 | let serve = server.serve_with(sock, http.clone()); 215 | tokio::spawn(serve.map_err(|e| error!("hyper error: {:?}", e))); 216 | 217 | Ok(()) 218 | }) 219 | .map_err(|e| eprintln!("accept error: {}", e)); 220 | 221 | eprintln!("grpc interop server listening on {}", addr); 222 | tokio::run(serve) 223 | } 224 | -------------------------------------------------------------------------------- /tower-grpc-examples/src/routeguide/server.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, rust_2018_idioms)] 2 | 3 | mod data; 4 | 5 | use crate::routeguide::{server, Feature, Point, Rectangle, RouteNote, RouteSummary}; 6 | 7 | use futures::sync::mpsc; 8 | use futures::{future, stream, Future, Sink, Stream}; 9 | use log::error; 10 | use std::collections::HashMap; 11 | use std::hash::{Hash, Hasher}; 12 | use std::sync::{Arc, Mutex}; 13 | use std::time::Instant; 14 | use tokio::net::TcpListener; 15 | use tower_grpc::{Request, Response, Streaming}; 16 | use tower_hyper::server::{Http, Server}; 17 | 18 | pub mod routeguide { 19 | include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); 20 | } 21 | 22 | #[derive(Debug, Clone)] 23 | struct RouteGuide { 24 | state: Arc, 25 | } 26 | 27 | #[derive(Debug)] 28 | struct State { 29 | features: Vec, 30 | notes: Mutex>>, 31 | } 32 | 33 | // Implement hash for Point 34 | impl Hash for Point { 35 | fn hash(&self, state: &mut H) 36 | where 37 | H: Hasher, 38 | { 39 | self.latitude.hash(state); 40 | self.longitude.hash(state); 41 | } 42 | } 43 | 44 | impl Eq for Point {} 45 | 46 | impl routeguide::server::RouteGuide for RouteGuide { 47 | type GetFeatureFuture = future::FutureResult, tower_grpc::Status>; 48 | 49 | /// returns the feature at the given point. 50 | fn get_feature(&mut self, request: Request) -> Self::GetFeatureFuture { 51 | println!("GetFeature = {:?}", request); 52 | 53 | for feature in &self.state.features[..] { 54 | if feature.location.as_ref() == Some(request.get_ref()) { 55 | return future::ok(Response::new(feature.clone())); 56 | } 57 | } 58 | 59 | // Otherwise, return some other feature? 60 | let response = Response::new(Feature { 61 | name: "".to_string(), 62 | location: None, 63 | }); 64 | 65 | future::ok(response) 66 | } 67 | 68 | type ListFeaturesStream = Box + Send>; 69 | type ListFeaturesFuture = 70 | future::FutureResult, tower_grpc::Status>; 71 | 72 | /// Lists all features contained within the given bounding Rectangle. 73 | fn list_features(&mut self, request: Request) -> Self::ListFeaturesFuture { 74 | use std::thread; 75 | 76 | println!("ListFeatures = {:?}", request); 77 | 78 | let (tx, rx) = mpsc::channel(4); 79 | 80 | let state = self.state.clone(); 81 | 82 | thread::spawn(move || { 83 | let mut tx = tx.wait(); 84 | 85 | for feature in &state.features[..] { 86 | if in_range(feature.location.as_ref().unwrap(), request.get_ref()) { 87 | println!(" => send {:?}", feature); 88 | tx.send(feature.clone()).unwrap(); 89 | } 90 | } 91 | 92 | println!(" /// done sending"); 93 | }); 94 | 95 | let rx = rx.map_err(|_| unimplemented!()); 96 | future::ok(Response::new(Box::new(rx))) 97 | } 98 | 99 | type RecordRouteFuture = 100 | Box, Error = tower_grpc::Status> + Send>; 101 | 102 | /// Records a route composited of a sequence of points. 103 | /// 104 | /// It gets a stream of points, and responds with statistics about the 105 | /// "trip": number of points, number of known features visited, total 106 | /// distance traveled, and total time spent. 107 | fn record_route(&mut self, request: Request>) -> Self::RecordRouteFuture { 108 | println!("RecordRoute = {:?}", request); 109 | 110 | let now = Instant::now(); 111 | let state = self.state.clone(); 112 | 113 | let response = request 114 | .into_inner() 115 | .map_err(|e| { 116 | println!(" !!! err={:?}", e); 117 | e 118 | }) 119 | // Iterate over all points, building up the route summary 120 | .fold( 121 | (RouteSummary::default(), None), 122 | move |(mut summary, last_point), point| { 123 | println!(" ==> Point = {:?}", point); 124 | 125 | // Increment the point count 126 | summary.point_count += 1; 127 | 128 | // Find features 129 | for feature in &state.features[..] { 130 | if feature.location.as_ref() == Some(&point) { 131 | summary.feature_count += 1; 132 | } 133 | } 134 | 135 | // Calculate the distance 136 | if let Some(ref last_point) = last_point { 137 | summary.distance += calc_distance(last_point, &point); 138 | } 139 | 140 | Ok::<_, tower_grpc::Status>((summary, Some(point))) 141 | }, 142 | ) 143 | // Map the route summary to a gRPC response 144 | .map(move |(mut summary, _)| { 145 | println!(" => Done = {:?}", summary); 146 | 147 | summary.elapsed_time = now.elapsed().as_secs() as i32; 148 | Response::new(summary) 149 | }); 150 | 151 | Box::new(response) 152 | } 153 | 154 | type RouteChatStream = Box + Send>; 155 | type RouteChatFuture = 156 | future::FutureResult, tower_grpc::Status>; 157 | 158 | // Receives a stream of message/location pairs, and responds with a stream 159 | // of all previous messages at each of those locations. 160 | fn route_chat(&mut self, request: Request>) -> Self::RouteChatFuture { 161 | println!("RouteChat = {:?}", request); 162 | 163 | let state = self.state.clone(); 164 | 165 | let response = request 166 | .into_inner() 167 | .map(move |note| { 168 | let location = note.location.clone().unwrap(); 169 | let mut notes = state.notes.lock().unwrap(); 170 | let notes = notes.entry(location).or_insert(vec![]); 171 | 172 | notes.push(note); 173 | 174 | stream::iter_ok(notes.clone()) 175 | }) 176 | .flatten(); 177 | 178 | future::ok(Response::new(Box::new(response))) 179 | } 180 | } 181 | 182 | fn in_range(point: &Point, rect: &Rectangle) -> bool { 183 | use std::cmp; 184 | 185 | let lo = rect.lo.as_ref().unwrap(); 186 | let hi = rect.hi.as_ref().unwrap(); 187 | 188 | let left = cmp::min(lo.longitude, hi.longitude); 189 | let right = cmp::max(lo.longitude, hi.longitude); 190 | let top = cmp::max(lo.latitude, hi.latitude); 191 | let bottom = cmp::min(lo.latitude, hi.latitude); 192 | 193 | point.longitude >= left 194 | && point.longitude <= right 195 | && point.latitude >= bottom 196 | && point.latitude <= top 197 | } 198 | 199 | /// Calculates the distance between two points using the "haversine" formula. 200 | /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. 201 | fn calc_distance(p1: &Point, p2: &Point) -> i32 { 202 | const CORD_FACTOR: f64 = 1e7; 203 | const R: f64 = 6371000.0; // meters 204 | 205 | let lat1 = p1.latitude as f64 / CORD_FACTOR; 206 | let lat2 = p2.latitude as f64 / CORD_FACTOR; 207 | let lng1 = p1.longitude as f64 / CORD_FACTOR; 208 | let lng2 = p2.longitude as f64 / CORD_FACTOR; 209 | 210 | let lat_rad1 = lat1.to_radians(); 211 | let lat_rad2 = lat2.to_radians(); 212 | 213 | let delta_lat = (lat2 - lat1).to_radians(); 214 | let delta_lng = (lng2 - lng1).to_radians(); 215 | 216 | let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin() 217 | + (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin(); 218 | 219 | let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt()); 220 | 221 | (R * c) as i32 222 | } 223 | 224 | pub fn main() { 225 | let _ = ::env_logger::init(); 226 | 227 | let handler = RouteGuide { 228 | state: Arc::new(State { 229 | // Load data file 230 | features: data::load(), 231 | notes: Mutex::new(HashMap::new()), 232 | }), 233 | }; 234 | 235 | let new_service = server::RouteGuideServer::new(handler); 236 | 237 | let mut server = Server::new(new_service); 238 | let http = Http::new().http2_only(true).clone(); 239 | 240 | let addr = "127.0.0.1:10000".parse().unwrap(); 241 | let bind = TcpListener::bind(&addr).expect("bind"); 242 | 243 | println!("listining on {:?}", addr); 244 | 245 | let serve = bind 246 | .incoming() 247 | .for_each(move |sock| { 248 | if let Err(e) = sock.set_nodelay(true) { 249 | return Err(e); 250 | } 251 | 252 | let serve = server.serve_with(sock, http.clone()); 253 | tokio::spawn(serve.map_err(|e| error!("h2 error: {:?}", e))); 254 | 255 | Ok(()) 256 | }) 257 | .map_err(|e| eprintln!("accept error: {}", e)); 258 | 259 | tokio::run(serve); 260 | } 261 | -------------------------------------------------------------------------------- /tower-grpc/src/metadata/key.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use http::header::HeaderName; 3 | use std::borrow::Borrow; 4 | use std::error::Error; 5 | use std::fmt; 6 | use std::marker::PhantomData; 7 | use std::str::FromStr; 8 | 9 | use super::encoding::{Ascii, Binary, ValueEncoding}; 10 | 11 | /// Represents a custom metadata field name. 12 | /// 13 | /// `MetadataKey` is used as the [`MetadataMap`] key. 14 | /// 15 | /// [`HeaderMap`]: struct.HeaderMap.html 16 | #[derive(Clone, Eq, PartialEq, Hash)] 17 | #[repr(transparent)] 18 | pub struct MetadataKey { 19 | // Note: There are unsafe transmutes that assume that the memory layout 20 | // of MetadataValue is identical to HeaderName 21 | pub(crate) inner: http::header::HeaderName, 22 | phantom: PhantomData, 23 | } 24 | 25 | /// A possible error when converting a `MetadataKey` from another type. 26 | #[derive(Debug)] 27 | pub struct InvalidMetadataKey { 28 | _priv: (), 29 | } 30 | 31 | pub type AsciiMetadataKey = MetadataKey; 32 | pub type BinaryMetadataKey = MetadataKey; 33 | 34 | impl MetadataKey { 35 | /// Converts a slice of bytes to a `MetadataKey`. 36 | /// 37 | /// This function normalizes the input. 38 | pub fn from_bytes(src: &[u8]) -> Result { 39 | match HeaderName::from_bytes(src) { 40 | Ok(name) => { 41 | if !VE::is_valid_key(name.as_str()) { 42 | panic!("invalid metadata key") 43 | } 44 | 45 | Ok(MetadataKey { 46 | inner: name, 47 | phantom: PhantomData, 48 | }) 49 | } 50 | Err(_) => Err(InvalidMetadataKey::new()), 51 | } 52 | } 53 | 54 | /// Converts a static string to a `MetadataKey`. 55 | /// 56 | /// This function panics when the static string is a invalid metadata key. 57 | /// 58 | /// This function requires the static string to only contain lowercase 59 | /// characters, numerals and symbols, as per the HTTP/2.0 specification 60 | /// and header names internal representation within this library. 61 | /// 62 | /// 63 | /// # Examples 64 | /// 65 | /// ``` 66 | /// # use tower_grpc::metadata::*; 67 | /// // Parsing a metadata key 68 | /// let CUSTOM_KEY: &'static str = "custom-key"; 69 | /// 70 | /// let a = AsciiMetadataKey::from_bytes(b"custom-key").unwrap(); 71 | /// let b = AsciiMetadataKey::from_static(CUSTOM_KEY); 72 | /// assert_eq!(a, b); 73 | /// ``` 74 | /// 75 | /// ```should_panic 76 | /// # use tower_grpc::metadata::*; 77 | /// // Parsing a metadata key that contains invalid symbols(s): 78 | /// AsciiMetadataKey::from_static("content{}{}length"); // This line panics! 79 | /// ``` 80 | /// 81 | /// ```should_panic 82 | /// # use tower_grpc::metadata::*; 83 | /// // Parsing a metadata key that contains invalid uppercase characters. 84 | /// let a = AsciiMetadataKey::from_static("foobar"); 85 | /// let b = AsciiMetadataKey::from_static("FOOBAR"); // This line panics! 86 | /// ``` 87 | /// 88 | /// ```should_panic 89 | /// # use tower_grpc::metadata::*; 90 | /// // Parsing a -bin metadata key as an Ascii key. 91 | /// let b = AsciiMetadataKey::from_static("hello-bin"); // This line panics! 92 | /// ``` 93 | /// 94 | /// ```should_panic 95 | /// # use tower_grpc::metadata::*; 96 | /// // Parsing a non-bin metadata key as an Binary key. 97 | /// let b = BinaryMetadataKey::from_static("hello"); // This line panics! 98 | /// ``` 99 | pub fn from_static(src: &'static str) -> Self { 100 | let name = HeaderName::from_static(src); 101 | if !VE::is_valid_key(name.as_str()) { 102 | panic!("invalid metadata key") 103 | } 104 | 105 | MetadataKey { 106 | inner: name, 107 | phantom: PhantomData, 108 | } 109 | } 110 | 111 | /// Returns a `str` representation of the metadata key. 112 | /// 113 | /// The returned string will always be lower case. 114 | #[inline] 115 | pub fn as_str(&self) -> &str { 116 | self.inner.as_str() 117 | } 118 | 119 | /// Converts a HeaderName reference to a MetadataKey. This method assumes 120 | /// that the caller has made sure that the header name has the correct 121 | /// "-bin" or non-"-bin" suffix, it does not validate its input. 122 | #[inline] 123 | pub(crate) fn unchecked_from_header_name_ref(header_name: &HeaderName) -> &Self { 124 | unsafe { &*(header_name as *const HeaderName as *const Self) } 125 | } 126 | 127 | /// Converts a HeaderName reference to a MetadataKey. This method assumes 128 | /// that the caller has made sure that the header name has the correct 129 | /// "-bin" or non-"-bin" suffix, it does not validate its input. 130 | #[inline] 131 | pub(crate) fn unchecked_from_header_name(name: HeaderName) -> Self { 132 | MetadataKey { 133 | inner: name, 134 | phantom: PhantomData, 135 | } 136 | } 137 | } 138 | 139 | impl FromStr for MetadataKey { 140 | type Err = InvalidMetadataKey; 141 | 142 | fn from_str(s: &str) -> Result { 143 | MetadataKey::from_bytes(s.as_bytes()).map_err(|_| InvalidMetadataKey::new()) 144 | } 145 | } 146 | 147 | impl AsRef for MetadataKey { 148 | fn as_ref(&self) -> &str { 149 | self.as_str() 150 | } 151 | } 152 | 153 | impl AsRef<[u8]> for MetadataKey { 154 | fn as_ref(&self) -> &[u8] { 155 | self.as_str().as_bytes() 156 | } 157 | } 158 | 159 | impl Borrow for MetadataKey { 160 | fn borrow(&self) -> &str { 161 | self.as_str() 162 | } 163 | } 164 | 165 | impl fmt::Debug for MetadataKey { 166 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 167 | fmt::Debug::fmt(self.as_str(), fmt) 168 | } 169 | } 170 | 171 | impl fmt::Display for MetadataKey { 172 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 173 | fmt::Display::fmt(self.as_str(), fmt) 174 | } 175 | } 176 | 177 | impl InvalidMetadataKey { 178 | pub fn new() -> InvalidMetadataKey { 179 | InvalidMetadataKey { _priv: () } 180 | } 181 | } 182 | 183 | impl<'a, VE: ValueEncoding> From<&'a MetadataKey> for MetadataKey { 184 | fn from(src: &'a MetadataKey) -> MetadataKey { 185 | src.clone() 186 | } 187 | } 188 | 189 | impl From> for Bytes { 190 | #[inline] 191 | fn from(name: MetadataKey) -> Bytes { 192 | name.inner.into() 193 | } 194 | } 195 | 196 | impl<'a, VE: ValueEncoding> PartialEq<&'a MetadataKey> for MetadataKey { 197 | #[inline] 198 | fn eq(&self, other: &&'a MetadataKey) -> bool { 199 | *self == **other 200 | } 201 | } 202 | 203 | impl<'a, VE: ValueEncoding> PartialEq> for &'a MetadataKey { 204 | #[inline] 205 | fn eq(&self, other: &MetadataKey) -> bool { 206 | *other == *self 207 | } 208 | } 209 | 210 | impl PartialEq for MetadataKey { 211 | /// Performs a case-insensitive comparison of the string against the header 212 | /// name 213 | /// 214 | /// # Examples 215 | /// 216 | /// ``` 217 | /// # use tower_grpc::metadata::*; 218 | /// let content_length = AsciiMetadataKey::from_static("content-length"); 219 | /// 220 | /// assert_eq!(content_length, "content-length"); 221 | /// assert_eq!(content_length, "Content-Length"); 222 | /// assert_ne!(content_length, "content length"); 223 | /// ``` 224 | #[inline] 225 | fn eq(&self, other: &str) -> bool { 226 | self.inner.eq(other) 227 | } 228 | } 229 | 230 | impl PartialEq> for str { 231 | /// Performs a case-insensitive comparison of the string against the header 232 | /// name 233 | /// 234 | /// # Examples 235 | /// 236 | /// ``` 237 | /// # use tower_grpc::metadata::*; 238 | /// let content_length = AsciiMetadataKey::from_static("content-length"); 239 | /// 240 | /// assert_eq!(content_length, "content-length"); 241 | /// assert_eq!(content_length, "Content-Length"); 242 | /// assert_ne!(content_length, "content length"); 243 | /// ``` 244 | #[inline] 245 | fn eq(&self, other: &MetadataKey) -> bool { 246 | (*other).inner == *self 247 | } 248 | } 249 | 250 | impl<'a, VE: ValueEncoding> PartialEq<&'a str> for MetadataKey { 251 | /// Performs a case-insensitive comparison of the string against the header 252 | /// name 253 | #[inline] 254 | fn eq(&self, other: &&'a str) -> bool { 255 | *self == **other 256 | } 257 | } 258 | 259 | impl<'a, VE: ValueEncoding> PartialEq> for &'a str { 260 | /// Performs a case-insensitive comparison of the string against the header 261 | /// name 262 | #[inline] 263 | fn eq(&self, other: &MetadataKey) -> bool { 264 | *other == *self 265 | } 266 | } 267 | 268 | impl fmt::Display for InvalidMetadataKey { 269 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 270 | self.description().fmt(f) 271 | } 272 | } 273 | 274 | impl Error for InvalidMetadataKey { 275 | fn description(&self) -> &str { 276 | "invalid gRPC metadata key name" 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /tower-grpc/src/generic/codec.rs: -------------------------------------------------------------------------------- 1 | use crate::body::{Body, HttpBody}; 2 | use crate::error::Error; 3 | use crate::status::infer_grpc_status; 4 | use crate::Status; 5 | 6 | use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf}; 7 | use futures::{try_ready, Async, Poll, Stream}; 8 | use http::{HeaderMap, StatusCode}; 9 | use log::{debug, trace, warn}; 10 | use std::collections::VecDeque; 11 | use std::fmt; 12 | 13 | type BytesBuf = ::Buf; 14 | 15 | /// Encodes and decodes gRPC message types 16 | pub trait Codec { 17 | /// The encode type 18 | type Encode; 19 | 20 | /// Encoder type 21 | type Encoder: Encoder; 22 | 23 | /// The decode type 24 | type Decode; 25 | 26 | /// Decoder type 27 | type Decoder: Decoder; 28 | 29 | /// Returns a new encoder 30 | fn encoder(&mut self) -> Self::Encoder; 31 | 32 | /// Returns a new decoder 33 | fn decoder(&mut self) -> Self::Decoder; 34 | } 35 | 36 | /// Encodes gRPC message types 37 | pub trait Encoder { 38 | /// Type that is encoded 39 | type Item; 40 | 41 | /// The content-type header for messages using this encoding. 42 | /// 43 | /// Should be `application/grpc+yourencoding`. 44 | const CONTENT_TYPE: &'static str; 45 | 46 | /// Encode a message into the provided buffer. 47 | fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Status>; 48 | } 49 | 50 | /// Decodes gRPC message types 51 | pub trait Decoder { 52 | /// Type that is decoded 53 | type Item; 54 | 55 | /// Decode a message from the buffer. 56 | /// 57 | /// The buffer will contain exactly the bytes of a full message. There 58 | /// is no need to get the length from the bytes, gRPC framing is handled 59 | /// for you. 60 | fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result; 61 | } 62 | 63 | /// Encodes gRPC message types 64 | #[must_use = "futures do nothing unless polled"] 65 | #[derive(Debug)] 66 | pub struct Encode { 67 | inner: EncodeInner, 68 | 69 | /// Destination buffer 70 | buf: BytesMut, 71 | 72 | role: Role, 73 | } 74 | 75 | #[derive(Debug)] 76 | enum EncodeInner { 77 | Ok { 78 | /// The encoder 79 | encoder: T, 80 | 81 | /// The source of messages to encode 82 | inner: U, 83 | }, 84 | Empty, 85 | Err(Status), 86 | } 87 | 88 | #[derive(Debug)] 89 | enum Role { 90 | Client, 91 | Server, 92 | } 93 | 94 | /// An stream of inbound gRPC messages 95 | #[must_use = "futures do nothing unless polled"] 96 | pub struct Streaming { 97 | /// The decoder 98 | decoder: T, 99 | 100 | /// The source of encoded messages 101 | inner: B, 102 | 103 | /// buffer 104 | bufs: BufList, 105 | 106 | /// Decoding state 107 | state: State, 108 | 109 | direction: Direction, 110 | } 111 | 112 | /// Whether this is a request or a response stream value. 113 | #[derive(Clone, Copy, Debug)] 114 | pub(crate) enum Direction { 115 | /// For requests, we expect only headers and the streaming body. 116 | Request, 117 | /// For responses, the received HTTP status code must be provided. 118 | /// We also expect to receive trailers after the streaming body. 119 | Response(StatusCode), 120 | /// For streaming responses with zero response payloads, the HTTP 121 | /// status is provided immediately. In this case no additional 122 | /// trailers are expected. 123 | EmptyResponse, 124 | } 125 | 126 | #[derive(Debug)] 127 | enum State { 128 | ReadHeader, 129 | ReadBody { compression: bool, len: usize }, 130 | Done, 131 | } 132 | 133 | /// A buffer to encode a message into. 134 | #[derive(Debug)] 135 | pub struct EncodeBuf<'a> { 136 | bytes: &'a mut BytesMut, 137 | } 138 | 139 | /// A buffer to decode messages from. 140 | pub struct DecodeBuf<'a> { 141 | bufs: &'a mut dyn Buf, 142 | len: usize, 143 | } 144 | 145 | #[derive(Debug)] 146 | pub struct BufList { 147 | bufs: VecDeque, 148 | } 149 | 150 | // ===== impl Encode ===== 151 | 152 | impl Encode 153 | where 154 | T: Encoder, 155 | U: Stream, 156 | U::Error: Into, 157 | { 158 | fn new(encoder: T, inner: U, role: Role) -> Self { 159 | Encode { 160 | inner: EncodeInner::Ok { encoder, inner }, 161 | buf: BytesMut::new(), 162 | role, 163 | } 164 | } 165 | 166 | pub(crate) fn request(encoder: T, inner: U) -> Self { 167 | Encode::new(encoder, inner, Role::Client) 168 | } 169 | 170 | pub(crate) fn response(encoder: T, inner: U) -> Self { 171 | Encode::new(encoder, inner, Role::Server) 172 | } 173 | 174 | pub(crate) fn empty() -> Self { 175 | Encode { 176 | inner: EncodeInner::Empty, 177 | buf: BytesMut::new(), 178 | role: Role::Server, 179 | } 180 | } 181 | } 182 | 183 | impl HttpBody for Encode 184 | where 185 | T: Encoder, 186 | U: Stream, 187 | U::Error: Into, 188 | { 189 | type Data = BytesBuf; 190 | type Error = Status; 191 | 192 | fn is_end_stream(&self) -> bool { 193 | if let EncodeInner::Empty = self.inner { 194 | true 195 | } else { 196 | false 197 | } 198 | } 199 | 200 | fn poll_data(&mut self) -> Poll, Status> { 201 | match self.inner.poll_encode(&mut self.buf) { 202 | Ok(ok) => Ok(ok), 203 | Err(status) => { 204 | match self.role { 205 | // clients don't send statuses as trailers, so just return 206 | // this error directly to allow an HTTP2 rst_stream to be 207 | // sent. 208 | Role::Client => Err(status), 209 | // otherwise, its better to send this status in the 210 | // trailers, instead of a RST_STREAM as the server... 211 | Role::Server => { 212 | self.inner = EncodeInner::Err(status); 213 | Ok(None.into()) 214 | } 215 | } 216 | } 217 | } 218 | } 219 | 220 | fn poll_trailers(&mut self) -> Poll, Status> { 221 | if let Role::Client = self.role { 222 | return Ok(Async::Ready(None)); 223 | } 224 | 225 | let map = match self.inner { 226 | EncodeInner::Ok { .. } => Status::new(crate::Code::Ok, "").to_header_map(), 227 | EncodeInner::Empty => return Ok(None.into()), 228 | EncodeInner::Err(ref status) => status.to_header_map(), 229 | }; 230 | Ok(Some(map?).into()) 231 | } 232 | } 233 | 234 | impl EncodeInner 235 | where 236 | T: Encoder, 237 | U: Stream, 238 | U::Error: Into, 239 | { 240 | fn poll_encode(&mut self, buf: &mut BytesMut) -> Poll, Status> { 241 | match self { 242 | EncodeInner::Ok { 243 | ref mut inner, 244 | ref mut encoder, 245 | } => { 246 | let item = try_ready!(inner.poll().map_err(|err| { 247 | let err = err.into(); 248 | debug!("encoder inner stream error: {:?}", err); 249 | Status::from_error(&*err) 250 | })); 251 | 252 | let item = if let Some(item) = item { 253 | buf.reserve(5); 254 | unsafe { 255 | buf.advance_mut(5); 256 | } 257 | encoder.encode(item, &mut EncodeBuf { bytes: buf })?; 258 | 259 | // now that we know length, we can write the header 260 | let len = buf.len() - 5; 261 | assert!(len <= ::std::u32::MAX as usize); 262 | { 263 | let mut cursor = ::std::io::Cursor::new(&mut buf[..5]); 264 | cursor.put_u8(0); // byte must be 0, reserve doesn't auto-zero 265 | cursor.put_u32_be(len as u32); 266 | } 267 | 268 | Some(buf.split_to(len + 5).freeze().into_buf()) 269 | } else { 270 | None 271 | }; 272 | 273 | return Ok(Async::Ready(item)); 274 | } 275 | _ => return Ok(Async::Ready(None)), 276 | } 277 | } 278 | } 279 | 280 | // ===== impl Streaming ===== 281 | 282 | impl Streaming 283 | where 284 | T: Decoder, 285 | U: Body, 286 | { 287 | pub(crate) fn new(decoder: T, inner: U, direction: Direction) -> Self { 288 | Streaming { 289 | decoder, 290 | inner, 291 | bufs: BufList { 292 | bufs: VecDeque::new(), 293 | }, 294 | state: State::ReadHeader, 295 | direction, 296 | } 297 | } 298 | 299 | fn decode(&mut self) -> Result, crate::Status> { 300 | if let State::ReadHeader = self.state { 301 | if self.bufs.remaining() < 5 { 302 | return Ok(None); 303 | } 304 | 305 | let is_compressed = match self.bufs.get_u8() { 306 | 0 => false, 307 | 1 => { 308 | trace!("message compressed, compression not supported yet"); 309 | return Err(crate::Status::new( 310 | crate::Code::Unimplemented, 311 | "Message compressed, compression not supported yet.".to_string(), 312 | )); 313 | } 314 | f => { 315 | trace!("unexpected compression flag"); 316 | return Err(crate::Status::new( 317 | crate::Code::Internal, 318 | format!("Unexpected compression flag: {}", f), 319 | )); 320 | } 321 | }; 322 | let len = self.bufs.get_u32_be() as usize; 323 | 324 | self.state = State::ReadBody { 325 | compression: is_compressed, 326 | len, 327 | } 328 | } 329 | 330 | if let State::ReadBody { len, .. } = self.state { 331 | if self.bufs.remaining() < len { 332 | return Ok(None); 333 | } 334 | 335 | match self.decoder.decode(&mut DecodeBuf { 336 | bufs: &mut self.bufs, 337 | len, 338 | }) { 339 | Ok(msg) => { 340 | self.state = State::ReadHeader; 341 | return Ok(Some(msg)); 342 | } 343 | Err(e) => { 344 | return Err(e); 345 | } 346 | } 347 | } 348 | 349 | Ok(None) 350 | } 351 | } 352 | 353 | impl Stream for Streaming 354 | where 355 | T: Decoder, 356 | U: Body, 357 | { 358 | type Item = T::Item; 359 | type Error = Status; 360 | 361 | fn poll(&mut self) -> Poll, Self::Error> { 362 | loop { 363 | if let State::Done = self.state { 364 | break; 365 | } 366 | 367 | match self.decode()? { 368 | Some(val) => return Ok(Async::Ready(Some(val))), 369 | None => (), 370 | } 371 | 372 | let chunk = try_ready!(self.inner.poll_data().map_err(|err| { 373 | let err = err.into(); 374 | debug!("decoder inner stream error: {:?}", err); 375 | Status::from_error(&*err) 376 | })); 377 | 378 | if let Some(data) = chunk { 379 | self.bufs.bufs.push_back(data.into_buf()); 380 | } else { 381 | if self.bufs.has_remaining() { 382 | trace!("unexpected EOF decoding stream"); 383 | return Err(crate::Status::new( 384 | crate::Code::Internal, 385 | "Unexpected EOF decoding stream.".to_string(), 386 | )); 387 | } else { 388 | self.state = State::Done; 389 | break; 390 | } 391 | } 392 | } 393 | 394 | if let Direction::Response(status_code) = self.direction { 395 | let trailers = try_ready!(self.inner.poll_trailers().map_err(|err| { 396 | let err = err.into(); 397 | debug!("decoder inner trailers error: {:?}", err); 398 | Status::from_error(&*err) 399 | })); 400 | match infer_grpc_status(trailers, status_code) { 401 | Ok(_) => Ok(Async::Ready(None)), 402 | Err(err) => Err(err), 403 | } 404 | } else { 405 | Ok(Async::Ready(None)) 406 | } 407 | } 408 | } 409 | 410 | impl fmt::Debug for Streaming 411 | where 412 | T: fmt::Debug, 413 | B: Body + fmt::Debug, 414 | B::Data: fmt::Debug, 415 | { 416 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 417 | f.debug_struct("Streaming").finish() 418 | } 419 | } 420 | 421 | // ===== impl EncodeBuf ===== 422 | 423 | impl<'a> EncodeBuf<'a> { 424 | #[inline] 425 | pub fn reserve(&mut self, capacity: usize) { 426 | self.bytes.reserve(capacity); 427 | } 428 | } 429 | 430 | impl<'a> BufMut for EncodeBuf<'a> { 431 | #[inline] 432 | fn remaining_mut(&self) -> usize { 433 | self.bytes.remaining_mut() 434 | } 435 | 436 | #[inline] 437 | unsafe fn advance_mut(&mut self, cnt: usize) { 438 | self.bytes.advance_mut(cnt) 439 | } 440 | 441 | #[inline] 442 | unsafe fn bytes_mut(&mut self) -> &mut [u8] { 443 | self.bytes.bytes_mut() 444 | } 445 | } 446 | 447 | // ===== impl DecodeBuf ===== 448 | 449 | impl<'a> Buf for DecodeBuf<'a> { 450 | #[inline] 451 | fn remaining(&self) -> usize { 452 | self.len 453 | } 454 | 455 | #[inline] 456 | fn bytes(&self) -> &[u8] { 457 | let ret = self.bufs.bytes(); 458 | 459 | if ret.len() > self.len { 460 | &ret[..self.len] 461 | } else { 462 | ret 463 | } 464 | } 465 | 466 | #[inline] 467 | fn advance(&mut self, cnt: usize) { 468 | assert!(cnt <= self.len); 469 | self.bufs.advance(cnt); 470 | self.len -= cnt; 471 | } 472 | } 473 | 474 | impl<'a> fmt::Debug for DecodeBuf<'a> { 475 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 476 | f.debug_struct("DecodeBuf").finish() 477 | } 478 | } 479 | 480 | impl<'a> Drop for DecodeBuf<'a> { 481 | fn drop(&mut self) { 482 | if self.len > 0 { 483 | warn!("DecodeBuf was not advanced to end"); 484 | self.bufs.advance(self.len); 485 | } 486 | } 487 | } 488 | 489 | // ===== impl BufList ===== 490 | 491 | impl Buf for BufList { 492 | #[inline] 493 | fn remaining(&self) -> usize { 494 | self.bufs.iter().map(|buf| buf.remaining()).sum() 495 | } 496 | 497 | #[inline] 498 | fn bytes(&self) -> &[u8] { 499 | if self.bufs.is_empty() { 500 | &[] 501 | } else { 502 | self.bufs[0].bytes() 503 | } 504 | } 505 | 506 | #[inline] 507 | fn advance(&mut self, mut cnt: usize) { 508 | while cnt > 0 { 509 | { 510 | let front = &mut self.bufs[0]; 511 | if front.remaining() > cnt { 512 | front.advance(cnt); 513 | return; 514 | } else { 515 | cnt -= front.remaining(); 516 | } 517 | } 518 | self.bufs.pop_front(); 519 | } 520 | } 521 | } 522 | -------------------------------------------------------------------------------- /tower-grpc-examples/data/route_guide_db.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "location": { 3 | "latitude": 407838351, 4 | "longitude": -746143763 5 | }, 6 | "name": "Patriots Path, Mendham, NJ 07945, USA" 7 | }, { 8 | "location": { 9 | "latitude": 408122808, 10 | "longitude": -743999179 11 | }, 12 | "name": "101 New Jersey 10, Whippany, NJ 07981, USA" 13 | }, { 14 | "location": { 15 | "latitude": 413628156, 16 | "longitude": -749015468 17 | }, 18 | "name": "U.S. 6, Shohola, PA 18458, USA" 19 | }, { 20 | "location": { 21 | "latitude": 419999544, 22 | "longitude": -740371136 23 | }, 24 | "name": "5 Conners Road, Kingston, NY 12401, USA" 25 | }, { 26 | "location": { 27 | "latitude": 414008389, 28 | "longitude": -743951297 29 | }, 30 | "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" 31 | }, { 32 | "location": { 33 | "latitude": 419611318, 34 | "longitude": -746524769 35 | }, 36 | "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" 37 | }, { 38 | "location": { 39 | "latitude": 406109563, 40 | "longitude": -742186778 41 | }, 42 | "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" 43 | }, { 44 | "location": { 45 | "latitude": 416802456, 46 | "longitude": -742370183 47 | }, 48 | "name": "352 South Mountain Road, Wallkill, NY 12589, USA" 49 | }, { 50 | "location": { 51 | "latitude": 412950425, 52 | "longitude": -741077389 53 | }, 54 | "name": "Bailey Turn Road, Harriman, NY 10926, USA" 55 | }, { 56 | "location": { 57 | "latitude": 412144655, 58 | "longitude": -743949739 59 | }, 60 | "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" 61 | }, { 62 | "location": { 63 | "latitude": 415736605, 64 | "longitude": -742847522 65 | }, 66 | "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" 67 | }, { 68 | "location": { 69 | "latitude": 413843930, 70 | "longitude": -740501726 71 | }, 72 | "name": "162 Merrill Road, Highland Mills, NY 10930, USA" 73 | }, { 74 | "location": { 75 | "latitude": 410873075, 76 | "longitude": -744459023 77 | }, 78 | "name": "Clinton Road, West Milford, NJ 07480, USA" 79 | }, { 80 | "location": { 81 | "latitude": 412346009, 82 | "longitude": -744026814 83 | }, 84 | "name": "16 Old Brook Lane, Warwick, NY 10990, USA" 85 | }, { 86 | "location": { 87 | "latitude": 402948455, 88 | "longitude": -747903913 89 | }, 90 | "name": "3 Drake Lane, Pennington, NJ 08534, USA" 91 | }, { 92 | "location": { 93 | "latitude": 406337092, 94 | "longitude": -740122226 95 | }, 96 | "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" 97 | }, { 98 | "location": { 99 | "latitude": 406421967, 100 | "longitude": -747727624 101 | }, 102 | "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" 103 | }, { 104 | "location": { 105 | "latitude": 416318082, 106 | "longitude": -749677716 107 | }, 108 | "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" 109 | }, { 110 | "location": { 111 | "latitude": 415301720, 112 | "longitude": -748416257 113 | }, 114 | "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" 115 | }, { 116 | "location": { 117 | "latitude": 402647019, 118 | "longitude": -747071791 119 | }, 120 | "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" 121 | }, { 122 | "location": { 123 | "latitude": 412567807, 124 | "longitude": -741058078 125 | }, 126 | "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" 127 | }, { 128 | "location": { 129 | "latitude": 416855156, 130 | "longitude": -744420597 131 | }, 132 | "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" 133 | }, { 134 | "location": { 135 | "latitude": 404663628, 136 | "longitude": -744820157 137 | }, 138 | "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" 139 | }, { 140 | "location": { 141 | "latitude": 407113723, 142 | "longitude": -749746483 143 | }, 144 | "name": "" 145 | }, { 146 | "location": { 147 | "latitude": 402133926, 148 | "longitude": -743613249 149 | }, 150 | "name": "" 151 | }, { 152 | "location": { 153 | "latitude": 400273442, 154 | "longitude": -741220915 155 | }, 156 | "name": "" 157 | }, { 158 | "location": { 159 | "latitude": 411236786, 160 | "longitude": -744070769 161 | }, 162 | "name": "" 163 | }, { 164 | "location": { 165 | "latitude": 411633782, 166 | "longitude": -746784970 167 | }, 168 | "name": "211-225 Plains Road, Augusta, NJ 07822, USA" 169 | }, { 170 | "location": { 171 | "latitude": 415830701, 172 | "longitude": -742952812 173 | }, 174 | "name": "" 175 | }, { 176 | "location": { 177 | "latitude": 413447164, 178 | "longitude": -748712898 179 | }, 180 | "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" 181 | }, { 182 | "location": { 183 | "latitude": 405047245, 184 | "longitude": -749800722 185 | }, 186 | "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" 187 | }, { 188 | "location": { 189 | "latitude": 418858923, 190 | "longitude": -746156790 191 | }, 192 | "name": "" 193 | }, { 194 | "location": { 195 | "latitude": 417951888, 196 | "longitude": -748484944 197 | }, 198 | "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" 199 | }, { 200 | "location": { 201 | "latitude": 407033786, 202 | "longitude": -743977337 203 | }, 204 | "name": "26 East 3rd Street, New Providence, NJ 07974, USA" 205 | }, { 206 | "location": { 207 | "latitude": 417548014, 208 | "longitude": -740075041 209 | }, 210 | "name": "" 211 | }, { 212 | "location": { 213 | "latitude": 410395868, 214 | "longitude": -744972325 215 | }, 216 | "name": "" 217 | }, { 218 | "location": { 219 | "latitude": 404615353, 220 | "longitude": -745129803 221 | }, 222 | "name": "" 223 | }, { 224 | "location": { 225 | "latitude": 406589790, 226 | "longitude": -743560121 227 | }, 228 | "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" 229 | }, { 230 | "location": { 231 | "latitude": 414653148, 232 | "longitude": -740477477 233 | }, 234 | "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" 235 | }, { 236 | "location": { 237 | "latitude": 405957808, 238 | "longitude": -743255336 239 | }, 240 | "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" 241 | }, { 242 | "location": { 243 | "latitude": 411733589, 244 | "longitude": -741648093 245 | }, 246 | "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" 247 | }, { 248 | "location": { 249 | "latitude": 412676291, 250 | "longitude": -742606606 251 | }, 252 | "name": "1270 Lakes Road, Monroe, NY 10950, USA" 253 | }, { 254 | "location": { 255 | "latitude": 409224445, 256 | "longitude": -748286738 257 | }, 258 | "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" 259 | }, { 260 | "location": { 261 | "latitude": 406523420, 262 | "longitude": -742135517 263 | }, 264 | "name": "652 Garden Street, Elizabeth, NJ 07202, USA" 265 | }, { 266 | "location": { 267 | "latitude": 401827388, 268 | "longitude": -740294537 269 | }, 270 | "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" 271 | }, { 272 | "location": { 273 | "latitude": 410564152, 274 | "longitude": -743685054 275 | }, 276 | "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" 277 | }, { 278 | "location": { 279 | "latitude": 408472324, 280 | "longitude": -740726046 281 | }, 282 | "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" 283 | }, { 284 | "location": { 285 | "latitude": 412452168, 286 | "longitude": -740214052 287 | }, 288 | "name": "5 White Oak Lane, Stony Point, NY 10980, USA" 289 | }, { 290 | "location": { 291 | "latitude": 409146138, 292 | "longitude": -746188906 293 | }, 294 | "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" 295 | }, { 296 | "location": { 297 | "latitude": 404701380, 298 | "longitude": -744781745 299 | }, 300 | "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" 301 | }, { 302 | "location": { 303 | "latitude": 409642566, 304 | "longitude": -746017679 305 | }, 306 | "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" 307 | }, { 308 | "location": { 309 | "latitude": 408031728, 310 | "longitude": -748645385 311 | }, 312 | "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" 313 | }, { 314 | "location": { 315 | "latitude": 413700272, 316 | "longitude": -742135189 317 | }, 318 | "name": "367 Prospect Road, Chester, NY 10918, USA" 319 | }, { 320 | "location": { 321 | "latitude": 404310607, 322 | "longitude": -740282632 323 | }, 324 | "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" 325 | }, { 326 | "location": { 327 | "latitude": 409319800, 328 | "longitude": -746201391 329 | }, 330 | "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" 331 | }, { 332 | "location": { 333 | "latitude": 406685311, 334 | "longitude": -742108603 335 | }, 336 | "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" 337 | }, { 338 | "location": { 339 | "latitude": 419018117, 340 | "longitude": -749142781 341 | }, 342 | "name": "43 Dreher Road, Roscoe, NY 12776, USA" 343 | }, { 344 | "location": { 345 | "latitude": 412856162, 346 | "longitude": -745148837 347 | }, 348 | "name": "Swan Street, Pine Island, NY 10969, USA" 349 | }, { 350 | "location": { 351 | "latitude": 416560744, 352 | "longitude": -746721964 353 | }, 354 | "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" 355 | }, { 356 | "location": { 357 | "latitude": 405314270, 358 | "longitude": -749836354 359 | }, 360 | "name": "" 361 | }, { 362 | "location": { 363 | "latitude": 414219548, 364 | "longitude": -743327440 365 | }, 366 | "name": "" 367 | }, { 368 | "location": { 369 | "latitude": 415534177, 370 | "longitude": -742900616 371 | }, 372 | "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" 373 | }, { 374 | "location": { 375 | "latitude": 406898530, 376 | "longitude": -749127080 377 | }, 378 | "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" 379 | }, { 380 | "location": { 381 | "latitude": 407586880, 382 | "longitude": -741670168 383 | }, 384 | "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" 385 | }, { 386 | "location": { 387 | "latitude": 400106455, 388 | "longitude": -742870190 389 | }, 390 | "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" 391 | }, { 392 | "location": { 393 | "latitude": 400066188, 394 | "longitude": -746793294 395 | }, 396 | "name": "" 397 | }, { 398 | "location": { 399 | "latitude": 418803880, 400 | "longitude": -744102673 401 | }, 402 | "name": "40 Mountain Road, Napanoch, NY 12458, USA" 403 | }, { 404 | "location": { 405 | "latitude": 414204288, 406 | "longitude": -747895140 407 | }, 408 | "name": "" 409 | }, { 410 | "location": { 411 | "latitude": 414777405, 412 | "longitude": -740615601 413 | }, 414 | "name": "" 415 | }, { 416 | "location": { 417 | "latitude": 415464475, 418 | "longitude": -747175374 419 | }, 420 | "name": "48 North Road, Forestburgh, NY 12777, USA" 421 | }, { 422 | "location": { 423 | "latitude": 404062378, 424 | "longitude": -746376177 425 | }, 426 | "name": "" 427 | }, { 428 | "location": { 429 | "latitude": 405688272, 430 | "longitude": -749285130 431 | }, 432 | "name": "" 433 | }, { 434 | "location": { 435 | "latitude": 400342070, 436 | "longitude": -748788996 437 | }, 438 | "name": "" 439 | }, { 440 | "location": { 441 | "latitude": 401809022, 442 | "longitude": -744157964 443 | }, 444 | "name": "" 445 | }, { 446 | "location": { 447 | "latitude": 404226644, 448 | "longitude": -740517141 449 | }, 450 | "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" 451 | }, { 452 | "location": { 453 | "latitude": 410322033, 454 | "longitude": -747871659 455 | }, 456 | "name": "" 457 | }, { 458 | "location": { 459 | "latitude": 407100674, 460 | "longitude": -747742727 461 | }, 462 | "name": "" 463 | }, { 464 | "location": { 465 | "latitude": 418811433, 466 | "longitude": -741718005 467 | }, 468 | "name": "213 Bush Road, Stone Ridge, NY 12484, USA" 469 | }, { 470 | "location": { 471 | "latitude": 415034302, 472 | "longitude": -743850945 473 | }, 474 | "name": "" 475 | }, { 476 | "location": { 477 | "latitude": 411349992, 478 | "longitude": -743694161 479 | }, 480 | "name": "" 481 | }, { 482 | "location": { 483 | "latitude": 404839914, 484 | "longitude": -744759616 485 | }, 486 | "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" 487 | }, { 488 | "location": { 489 | "latitude": 414638017, 490 | "longitude": -745957854 491 | }, 492 | "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" 493 | }, { 494 | "location": { 495 | "latitude": 412127800, 496 | "longitude": -740173578 497 | }, 498 | "name": "" 499 | }, { 500 | "location": { 501 | "latitude": 401263460, 502 | "longitude": -747964303 503 | }, 504 | "name": "" 505 | }, { 506 | "location": { 507 | "latitude": 412843391, 508 | "longitude": -749086026 509 | }, 510 | "name": "" 511 | }, { 512 | "location": { 513 | "latitude": 418512773, 514 | "longitude": -743067823 515 | }, 516 | "name": "" 517 | }, { 518 | "location": { 519 | "latitude": 404318328, 520 | "longitude": -740835638 521 | }, 522 | "name": "42-102 Main Street, Belford, NJ 07718, USA" 523 | }, { 524 | "location": { 525 | "latitude": 419020746, 526 | "longitude": -741172328 527 | }, 528 | "name": "" 529 | }, { 530 | "location": { 531 | "latitude": 404080723, 532 | "longitude": -746119569 533 | }, 534 | "name": "" 535 | }, { 536 | "location": { 537 | "latitude": 401012643, 538 | "longitude": -744035134 539 | }, 540 | "name": "" 541 | }, { 542 | "location": { 543 | "latitude": 404306372, 544 | "longitude": -741079661 545 | }, 546 | "name": "" 547 | }, { 548 | "location": { 549 | "latitude": 403966326, 550 | "longitude": -748519297 551 | }, 552 | "name": "" 553 | }, { 554 | "location": { 555 | "latitude": 405002031, 556 | "longitude": -748407866 557 | }, 558 | "name": "" 559 | }, { 560 | "location": { 561 | "latitude": 409532885, 562 | "longitude": -742200683 563 | }, 564 | "name": "" 565 | }, { 566 | "location": { 567 | "latitude": 416851321, 568 | "longitude": -742674555 569 | }, 570 | "name": "" 571 | }, { 572 | "location": { 573 | "latitude": 406411633, 574 | "longitude": -741722051 575 | }, 576 | "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" 577 | }, { 578 | "location": { 579 | "latitude": 413069058, 580 | "longitude": -744597778 581 | }, 582 | "name": "261 Van Sickle Road, Goshen, NY 10924, USA" 583 | }, { 584 | "location": { 585 | "latitude": 418465462, 586 | "longitude": -746859398 587 | }, 588 | "name": "" 589 | }, { 590 | "location": { 591 | "latitude": 411733222, 592 | "longitude": -744228360 593 | }, 594 | "name": "" 595 | }, { 596 | "location": { 597 | "latitude": 410248224, 598 | "longitude": -747127767 599 | }, 600 | "name": "3 Hasta Way, Newton, NJ 07860, USA" 601 | }] 602 | --------------------------------------------------------------------------------