1use std::collections::HashMap;
2
3use reqwest::header::HeaderMap;
4
5use crate::http_client::Method;
6
7#[derive(Debug, Clone)]
9pub struct RateLimit {
10 pub limit: i32,
12 pub period: Period,
14 pub remaining: i32,
16 pub reset: u128,
18}
19
20impl RateLimit {
21 pub fn new(limit: i32, period: Period, remaining: i32, reset: u128) -> Self {
23 Self {
24 limit,
25 period,
26 remaining,
27 reset,
28 }
29 }
30
31 pub fn default(limit: i32, period: Period) -> Self {
33 Self::new(limit, period, limit, 0)
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum Period {
39 Minute,
40 Hour,
41 Day,
42}
43
44pub struct RateLimits {
46 pub global_limit: RateLimit,
48 pub get_limits: HashMap<String, RateLimit>,
50 pub post_limits: HashMap<String, RateLimit>,
52}
53
54impl RateLimits {
55 pub fn get_limit(&self, method: &Method, path: &str) -> RateLimit {
60 match method {
61 Method::Get => self.get_limits.get(path).cloned().unwrap_or(self.global_limit.clone()),
62 Method::Post => self.post_limits.get(path).cloned().unwrap_or(self.global_limit.clone()),
63 }
64 }
65
66 pub fn get_limit_mut(&mut self, method: &Method, path: &str) -> &mut RateLimit {
71 match method {
72 Method::Get => self
73 .get_limits
74 .get_mut(path)
75 .unwrap_or(&mut self.global_limit),
76 Method::Post => self
77 .post_limits
78 .get_mut(path)
79 .unwrap_or(&mut self.global_limit),
80 }
81 }
82
83 pub fn update_limit(&mut self, method: &Method, path: &str, rate_limit: RateLimit) {
89 let now_rate_limit = self.get_limit_mut(method, path);
90 *now_rate_limit = rate_limit;
91 }
92
93 pub fn update_from_headers(&mut self, method: &Method, path: &str, headers: &HeaderMap) {
95 let limit = headers
96 .get("x-ratelimit-limit")
97 .and_then(|s| s.to_str().unwrap_or("0").parse::<i32>().ok())
98 .unwrap_or(0);
99 if limit <= 0 {
100 return;
101 }
102 let remaining = headers
103 .get("x-ratelimit-remaining")
104 .and_then(|s| s.to_str().unwrap_or("0").parse::<i32>().ok())
105 .unwrap_or(0);
106 let reset = headers
107 .get("x-ratelimit-reset")
108 .and_then(|s| s.to_str().unwrap_or("0").parse::<u128>().ok())
109 .unwrap_or(0);
110 let rate_limit = self.get_limit_mut(method, path);
111 rate_limit.limit = limit;
112 rate_limit.remaining = remaining;
113 rate_limit.reset = reset;
114 }
115}
116
117impl Default for RateLimits {
118 fn default() -> Self {
119 let global_limit = RateLimit::default(120, Period::Minute);
120 let mut get_limits = HashMap::new();
121 let mut post_limits = HashMap::new();
122
123 get_limits.insert(
125 "/game/room-terrain".to_string(),
126 RateLimit::default(360, Period::Hour),
127 );
128 get_limits.insert(
129 "/user/code".to_string(),
130 RateLimit::default(60, Period::Hour),
131 );
132 get_limits.insert(
133 "/user/memory".to_string(),
134 RateLimit::default(1440, Period::Day),
135 );
136 get_limits.insert(
137 "/user/memory-segment".to_string(),
138 RateLimit::default(360, Period::Hour),
139 );
140 get_limits.insert(
141 "/game/market/orders-index".to_string(),
142 RateLimit::default(60, Period::Hour),
143 );
144 get_limits.insert(
145 "/game/market/orders".to_string(),
146 RateLimit::default(60, Period::Hour),
147 );
148 get_limits.insert(
149 "/game/market/my-orders".to_string(),
150 RateLimit::default(60, Period::Hour),
151 );
152 get_limits.insert(
153 "/game/market/stats".to_string(),
154 RateLimit::default(60, Period::Hour),
155 );
156 get_limits.insert(
157 "/game/user/money-history".to_string(),
158 RateLimit::default(60, Period::Hour),
159 );
160
161 post_limits.insert(
163 "/user/console".to_string(),
164 RateLimit::default(360, Period::Hour),
165 );
166 post_limits.insert(
167 "/game/map-stats".to_string(),
168 RateLimit::default(60, Period::Hour),
169 );
170 post_limits.insert(
171 "/user/code".to_string(),
172 RateLimit::default(240, Period::Day),
173 );
174 post_limits.insert(
175 "/user/set-active-branch".to_string(),
176 RateLimit::default(240, Period::Day),
177 );
178 post_limits.insert(
179 "/user/memory".to_string(),
180 RateLimit::default(240, Period::Day),
181 );
182 post_limits.insert(
183 "/user/memory-segment".to_string(),
184 RateLimit::default(60, Period::Hour),
185 );
186
187 Self {
188 global_limit,
189 get_limits,
190 post_limits,
191 }
192 }
193}