Clean up main crate and more work on macro
Signed-off-by: Lucio Franco <luciofranco14@gmail.com>
This commit is contained in:
@@ -2,5 +2,6 @@
|
||||
members = [
|
||||
"tonic",
|
||||
"tonic-macros",
|
||||
"tonic-examples",
|
||||
"tower-h2"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "tonic-examples"
|
||||
version = "0.1.0"
|
||||
authors = ["Lucio Franco <luciofranco14@gmail.com>"]
|
||||
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! {
|
||||
use tonic::_codegen;
|
||||
use proto::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GrpcServer {
|
||||
inner: std::sync::Arc<#s>,
|
||||
}
|
||||
|
||||
impl From<#s> for GrpcServer {
|
||||
fn from(t: #s) -> Self {
|
||||
impl GrpcServer {
|
||||
fn new(t: #s) -> Self {
|
||||
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 {
|
||||
type Response = tonic::Response<tonic::body::BoxAsyncBody>;
|
||||
impl _codegen::Service<_codegen::http::Request<tower_h2::RecvBody>> for GrpcServer {
|
||||
type Response = _codegen::http::Response<tonic::body::BoxAsyncBody>;
|
||||
type Error = tonic::error::Never;
|
||||
type Future = _codegen::ResponseFuture2<Self::Response, Self::Error>;
|
||||
|
||||
@@ -76,40 +77,48 @@ pub fn server(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
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();
|
||||
|
||||
match request.uri().path() {
|
||||
"/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 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 response = match grpc.unary_request(request).await {
|
||||
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)
|
||||
let res = grpc.unary(method, request).await;
|
||||
Ok(res)
|
||||
};
|
||||
|
||||
|
||||
Box::pin(fut)
|
||||
},
|
||||
|
||||
"helloworld.Greeter/SayHelloStream" => {
|
||||
unimplemented!()
|
||||
},
|
||||
_ => unimplemented!("use grpc unimplemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
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 async_stream::stream;
|
||||
use bytes::{Buf, BufMut, BytesMut, IntoBuf};
|
||||
use futures_core::TryStream;
|
||||
use futures_util::{future, TryStreamExt};
|
||||
use futures_core::{Stream, TryStream};
|
||||
use futures_util::{future, StreamExt};
|
||||
use http_body::Body;
|
||||
use prost::Message;
|
||||
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>
|
||||
where
|
||||
T: Encoder<Error = Status>,
|
||||
U: TryStream<Ok = T::Item, Error = Status> + Unpin,
|
||||
U: Stream<Item = Result<T::Item, Status>> + Unpin,
|
||||
{
|
||||
stream! {
|
||||
let mut buf = BytesMut::with_capacity(1024);
|
||||
|
||||
loop {
|
||||
match source.try_next().await {
|
||||
Ok(Some(item)) => {
|
||||
|
||||
|
||||
match source.next().await {
|
||||
Some(Ok(item)) => {
|
||||
buf.reserve(5);
|
||||
unsafe {
|
||||
buf.advance_mut(5);
|
||||
@@ -54,8 +50,8 @@ where
|
||||
|
||||
yield Ok(buf.split_to(len + 5).freeze().into_buf());
|
||||
},
|
||||
Ok(None) => break,
|
||||
Err(status) => yield Err(status),
|
||||
Some(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 {
|
||||
// Map Protobuf parse errors to an INTERNAL status code, as per
|
||||
// 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)]
|
||||
@@ -291,5 +287,4 @@ impl Decoder for UnitDecoder {
|
||||
enum State {
|
||||
ReadHeader,
|
||||
ReadBody { compression: bool, len: usize },
|
||||
Done,
|
||||
}
|
||||
|
||||
@@ -40,15 +40,19 @@ impl<T> Request<T> {
|
||||
self.message
|
||||
}
|
||||
|
||||
/// Convert an HTTP request to a gRPC request
|
||||
pub fn from_http(http: http::Request<T>) -> Self {
|
||||
let (head, message) = http.into_parts();
|
||||
pub(crate) fn from_http_parts(parts: http::request::Parts, message: T) -> Self {
|
||||
Request {
|
||||
metadata: MetadataMap::from_headers(head.headers),
|
||||
metadata: MetadataMap::from_headers(parts.headers),
|
||||
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> {
|
||||
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 {
|
||||
&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::{
|
||||
body::{BoxAsyncBody, BytesBuf},
|
||||
codec::{self, Codec},
|
||||
Request, Response, Status,
|
||||
mod grpc;
|
||||
mod service;
|
||||
|
||||
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