xapi_binance/common/
ratelimiter.rs1use crate::data::enums::ratelimit::{BnRateLimit, BnRateLimitInterval, BnRateLimitType};
2use governor::{DefaultDirectRateLimiter, InsufficientCapacity, Quota};
3use std::{collections::HashMap, num::NonZero, time::Duration};
4use xapi_shared::ratelimiter::SharedRatelimiterTrait;
5
6pub struct BnRatelimiter {
7 limiters: HashMap<BnRateLimitType, Vec<DefaultDirectRateLimiter>>,
8}
9
10#[async_trait::async_trait]
11impl SharedRatelimiterTrait<BnRateLimitType> for BnRatelimiter {
12 async fn limit_on(
13 &self,
14 key: &BnRateLimitType,
15 value: NonZero<u32>,
16 ) -> Result<(), InsufficientCapacity> {
17 if let Some(limiters) = self.limiters.get(key) {
18 for limiter in limiters {
19 limiter
20 .until_n_ready(value)
21 .await
22 .inspect_err(|err| tracing::error!("bn rate limiter error: {err}"))?
23 }
24 }
25
26 Ok(())
27 }
28}
29
30impl Default for BnRatelimiter {
31 fn default() -> Self {
32 let limits = vec![
33 BnRateLimit {
34 rate_limit_type: BnRateLimitType::RequestWeight,
35 interval: BnRateLimitInterval::Minute,
36 interval_num: 1,
37 limit: 6000,
38 },
39 BnRateLimit {
40 rate_limit_type: BnRateLimitType::Orders,
41 interval: BnRateLimitInterval::Second,
42 interval_num: 10,
43 limit: 100,
44 },
45 BnRateLimit {
46 rate_limit_type: BnRateLimitType::Orders,
47 interval: BnRateLimitInterval::Day,
48 interval_num: 1,
49 limit: 200_000,
50 },
51 BnRateLimit {
52 rate_limit_type: BnRateLimitType::RawRequests,
53 interval: BnRateLimitInterval::Minute,
54 interval_num: 5,
55 limit: 61_000,
56 },
57 ];
58
59 Self::new(&limits)
60 }
61}
62
63impl BnRatelimiter {
64 pub fn new(rules: &Vec<BnRateLimit>) -> Self {
65 let mut limiters = HashMap::new();
66
67 for rule in rules {
68 if rule.limit == 0 {
69 tracing::warn!("skipping rate limit rule with non-positive limit: {rule:?}");
70 continue;
71 }
72
73 let limit = NonZero::new(rule.limit).unwrap();
74
75 let quota = match rule.interval {
76 BnRateLimitInterval::Second => Quota::per_second(limit),
77 BnRateLimitInterval::Minute => Quota::per_minute(limit),
78 BnRateLimitInterval::Day => Quota::with_period(Duration::from_secs(60 * 60 * 24))
79 .unwrap()
80 .allow_burst(limit),
81 };
82
83 let limiter = DefaultDirectRateLimiter::direct(quota);
84
85 limiters
86 .entry(rule.rate_limit_type)
87 .or_insert_with(Vec::new)
88 .push(limiter);
89 }
90
91 Self { limiters }
92 }
93}