tokio-rs / gsoc

Organize the Google Summer of Code projects.
MIT License
6 stars 1 forks source link

Improve gRPC server #6

Open carllerche opened 5 years ago

carllerche commented 5 years ago

Tower gRPC provides a gRPC client / server implementation on top of the Tokio stack. Currently, the server API is tedious to use and has some limitations. The goal for the project is to implement a procedural macro to remove the boilerplate when defining gRPC server services. Also, a routing layer should be implemented in order to allow multiple gRPC services to respond on the same socket.

Expected outcomes

Skills

Difficulty level

Medium

carllerche commented 5 years ago

Here are some thoughts about what using a macro might look like:

use futures::Stream;

struct MyGreeter;

impl MyGreeter {
    fn new() -> MyGreeter {
        MyGreeter
    }
}

// Includes code generated from the `.proto` service and message definition.
include_proto!();

// For this to work, the `helloworld` module (generated by `include_proto!`)
// must be in scope. The macro will impl the `helloworld::Greeter` trait.
#[grpc(service = "helloworld.Greeter")]
impl MyGreeter {
    fn say_hello(&self, request: HelloRequest) -> impl Future<Item = HelloReply> {
        println!("HELLO; {:?}", request);
    }

    // The macro supports the following return types:
    //
    // -> impl Stream<Item = HelloReply>
    // -> impl Future<Item = impl Stream<Item = HelloReply>>
    // -> impl Future<Item = Response<impl Stream<Item = HelloReply>>>
    // -> MyFuture
    // -> impl Future<Item = MyStream>
    // -> impl Future<Item = Response<MyStream>>
    //
    // # Wish list
    //
    // The macro knows what the item type should be and the error type does not
    // matter as it gets mapped to an internal error. It would be nice if the
    // return type could be simplified to:
    //
    // -> impl Future
    // -> impl Stream
    //
    // This *should* be possible.
    fn streaming_hello<S>(&self, request: S) -> impl Stream
    where S: Stream<Item = HelloRequest>
    {
        unimplemented!();
    }
}
Hexilee commented 5 years ago

@carllerche As impl syntax is not supported in trait, do you means we should take input TokenStream like:

#[grpc(service = "helloworld.Greeter")]
impl MyGreeter {
    fn say_hello(&self, request: HelloRequest) -> impl Future<Item = HelloReply> {
        println!("HELLO; {:?}", request);
    }
}

and get output TokenStream like:

impl helloworld::Greeter for MyGreeter {
    fn say_hello<F: Future<Item = HelloReply>>(&self, request: HelloRequest) -> F  {
        println!("HELLO; {:?}", request);
    }
}

?

carllerche commented 5 years ago

@Hexilee The macro would have to translate impl syntax -> Box<Future>. This is what tower-web does