cloudwego / volo

Rust RPC framework with high-performance and strong-extensibility for building micro-services.
https://crates.io/crates/volo
Apache License 2.0
2.2k stars 179 forks source link

volo-grpc和volo-http的中间件不知是否通用,是否支持动态加载 #472

Open tgy3300 opened 1 month ago

tgy3300 commented 1 month ago

先说问题:

问题1:http服务能使用开发的测试中间件TestLayer和DemoLayer,但是grpc服务不能,所以一问:volo_grpc和volo_http的中间件是否通用

问题2:开发的测试中间件TestLayer和DemoLayer能否放在一个Vec中,如果能,哪这个Vec的类型如何定义,如下:

let mut layer_data = Vec::new();    //这里的变量类型如何定义
layer_data.push(TestLayer::new());
layer_data.push(DemoLayer::new());

volo-grpc和volo-http的中间件不知是否通用 下面是开发的测试中间件

//-----DemoLayer--------
use motore::{layer::Layer, service::Service};
use volo_http::{
    context::ServerContext, request::ServerRequest, response::ServerResponse, server::IntoResponse,
};

#[derive(Debug, Clone)]
pub struct DemoLayer;

impl DemoLayer {
    pub fn new() -> Self {
        Self
    }
}

impl<S> Layer<S> for DemoLayer {
    type Service = Demo<S>;

    fn layer(self, inner: S) -> Self::Service {
        println!("-----demo layer-----");
        Self::Service::new(inner)
    }
}

#[derive(Debug, Clone)]
pub struct Demo<S> {
    inner: S,
}

impl<S> Demo<S> {
    pub fn new(inner: S) -> Self {
        Self { inner }
    }
}

impl<S> Service<ServerContext, ServerRequest> for Demo<S>
where
    S: Service<ServerContext, ServerRequest> + Send + Sync + 'static,
    S::Response: IntoResponse,
    S::Error: IntoResponse,
{
    type Response = ServerResponse;
    type Error = S::Error;

    async fn call(
        &self,
        cx: &mut ServerContext,
        req: ServerRequest,
    ) -> Result<Self::Response, Self::Error> {
        println!("-----demo call-----");
        Ok(self.inner.call(cx, req).await.into_response())
    }
}
//-----TestLayer--------
use motore::{layer::Layer, service::Service};
use volo_http::{
    context::ServerContext, request::ServerRequest, response::ServerResponse, server::IntoResponse,
};

#[derive(Debug, Clone)]
pub struct TestLayer;

impl TestLayer {
    pub fn new() -> Self {
        Self
    }
}

impl<S> Layer<S> for TestLayer {
    type Service = Test<S>;

    fn layer(self, inner: S) -> Self::Service {
        println!("-----test layer-----");
        Self::Service::new(inner)
    }
}

#[derive(Debug, Clone)]
pub struct Test<S> {
    inner: S,
}

impl<S> Test<S> {
    pub fn new(inner: S) -> Self {
        Self { inner }
    }
}

impl<S> Service<ServerContext, ServerRequest> for Test<S>
where
    S: Service<ServerContext, ServerRequest> + Send + Sync + 'static,
    S::Response: IntoResponse,
    S::Error: IntoResponse,
{
    type Response = ServerResponse;
    type Error = S::Error;

    async fn call(
        &self,
        cx: &mut ServerContext,
        req: ServerRequest,
    ) -> Result<Self::Response, Self::Error> {
        println!("-----test call-----");
        Ok(self.inner.call(cx, req).await.into_response())
    }
}

http 服务启动(正常)

use volo_http::{Router, Server as HttpServer}

let http_app = Router::new().route("xxx", get(xx)).route("xxx", get(xx)).layer(TestLayer::new()).layer(DemoLayer::new());
let addr: SocketAddr = "0.0.0.0:8080".parse().unwrap();
let addr = volo::net::Address::from(addr);
HttpServer::new(app).run(addr).await.unwrap();

grpc 服务启动(问题,中间件不通用)

use volo_grpc::server::Server as GrpcServer;

let addr: SocketAddr = "[::]:8080".parse().unwrap();
let addr = volo::net::Address::from(addr);
GrpcServer::new().add_service(s).layer(TestLayer::new()).layer(DemoLayer::new()).run(addr).await.unwrap();
PureWhiteWu commented 1 month ago

抱歉回复有一些晚。

Service 中间件是否通用主要看的是你是否对 Cx 及 Req 有明确的要求或者指定。

比如,如果你一定需要从 Cx 中获取一些 HTTP 的信息,那么你就需要指定 Cx 为 Volo-HTTP 的 Context 了,这种情况下中间件就不能复用了。

但是如果你直接使用 Volo 的 Context 就能满足需求,那么就是可以通用的,Volo-HTTP 和 Volo-gRPC 的 Context 都是基于 Volo 的 Context 扩展得到的。

Millione commented 1 month ago

问题2: 两个不同类型是不能放到一个Vec里的,如果你一定要放在一个Vec里,需要加一层Box擦除具体类型