tokio-rs / tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
https://tokio.rs
MIT License
25.72k stars 2.35k forks source link

Tonic server uses encapsulation #6560

Closed tgy3300 closed 2 months ago

tgy3300 commented 2 months ago

Tonic server uses encapsulation

proto file

syntax = "proto3";

package logic;

service Logic { rpc Conn(ConnRequest) returns (ConnReply); }

message ConnRequest { string name = 1; }

message ConnReply { string message = 1; }

build.rs code

fn main() {
    tonic_build::configure()
        .build_server(true)
        .build_client(true)
        .out_dir("src/api")
        .compile(&["src/api/logic.proto"], &["src/api/"])
        .expect("Failed to generate logic grpc");
}

server side original call code

#[tokio::main]
async fn main() {
    let addr = "[::1]:50052".parse().unwrap();
    let greeter = LogicSrv::default();

    Server::builder()
        .add_service(LogicServer::new(greeter))
        .serve(addr)
        .await?;
}

#[derive(Debug, Default)]
pub struct LogicSrv;

#[tonic::async_trait]
impl Logic for LogicSrv {
    async fn conn(&self, request: Request<ConnRequest>) -> Result<Response<ConnReply>, Status> {
        println!("Got a request: {:#?}", request);

        let reply = ConnReply {
            message: format!("Hello {}", request.into_inner().name),
        };

        Ok(Response::new(reply))
    }
}

I now want to implement the encapsulation of the server-side code call, convenient call (some people may say, why to encapsulate, my purpose is, after encapsulation, I can put the server-side logic to the parameter, there is no need to repeat the use of Server::builder()), my approach is:

#[tokio::main]
async fn main() {
    grpc_srv_fun("[::1]:50052".to_string(), || {
            LogicServer::new(LogicSrv::default())
        }).await?;
}

async fn grpc_srv_fun<S, F>(addr: String, srv: F) -> Result<(), std::io::Error>
where
    S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>
        + NamedService
        + Clone
        + Send
        + 'static,
    S::Future: Send + 'static,
    F: Fn() -> S + Send + 'static,
{
    let addr = addr.parse().unwrap();
    Server::builder()
        .add_service(srv())
        .serve(addr)
        .await
        .unwrap();
    Ok(())
}

#[derive(Debug, Default)]
pub struct LogicSrv;

#[tonic::async_trait]
impl Logic for LogicSrv {
    async fn conn(&self, request: Request<ConnRequest>) -> Result<Response<ConnReply>, Status> {
        println!("Got a request: {:#?}", request);

        let reply = ConnReply {
            message: format!("Hello {}", request.into_inner().name),
        };

        Ok(Response::new(reply))
    }
}

Question: grpc_srv_fun() function of the srv parameter type is always an error, can I have the tonic::transport::server::Server.add_service() constraint parameter type, or an error, turn to your bosses

tgy3300 commented 2 months ago

Resolved, the reference dependency version is not the same issue

mox692 commented 2 months ago

If you have questions about the tonic, you can ask them in the tonic repo.