cratestack_axum/ratelimit/
service.rs1use std::sync::Arc;
9use std::time::Duration;
10
11use axum::extract::Request;
12use axum::response::Response;
13use cratestack_exec::OpExecutor;
14use tower::Service;
15
16use super::budget::warn::BudgetWarnings;
17use super::config::RateLimitConfig;
18use super::layer::{KeyFn, OpResolver};
19use super::policy::{StoreErrorPolicy, StoreErrorWarnings};
20
21#[derive(Clone)]
22pub struct RateLimitService<S> {
23 pub(super) inner: S,
24 pub(super) executor: OpExecutor,
27 pub(super) config: RateLimitConfig,
29 pub(super) key_fn: KeyFn,
30 pub(super) op_resolver: OpResolver,
31 pub(super) store_error_policy: StoreErrorPolicy,
32 pub(super) store_timeout: Duration,
33 pub(super) warnings: Arc<StoreErrorWarnings>,
34 pub(super) budget_warnings: Arc<BudgetWarnings>,
35}
36
37impl<S> Service<Request> for RateLimitService<S>
38where
39 S: Service<Request, Response = Response, Error = std::convert::Infallible>
40 + Clone
41 + Send
42 + 'static,
43 S::Future: Send + 'static,
44{
45 type Response = Response;
46 type Error = std::convert::Infallible;
47 type Future =
48 std::pin::Pin<Box<dyn std::future::Future<Output = Result<Response, Self::Error>> + Send>>;
49
50 fn poll_ready(
51 &mut self,
52 cx: &mut std::task::Context<'_>,
53 ) -> std::task::Poll<Result<(), Self::Error>> {
54 self.inner.poll_ready(cx)
55 }
56
57 fn call(&mut self, req: Request) -> Self::Future {
58 let op = (self.op_resolver)(&req);
59 let should_rate_limit = self.executor.rate_limit_applies(&op);
60 let mut service = self.clone();
64 Box::pin(async move {
65 if !should_rate_limit {
71 return service.inner.call(req).await;
72 }
73 Ok(super::consume::run(service, req, op).await)
74 })
75 }
76}