Clean up main crate and more work on macro

Signed-off-by: Lucio Franco <luciofranco14@gmail.com>
This commit is contained in:
Lucio Franco
2019-08-15 15:09:54 -04:00
parent 55941c0dd1
commit 0a8aaa8071
13 changed files with 438 additions and 307 deletions
+1
View File
@@ -2,5 +2,6 @@
members = [
"tonic",
"tonic-macros",
"tonic-examples",
"tower-h2"
]
+24
View File
@@ -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"
+1
View File
@@ -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;
}
+67
View File
@@ -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
View File
@@ -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));
-52
View File
@@ -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
View File
@@ -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,
}
+8 -4
View File
@@ -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);
-1
View File
@@ -16,7 +16,6 @@ impl<T> Response<T> {
}
}
/// Get a reference to the message
pub fn get_ref(&self) -> &T {
&self.message
}
+201
View File
@@ -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
View File
@@ -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)
}
}
}
}
+53
View File
@@ -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;
}