oauth2_broker/ext/
rate_limit.rs1use crate::{
6 _prelude::*,
7 auth::{ProviderId, ScopeSet, TenantId},
8};
9
10pub type RateLimitFuture<'a, Error> =
12 Pin<Box<dyn Future<Output = Result<RateLimitDecision, Error>> + 'a + Send>>;
13
14pub trait RateLimitPolicy<Error>
16where
17 Self: Send + Sync,
18{
19 fn evaluate(&self, context: &RateLimitContext) -> RateLimitFuture<'_, Error>;
21}
22
23#[derive(Clone, Debug)]
25pub struct RateLimitContext {
26 pub tenant_id: TenantId,
28 pub provider_id: ProviderId,
30 pub scope: ScopeSet,
32 pub operation: String,
34 pub observed_at: OffsetDateTime,
36}
37impl RateLimitContext {
38 pub fn new(
40 tenant_id: TenantId,
41 provider_id: ProviderId,
42 scope: ScopeSet,
43 operation: impl Into<String>,
44 ) -> Self {
45 Self {
46 tenant_id,
47 provider_id,
48 scope,
49 operation: operation.into(),
50 observed_at: OffsetDateTime::now_utc(),
51 }
52 }
53
54 pub fn with_observed_at(mut self, instant: OffsetDateTime) -> Self {
56 self.observed_at = instant;
57
58 self
59 }
60}
61
62#[derive(Clone, Debug, PartialEq, Eq)]
64pub enum RateLimitDecision {
65 Allow,
67 Delay(RetryDirective),
69}
70
71#[derive(Clone, Debug, PartialEq, Eq)]
73pub struct RetryDirective {
74 pub earliest_retry_at: OffsetDateTime,
76 pub recommended_backoff: Duration,
78 pub reason: Option<String>,
80}
81impl RetryDirective {
82 pub fn new(earliest_retry_at: OffsetDateTime, recommended_backoff: Duration) -> Self {
84 Self { earliest_retry_at, recommended_backoff, reason: None }
85 }
86
87 pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
89 self.reason = Some(reason.into());
90
91 self
92 }
93}