Clean up main crate and more work on macro
Signed-off-by: Lucio Franco <[email protected]>
This commit is contained in:
@@ -2,5 +2,6 @@
|
|||||||
members = [
|
members = [
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-macros",
|
"tonic-macros",
|
||||||
|
"tonic-examples",
|
||||||
"tower-h2"
|
"tower-h2"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "tonic-examples"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Lucio Franco <[email protected]>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "helloworld-server"
|
||||||
|
path = "src/helloworld/server.rs"
|
||||||
|
|
||||||
|
# [[bin]]
|
||||||
|
# name = "helloworld-client"
|
||||||
|
# path = "src/helloworld/client.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tonic = { path = "../tonic" }
|
||||||
|
tower-h2 = { path = "../tower-h2" }
|
||||||
|
futures-preview = { version = "=0.3.0-alpha.17", default-features = false, features = ["alloc"]}
|
||||||
|
tokio = "=0.2.0-alpha.1"
|
||||||
|
prost = "0.5"
|
||||||
|
prost-derive = "0.5"
|
||||||
|
bytes = "0.4"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2015 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option java_package = "io.grpc.examples.helloworld";
|
||||||
|
option java_outer_classname = "HelloWorldProto";
|
||||||
|
|
||||||
|
package helloworld;
|
||||||
|
|
||||||
|
// The greeting service definition.
|
||||||
|
service Greeter {
|
||||||
|
// Sends a greeting
|
||||||
|
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request message containing the user's name.
|
||||||
|
message HelloRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The response message containing the greetings
|
||||||
|
message HelloReply {
|
||||||
|
string message = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#![feature(async_await)]
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::{timer::Delay, net::TcpListener};
|
||||||
|
use tonic::{Request, Response, Status};
|
||||||
|
use tower_h2::Server;
|
||||||
|
|
||||||
|
mod proto {
|
||||||
|
#[derive(Clone, PartialEq, prost::Message)]
|
||||||
|
pub struct HelloRequest {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: std::string::String,
|
||||||
|
}
|
||||||
|
/// The response message containing the greetings
|
||||||
|
#[derive(Clone, PartialEq, prost::Message)]
|
||||||
|
pub struct HelloReply {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub message: std::string::String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct MyGreeter {
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::server(service = "helloworld.Greeter", proto = "proto")]
|
||||||
|
impl MyGreeter {
|
||||||
|
pub async fn say_hello(&self, request: Request<proto::HelloRequest>) -> Result<Response<proto::HelloReply>, Status> {
|
||||||
|
println!("Got a request: {:?}", request);
|
||||||
|
|
||||||
|
let string = &self.data;
|
||||||
|
|
||||||
|
let when = tokio::clock::now() + Duration::from_millis(100);
|
||||||
|
Delay::new(when).await;
|
||||||
|
|
||||||
|
println!("My data: {:?}", string);
|
||||||
|
|
||||||
|
Delay::new(when).await;
|
||||||
|
|
||||||
|
let reply = HelloReply {
|
||||||
|
message: "Zomg, it works!".into(),
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let addr = "[::1]:50051".parse().unwrap();
|
||||||
|
let mut bind = TcpListener::bind(&addr)?;
|
||||||
|
|
||||||
|
let greeter = MyGreeter::default();
|
||||||
|
let mut server = Server::new(GrpcServer::new(greeter), Default::default());
|
||||||
|
|
||||||
|
while let Ok((sock, _addr)) = bind.accept().await {
|
||||||
|
if let Err(e) = sock.set_nodelay(true) {
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = server.serve(sock).await {
|
||||||
|
println!("H2 ERROR: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
+32
-23
@@ -41,14 +41,15 @@ pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
let ts = quote! {
|
let ts = quote! {
|
||||||
use tonic::_codegen;
|
use tonic::_codegen;
|
||||||
|
use proto::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GrpcServer {
|
pub struct GrpcServer {
|
||||||
inner: std::sync::Arc<#s>,
|
inner: std::sync::Arc<#s>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<#s> for GrpcServer {
|
impl GrpcServer {
|
||||||
fn from(t: #s) -> Self {
|
fn new(t: #s) -> Self {
|
||||||
Self { inner: std::sync::Arc::new(t) }
|
Self { inner: std::sync::Arc::new(t) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,8 +68,8 @@ pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl _codegen::Service<_codegen::http::Request<()>> for GrpcServer {
|
impl _codegen::Service<_codegen::http::Request<tower_h2::RecvBody>> for GrpcServer {
|
||||||
type Response = tonic::Response<tonic::body::BoxAsyncBody>;
|
type Response = _codegen::http::Response<tonic::body::BoxAsyncBody>;
|
||||||
type Error = tonic::error::Never;
|
type Error = tonic::error::Never;
|
||||||
type Future = _codegen::ResponseFuture2<Self::Response, Self::Error>;
|
type Future = _codegen::ResponseFuture2<Self::Response, Self::Error>;
|
||||||
|
|
||||||
@@ -76,40 +77,48 @@ pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
Ok(()).into()
|
Ok(()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, request: _codegen::http::Request<()>) -> Self::Future {
|
fn call(&mut self, request: _codegen::http::Request<tower_h2::RecvBody>) -> Self::Future {
|
||||||
let inner = self.inner.clone();
|
let inner = self.inner.clone();
|
||||||
|
|
||||||
match request.uri().path() {
|
match request.uri().path() {
|
||||||
"/helloworld.Greeter/SayHello" => {
|
"/helloworld.Greeter/SayHello" => {
|
||||||
|
use tonic::_codegen::*;
|
||||||
|
use tonic::*;
|
||||||
|
|
||||||
|
pub struct SayHello(pub std::sync::Arc<#s>);
|
||||||
|
|
||||||
|
impl tonic::server::UnaryService<HelloRequest> for SayHello {
|
||||||
|
type Response = HelloReply;
|
||||||
|
type Future = Pin<Box<dyn Future<Output = Result<Response<Self::Response>, Status>> + Send + 'static>>;
|
||||||
|
|
||||||
|
fn call(&mut self, request: Request<HelloRequest>) -> Self::Future {
|
||||||
|
let inner = self.0.clone();
|
||||||
|
let fut = async move {
|
||||||
|
inner.#m_ident(request).await
|
||||||
|
};
|
||||||
|
Box::pin(fut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let inner = self.inner.clone();
|
let inner = self.inner.clone();
|
||||||
|
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
let codec = tonic::codec::UnitCodec::default();
|
let method = SayHello(inner);
|
||||||
|
let codec = tonic::codec::ProstCodec::new();
|
||||||
let mut grpc = tonic::server::Grpc::new(codec);
|
let mut grpc = tonic::server::Grpc::new(codec);
|
||||||
|
let res = grpc.unary(method, request).await;
|
||||||
let response = match grpc.unary_request(request).await {
|
Ok(res)
|
||||||
Ok(request) => inner.#m_ident(request).await,
|
|
||||||
Err(status) => Err(status),
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = grpc.unary_response(response.unwrap())
|
|
||||||
.await
|
|
||||||
.map(|b| tonic::body::BoxAsyncBody::new(b));
|
|
||||||
// .map(|b| tonic::body::BoxBody::map(b))
|
|
||||||
|
|
||||||
Ok(response)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Box::pin(fut)
|
Box::pin(fut)
|
||||||
},
|
},
|
||||||
|
|
||||||
"helloworld.Greeter/SayHelloStream" => {
|
|
||||||
unimplemented!()
|
|
||||||
},
|
|
||||||
_ => unimplemented!("use grpc unimplemented")
|
_ => unimplemented!("use grpc unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
original.extend(TokenStream::from(ts));
|
original.extend(TokenStream::from(ts));
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#![feature(async_await)]
|
|
||||||
|
|
||||||
use futures::Stream;
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::timer::Delay;
|
|
||||||
use tonic::{Request, Response, Status};
|
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// struct HelloRequest;
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// struct HelloResponse;
|
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
|
||||||
pub struct MyGreeter {
|
|
||||||
data: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tonic::server(service = "proto/helloworld.proto")]
|
|
||||||
impl MyGreeter {
|
|
||||||
pub async fn say_hello(&self, request: Request<()>) -> Result<Response<()>, Status> {
|
|
||||||
println!("Got a request: {:?}", request);
|
|
||||||
|
|
||||||
let string = &self.data;
|
|
||||||
|
|
||||||
let when = tokio::clock::now() + Duration::from_millis(100);
|
|
||||||
Delay::new(when).await;
|
|
||||||
|
|
||||||
println!("My data: {:?}", string);
|
|
||||||
|
|
||||||
Delay::new(when).await;
|
|
||||||
|
|
||||||
Ok(Response::new(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub async fn streaming(&self, request: Request<impl Stream>) -> Result<Response<impl Stream>, Status> {
|
|
||||||
// unimplemented!()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub async fn server_stream(&self, request: Request<()>) -> Result<impl Stream, Status> {
|
|
||||||
// unimplemented!()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub async fn client_stream(&self, request: Request<impl Stream>) -> Result<(), Status> {
|
|
||||||
// unimplemented!()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn grpc() {
|
|
||||||
let svc = MyGreeter::default();
|
|
||||||
let mut _server = GrpcServer::from(svc);
|
|
||||||
}
|
|
||||||
+8
-13
@@ -1,10 +1,8 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use crate::{body::BytesBuf, Code, Status};
|
use crate::{body::BytesBuf, Code, Status};
|
||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
|
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
|
||||||
use futures_core::TryStream;
|
use futures_core::{Stream, TryStream};
|
||||||
use futures_util::{future, TryStreamExt};
|
use futures_util::{future, StreamExt};
|
||||||
use http_body::Body;
|
use http_body::Body;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -27,16 +25,14 @@ pub trait Codec {
|
|||||||
pub fn encode<T, U>(mut encoder: T, mut source: U) -> impl TryStream<Ok = BytesBuf, Error = Status>
|
pub fn encode<T, U>(mut encoder: T, mut source: U) -> impl TryStream<Ok = BytesBuf, Error = Status>
|
||||||
where
|
where
|
||||||
T: Encoder<Error = Status>,
|
T: Encoder<Error = Status>,
|
||||||
U: TryStream<Ok = T::Item, Error = Status> + Unpin,
|
U: Stream<Item = Result<T::Item, Status>> + Unpin,
|
||||||
{
|
{
|
||||||
stream! {
|
stream! {
|
||||||
let mut buf = BytesMut::with_capacity(1024);
|
let mut buf = BytesMut::with_capacity(1024);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match source.try_next().await {
|
match source.next().await {
|
||||||
Ok(Some(item)) => {
|
Some(Ok(item)) => {
|
||||||
|
|
||||||
|
|
||||||
buf.reserve(5);
|
buf.reserve(5);
|
||||||
unsafe {
|
unsafe {
|
||||||
buf.advance_mut(5);
|
buf.advance_mut(5);
|
||||||
@@ -54,8 +50,8 @@ where
|
|||||||
|
|
||||||
yield Ok(buf.split_to(len + 5).freeze().into_buf());
|
yield Ok(buf.split_to(len + 5).freeze().into_buf());
|
||||||
},
|
},
|
||||||
Ok(None) => break,
|
Some(Err(status)) => yield Err(status),
|
||||||
Err(status) => yield Err(status),
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +237,7 @@ impl<U: Message + Default> Decoder for ProstDecoder<U> {
|
|||||||
fn from_decode_error(error: prost::DecodeError) -> crate::Status {
|
fn from_decode_error(error: prost::DecodeError) -> crate::Status {
|
||||||
// Map Protobuf parse errors to an INTERNAL status code, as per
|
// Map Protobuf parse errors to an INTERNAL status code, as per
|
||||||
// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
|
// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
|
||||||
crate::Status::new(crate::Code::Internal, error.to_string())
|
Status::new(Code::Internal, error.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -291,5 +287,4 @@ impl Decoder for UnitDecoder {
|
|||||||
enum State {
|
enum State {
|
||||||
ReadHeader,
|
ReadHeader,
|
||||||
ReadBody { compression: bool, len: usize },
|
ReadBody { compression: bool, len: usize },
|
||||||
Done,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,15 +40,19 @@ impl<T> Request<T> {
|
|||||||
self.message
|
self.message
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert an HTTP request to a gRPC request
|
pub(crate) fn from_http_parts(parts: http::request::Parts, message: T) -> Self {
|
||||||
pub fn from_http(http: http::Request<T>) -> Self {
|
|
||||||
let (head, message) = http.into_parts();
|
|
||||||
Request {
|
Request {
|
||||||
metadata: MetadataMap::from_headers(head.headers),
|
metadata: MetadataMap::from_headers(parts.headers),
|
||||||
message,
|
message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert an HTTP request to a gRPC request
|
||||||
|
pub fn from_http(http: http::Request<T>) -> Self {
|
||||||
|
let (parts, message) = http.into_parts();
|
||||||
|
Request::from_http_parts(parts, message)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn into_http(self, uri: http::Uri) -> http::Request<T> {
|
pub fn into_http(self, uri: http::Uri) -> http::Request<T> {
|
||||||
let mut request = http::Request::new(self.message);
|
let mut request = http::Request::new(self.message);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ impl<T> Response<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the message
|
|
||||||
pub fn get_ref(&self) -> &T {
|
pub fn get_ref(&self) -> &T {
|
||||||
&self.message
|
&self.message
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
use crate::{
|
||||||
|
body::{BoxAsyncBody, BytesBuf},
|
||||||
|
codec::{decode, encode, Codec},
|
||||||
|
server::{ClientStreamingService, ServerStreamingService, StreamingService, UnaryService},
|
||||||
|
Code, Request, Response, Status,
|
||||||
|
};
|
||||||
|
use futures_core::{Stream, TryStream};
|
||||||
|
use futures_util::{future, stream, StreamExt, TryStreamExt};
|
||||||
|
use http_body::Body;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
type BoxStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send + 'static>>;
|
||||||
|
|
||||||
|
pub struct Grpc<T> {
|
||||||
|
codec: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Grpc<T>
|
||||||
|
where
|
||||||
|
T: Codec,
|
||||||
|
T::Decoder: Send + 'static,
|
||||||
|
T::Decode: Send + Unpin + 'static,
|
||||||
|
T::Encoder: Send + 'static,
|
||||||
|
T::Encode: Send + Unpin + 'static,
|
||||||
|
{
|
||||||
|
pub fn new(codec: T) -> Self {
|
||||||
|
Self { codec }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn unary<S, B>(
|
||||||
|
&mut self,
|
||||||
|
mut service: S,
|
||||||
|
req: http::Request<B>,
|
||||||
|
) -> http::Response<BoxAsyncBody>
|
||||||
|
where
|
||||||
|
S: UnaryService<T::Decode, Response = T::Encode>,
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let request = match self.map_request_unary(req).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(status) => {
|
||||||
|
return self
|
||||||
|
.map_response::<stream::Once<future::Ready<Result<T::Encode, Status>>>>(Err(
|
||||||
|
status,
|
||||||
|
))
|
||||||
|
.map(BoxAsyncBody::new_try);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = service
|
||||||
|
.call(request)
|
||||||
|
.await
|
||||||
|
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
||||||
|
|
||||||
|
self.map_response(response).map(BoxAsyncBody::new_try)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn server_streaming<S, B>(
|
||||||
|
&mut self,
|
||||||
|
mut service: S,
|
||||||
|
req: http::Request<B>,
|
||||||
|
) -> http::Response<BoxAsyncBody>
|
||||||
|
where
|
||||||
|
S: ServerStreamingService<T::Decode, Response = T::Encode>,
|
||||||
|
S::ResponseStream: Send + 'static,
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let request = match self.map_request_unary(req).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(status) => {
|
||||||
|
return self
|
||||||
|
.map_response::<S::ResponseStream>(Err(status))
|
||||||
|
.map(BoxAsyncBody::new_try);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = service.call(request).await;
|
||||||
|
|
||||||
|
self.map_response(response).map(BoxAsyncBody::new_try)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn client_streaming<S, B>(
|
||||||
|
&mut self,
|
||||||
|
mut service: S,
|
||||||
|
req: http::Request<B>,
|
||||||
|
) -> http::Response<BoxAsyncBody>
|
||||||
|
where
|
||||||
|
S: ClientStreamingService<BoxStream<T::Decode>, Response = T::Encode>,
|
||||||
|
T::Decode: Send,
|
||||||
|
T::Decoder: Send + 'static,
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let request = self.map_request_streaming(req);
|
||||||
|
let response = service
|
||||||
|
.call(request)
|
||||||
|
.await
|
||||||
|
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
||||||
|
self.map_response(response).map(BoxAsyncBody::new_try)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn streaming<S, B>(
|
||||||
|
&mut self,
|
||||||
|
mut service: S,
|
||||||
|
req: http::Request<B>,
|
||||||
|
) -> http::Response<BoxAsyncBody>
|
||||||
|
where
|
||||||
|
S: StreamingService<BoxStream<T::Decode>, Response = T::Encode> + Send,
|
||||||
|
S::ResponseStream: Send + 'static,
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let request = self.map_request_streaming(req);
|
||||||
|
let response = service.call(request).await;
|
||||||
|
self.map_response(response).map(BoxAsyncBody::new_try)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn map_request_unary<B>(
|
||||||
|
&mut self,
|
||||||
|
request: http::Request<B>,
|
||||||
|
) -> Result<Request<T::Decode>, Status>
|
||||||
|
where
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
let (parts, body) = request.into_parts();
|
||||||
|
let stream = decode(self.codec.decoder(), body).into_stream();
|
||||||
|
|
||||||
|
futures_util::pin_mut!(stream);
|
||||||
|
|
||||||
|
let message = stream
|
||||||
|
.try_next()
|
||||||
|
.await?
|
||||||
|
.ok_or(Status::new(Code::Internal, "Missing request message."))?;
|
||||||
|
|
||||||
|
Ok(Request::from_http_parts(parts, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_request_streaming<B>(
|
||||||
|
&mut self,
|
||||||
|
request: http::Request<B>,
|
||||||
|
) -> Request<BoxStream<T::Decode>>
|
||||||
|
where
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<crate::Error> + Send,
|
||||||
|
{
|
||||||
|
Request::from_http(
|
||||||
|
request.map(|b| {
|
||||||
|
decode(self.codec.decoder(), b).into_stream().boxed() as BoxStream<T::Decode>
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_response<B>(
|
||||||
|
&mut self,
|
||||||
|
response: Result<crate::Response<B>, Status>,
|
||||||
|
) -> http::Response<BoxStream<BytesBuf>>
|
||||||
|
where
|
||||||
|
B: TryStream<Ok = T::Encode, Error = Status> + Send + 'static,
|
||||||
|
{
|
||||||
|
match response {
|
||||||
|
Ok(r) => {
|
||||||
|
let (mut parts, body) = r.into_http().into_parts();
|
||||||
|
|
||||||
|
// Set the content type
|
||||||
|
parts.headers.insert(
|
||||||
|
http::header::CONTENT_TYPE,
|
||||||
|
http::header::HeaderValue::from_static(T::CONTENT_TYPE),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: find way to pin this to the stack instead
|
||||||
|
let body = Box::pin(body.into_stream());
|
||||||
|
let body = encode(self.codec.encoder(), body).into_stream();
|
||||||
|
|
||||||
|
let body = Box::pin(body) as BoxStream<BytesBuf>;
|
||||||
|
http::Response::from_parts(parts, body)
|
||||||
|
}
|
||||||
|
Err(status) => {
|
||||||
|
let status = stream::once(future::err(status));
|
||||||
|
let body = encode(self.codec.encoder(), status).into_stream();
|
||||||
|
let (mut parts, _body) = Response::new(()).into_http().into_parts();
|
||||||
|
|
||||||
|
parts.headers.insert(
|
||||||
|
http::header::CONTENT_TYPE,
|
||||||
|
http::header::HeaderValue::from_static(T::CONTENT_TYPE),
|
||||||
|
);
|
||||||
|
|
||||||
|
let body = Box::pin(body) as BoxStream<BytesBuf>;
|
||||||
|
http::Response::from_parts(parts, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-214
@@ -1,215 +1,7 @@
|
|||||||
use crate::{
|
mod grpc;
|
||||||
body::{BoxAsyncBody, BytesBuf},
|
mod service;
|
||||||
codec::{self, Codec},
|
|
||||||
Request, Response, Status,
|
pub use self::grpc::Grpc;
|
||||||
|
pub use self::service::{
|
||||||
|
ClientStreamingService, ServerStreamingService, StreamingService, UnaryService,
|
||||||
};
|
};
|
||||||
use futures_core::{Future, Stream, TryStream};
|
|
||||||
use futures_util::{future, stream, TryStreamExt};
|
|
||||||
use http_body::Body;
|
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
type BoxStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send + 'static>>;
|
|
||||||
|
|
||||||
pub struct Grpc<T> {
|
|
||||||
codec: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
// type UnaryFuture<B> = Once<Ready<Result<B, Status>>>;
|
|
||||||
// type ResponseBody = impl Stream<Item = Result<crate::body::BytesBuf, Status>>;
|
|
||||||
|
|
||||||
pub trait UnaryService<R> {
|
|
||||||
/// Protobuf response message type
|
|
||||||
type Response;
|
|
||||||
|
|
||||||
/// Response future
|
|
||||||
type Future: Future<Output = Result<crate::Response<Self::Response>, Status>>;
|
|
||||||
|
|
||||||
/// Call the service
|
|
||||||
fn call(&mut self, request: Request<R>) -> Self::Future;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ServerStreamingService<R> {
|
|
||||||
/// Protobuf response message type
|
|
||||||
type Response;
|
|
||||||
|
|
||||||
/// Stream of outbound response messages
|
|
||||||
type ResponseStream: TryStream<Ok = Self::Response, Error = crate::Status> + Unpin;
|
|
||||||
|
|
||||||
/// Response future
|
|
||||||
type Future: Future<Output = Result<crate::Response<Self::ResponseStream>, crate::Status>>;
|
|
||||||
|
|
||||||
/// Call the service
|
|
||||||
fn call(&mut self, request: Request<R>) -> Self::Future;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ClientStreamingService<RequestStream> {
|
|
||||||
/// Protobuf response message type
|
|
||||||
type Response;
|
|
||||||
|
|
||||||
/// Response future
|
|
||||||
type Future: Future<Output = Result<crate::Response<Self::Response>, Status>>;
|
|
||||||
|
|
||||||
/// Call the service
|
|
||||||
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait StreamingService<RequestStream> {
|
|
||||||
/// Protobuf response message type
|
|
||||||
type Response;
|
|
||||||
|
|
||||||
/// Stream of outbound response messages
|
|
||||||
type ResponseStream: TryStream<Ok = Self::Response, Error = crate::Status> + Unpin;
|
|
||||||
|
|
||||||
/// Response future
|
|
||||||
type Future: Future<Output = Result<crate::Response<Self::ResponseStream>, crate::Status>>;
|
|
||||||
|
|
||||||
/// Call the service
|
|
||||||
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Grpc<T>
|
|
||||||
where
|
|
||||||
T: Codec,
|
|
||||||
T::Decode: Unpin + 'static,
|
|
||||||
T::Encoder: Send + 'static,
|
|
||||||
T::Encode: Send + Unpin + 'static,
|
|
||||||
{
|
|
||||||
pub fn new(codec: T) -> Self {
|
|
||||||
Self { codec }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn unary<S, B>(
|
|
||||||
&mut self,
|
|
||||||
mut service: S,
|
|
||||||
req: http::Request<B>,
|
|
||||||
) -> http::Response<BoxAsyncBody>
|
|
||||||
where
|
|
||||||
S: UnaryService<T::Decode, Response = T::Encode>,
|
|
||||||
B: Body,
|
|
||||||
B::Error: Into<crate::Error>,
|
|
||||||
{
|
|
||||||
let (_parts, body) = req.into_parts();
|
|
||||||
let stream = codec::decode(self.codec.decoder(), body).into_stream();
|
|
||||||
futures_util::pin_mut!(stream);
|
|
||||||
let message = stream.try_next().await.unwrap().unwrap();
|
|
||||||
let request = Request::new(message);
|
|
||||||
let response = service
|
|
||||||
.call(request)
|
|
||||||
.await
|
|
||||||
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
|
||||||
|
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn server_streaming<S, B>(
|
|
||||||
&mut self,
|
|
||||||
mut service: S,
|
|
||||||
req: http::Request<B>,
|
|
||||||
) -> http::Response<BoxAsyncBody>
|
|
||||||
where
|
|
||||||
S: ServerStreamingService<T::Decode, Response = T::Encode>,
|
|
||||||
S::ResponseStream: Send + 'static,
|
|
||||||
B: Body,
|
|
||||||
B::Error: Into<crate::Error>,
|
|
||||||
{
|
|
||||||
let (_parts, body) = req.into_parts();
|
|
||||||
let stream = codec::decode(self.codec.decoder(), body).into_stream();
|
|
||||||
futures_util::pin_mut!(stream);
|
|
||||||
let message = stream.try_next().await.unwrap().unwrap();
|
|
||||||
let request = Request::new(message);
|
|
||||||
let response = service.call(request).await;
|
|
||||||
|
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn client_streaming<S, B>(
|
|
||||||
&mut self,
|
|
||||||
mut service: S,
|
|
||||||
req: http::Request<B>,
|
|
||||||
) -> http::Response<impl TryStream<Ok = crate::body::BytesBuf, Error = Status>>
|
|
||||||
where
|
|
||||||
S: ClientStreamingService<BoxStream<T::Decode>, Response = T::Encode>,
|
|
||||||
T::Decode: Send,
|
|
||||||
T::Decoder: Send + 'static,
|
|
||||||
B: Body + Send + 'static,
|
|
||||||
B::Data: Send,
|
|
||||||
B::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
|
||||||
let (_parts, body) = req.into_parts();
|
|
||||||
let stream = codec::decode(self.codec.decoder(), body).into_stream();
|
|
||||||
let stream = Box::pin(stream) as BoxStream<T::Decode>;
|
|
||||||
let request = Request::new(stream);
|
|
||||||
let response = service.call(request).await.unwrap();
|
|
||||||
let message = response.into_inner();
|
|
||||||
let source = stream::once(future::ok(message));
|
|
||||||
let body = codec::encode(self.codec.encoder(), source);
|
|
||||||
|
|
||||||
http::Response::new(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn streaming<S, B>(
|
|
||||||
&mut self,
|
|
||||||
mut service: S,
|
|
||||||
req: http::Request<B>,
|
|
||||||
) -> http::Response<impl TryStream<Ok = crate::body::BytesBuf, Error = Status>>
|
|
||||||
where
|
|
||||||
S: StreamingService<BoxStream<T::Decode>, Response = T::Encode>,
|
|
||||||
T::Decode: Send,
|
|
||||||
T::Decoder: Send + 'static,
|
|
||||||
B: Body + Send + 'static,
|
|
||||||
B::Data: Send,
|
|
||||||
B::Error: Into<crate::Error> + Send,
|
|
||||||
{
|
|
||||||
let (_parts, body) = req.into_parts();
|
|
||||||
let stream = codec::decode(self.codec.decoder(), body).into_stream();
|
|
||||||
let stream = Box::pin(stream) as BoxStream<T::Decode>;
|
|
||||||
let request = Request::new(stream);
|
|
||||||
let response = service.call(request).await.unwrap();
|
|
||||||
let source = response.into_inner();
|
|
||||||
let body = codec::encode(self.codec.encoder(), source);
|
|
||||||
|
|
||||||
http::Response::new(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn map_request<B>(&mut self, request: http::Request<B>) -> Request<B> {
|
|
||||||
// Request::from_http(request.map(|b| codec::decode(self.codec.decoder(), b)))
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn map_response<B>(
|
|
||||||
&mut self,
|
|
||||||
response: Result<crate::Response<B>, Status>,
|
|
||||||
) -> http::Response<BoxStream<BytesBuf>>
|
|
||||||
where
|
|
||||||
B: TryStream<Ok = T::Encode, Error = Status> + Send + Unpin + 'static,
|
|
||||||
{
|
|
||||||
match response {
|
|
||||||
Ok(r) => {
|
|
||||||
let (mut parts, body) = r.into_http().into_parts();
|
|
||||||
|
|
||||||
// Set the content type
|
|
||||||
parts.headers.insert(
|
|
||||||
http::header::CONTENT_TYPE,
|
|
||||||
http::header::HeaderValue::from_static(T::CONTENT_TYPE),
|
|
||||||
);
|
|
||||||
|
|
||||||
let body = codec::encode(self.codec.encoder(), body).into_stream();
|
|
||||||
|
|
||||||
let body = Box::pin(body) as BoxStream<BytesBuf>;
|
|
||||||
http::Response::from_parts(parts, body)
|
|
||||||
}
|
|
||||||
Err(status) => {
|
|
||||||
let status = stream::once(future::err(status));
|
|
||||||
let body = codec::encode(self.codec.encoder(), status).into_stream();
|
|
||||||
let (mut parts, _body) = Response::new(()).into_http().into_parts();
|
|
||||||
|
|
||||||
parts.headers.insert(
|
|
||||||
http::header::CONTENT_TYPE,
|
|
||||||
http::header::HeaderValue::from_static(T::CONTENT_TYPE),
|
|
||||||
);
|
|
||||||
|
|
||||||
let body = Box::pin(body) as BoxStream<BytesBuf>;
|
|
||||||
http::Response::from_parts(parts, body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
use crate::{Request, Response, Status};
|
||||||
|
use futures_core::Stream;
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
pub trait UnaryService<R> {
|
||||||
|
/// Protobuf response message type
|
||||||
|
type Response;
|
||||||
|
|
||||||
|
/// Response future
|
||||||
|
type Future: Future<Output = Result<Response<Self::Response>, Status>>;
|
||||||
|
|
||||||
|
/// Call the service
|
||||||
|
fn call(&mut self, request: Request<R>) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ServerStreamingService<R> {
|
||||||
|
/// Protobuf response message type
|
||||||
|
type Response;
|
||||||
|
|
||||||
|
/// Stream of outbound response messages
|
||||||
|
type ResponseStream: Stream<Item = Result<Self::Response, Status>> + Unpin;
|
||||||
|
|
||||||
|
/// Response future
|
||||||
|
type Future: Future<Output = Result<Response<Self::ResponseStream>, Status>>;
|
||||||
|
|
||||||
|
/// Call the service
|
||||||
|
fn call(&mut self, request: Request<R>) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ClientStreamingService<RequestStream> {
|
||||||
|
/// Protobuf response message type
|
||||||
|
type Response;
|
||||||
|
|
||||||
|
/// Response future
|
||||||
|
type Future: Future<Output = Result<Response<Self::Response>, Status>>;
|
||||||
|
|
||||||
|
/// Call the service
|
||||||
|
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait StreamingService<RequestStream> {
|
||||||
|
/// Protobuf response message type
|
||||||
|
type Response;
|
||||||
|
|
||||||
|
/// Stream of outbound response messages
|
||||||
|
type ResponseStream: Stream<Item = Result<Self::Response, Status>> + Unpin;
|
||||||
|
|
||||||
|
/// Response future
|
||||||
|
type Future: Future<Output = Result<Response<Self::ResponseStream>, Status>>;
|
||||||
|
|
||||||
|
/// Call the service
|
||||||
|
fn call(&mut self, request: Request<RequestStream>) -> Self::Future;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user