benwis / tower-governor

Rate Limiting middleware for Tower/Axum/Tonic/Hyper utilizing the governor crate
MIT License
174 stars 29 forks source link

Any plans to support jsonrpsee? #33

Open jakerumbles opened 4 months ago

jakerumbles commented 4 months ago

I've been trying to use this as tower middleware in a jsonrpsee server, and it works fine until I get to server.start() where the GovernorLayer has missing trait implementations. I thought it should work as it's supposed to be tower compatible, but maybe there is some specific jsonrpsee part of the equation here. For reference, I'm able to get the out-of-the-box Tower .rate_limit(3, Duration::from_secs(60)) middleware layer working just fine, but as soon as I try to use GovernorLayer instead it breaks due to missing trait implementations.

My code:

use anyhow::Result;
// use jsonrpsee::server::stop_channel;
use jsonrpsee::server::RpcModule;
// use jsonrpsee::server::RpcServiceBuilder;
use jsonrpsee::server::ServerHandle;
// use jsonrpsee::server::TowerService;
// use jsonrpsee::server::TowerServiceBuilder;
use jsonrpsee::server::{Server, ServerBuilder};
// use rate_limiting::{Rate, RateLimit};
use std::sync::Arc;
use std::time::Duration;
use tower::ServiceBuilder;
use tower_governor::{governor::GovernorConfigBuilder, GovernorLayer};

    pub async fn start(&self) -> Result<RpcServerHandle> {
        // Allow bursts with up to five requests per IP address
        // and replenishes one element every two seconds
        // We Box it because Axum 0.6 requires all Layers to be Clone
        // and thus we need a static reference to it
        let governor_conf = Arc::new(
            GovernorConfigBuilder::default()
                .per_second(2)
                .burst_size(5)
                .finish()
                .unwrap(),
        );

        let governor_limiter = governor_conf.limiter().clone();
        let interval = Duration::from_secs(60);
        // a separate background task to clean up
        std::thread::spawn(move || loop {
            std::thread::sleep(interval);
            tracing::info!("rate limiting storage size: {}", governor_limiter.len());
            governor_limiter.retain_recent();
        });

        // Add rate limiter middleware
        // let rpc_middleware = RpcServiceBuilder::new().layer_fn(
        //     |service: jsonrpsee::server::middleware::rpc::RpcService| {
        //         tracing::info!("MIDDLEWARE: RATE LIMITING");
        //         RateLimit::new(
        //             service,
        //             Rate {
        //                 num: 1,
        //                 period: Duration::from_secs(15),
        //             },
        //         )
        //     },
        // );

        let http_middleware = ServiceBuilder::new()
            // .rate_limit(3, Duration::from_secs(60));
            .layer(GovernorLayer {
                config: governor_conf,
            });

        // let (stop_handle, handle) = stop_channel();

        // let new_server = ServerBuilder::new()
        //     .set_http_middleware(http_middleware)
        //     // .to_service_builder()
        //     // .build(self.rpc_module.clone(), stop_handle);
        //     .build(self.settings.http_listen_addr())
        //     .await?;

        let server = Server::builder()
            // .set_rpc_middleware(middleware)
            .set_http_middleware(http_middleware)
            .build(self.settings.http_listen_addr())
            .await?;

        let addr = server.local_addr()?;
        tracing::info!("RPC server started at: {}", addr);

        let handle = server.start(self.rpc_module.clone());

        Ok(RpcServerHandle {
            listen_addr: addr,
            handle,
        })
    }

Here's the error on server.start()

the method `start` exists for struct `Server<Stack<GovernorLayer<PeerIpKeyExtractor, NoOpMiddleware<QuantaInstant>>, Identity>>`, but its trait bounds were not satisfied
the full type name has been written to '/Users/jake-dev/Github/drosera/crates/target/debug/deps/drosera_services-cbadea97acc5bca2.long-type-5025332530578171701.txt'
consider using `--verbose` to print the full type name to the console
the following trait bounds were not satisfied:
`<Governor<PeerIpKeyExtractor, governor::middleware::NoOpMiddleware<governor::clock::quanta::QuantaInstant>, jsonrpsee::jsonrpsee_server::server::TowerServiceNoHttp<tower::layer::util::Identity>> as Service<tonic::codegen::http::request::Request<tonic::transport::Body>>>::Response = tonic::codegen::http::response::Response<_>`
`<Governor<PeerIpKeyExtractor, governor::middleware::NoOpMiddleware<governor::clock::quanta::QuantaInstant>, jsonrpsee::jsonrpsee_server::server::TowerServiceNoHttp<tower::layer::util::Identity>> as Service<tonic::codegen::http::request::Request<tonic::transport::Body>>>::Error = std::boxed::Box<(dyn StdError + std::marker::Send + std::marker::Sync + 'static)>`
`Governor<PeerIpKeyExtractor, governor::middleware::NoOpMiddleware<governor::clock::quanta::QuantaInstant>, jsonrpsee::jsonrpsee_server::server::TowerServiceNoHttp<tower::layer::util::Identity>>: Service<tonic::codegen::http::request::Request<tonic::transport::Body>>`rustc[Click for full compiler diagnostic](rust-analyzer-diagnostics-view:/diagnostic%20message%20%5B2%5D?2#file%3A%2F%2F%2FUsers%2Fjake-dev%2FGithub%2Fdrosera%2Fcrates%2Fservices%2Fsrc%2Fnetwork%2Frpc%2Fmod.rs)
governor.rs(324, 1): doesn't satisfy `<_ as Service<Request<Body>>>::Error = Box<dyn Error + Send + Sync>`, `<_ as Service<Request<Body>>>::Response = Response<_>` or `_: Service<Request<Body>>`
benwis commented 5 days ago

Since I mostly am only doing maintenance on this, I'd say no, but your'e welcome to take a look and see if any changes can be made to support this!