rosu_render/client/builder.rs
1use std::sync::Arc;
2
3use hyper_util::rt::TokioExecutor;
4
5use crate::{client::connector, model::Verification};
6
7use super::{ratelimiter::Ratelimiter, OrdrClient, OrdrRef};
8
9/// A builder for [`OrdrClient`].
10#[derive(Default)]
11#[must_use]
12pub struct OrdrClientBuilder {
13 verification: Option<Verification>,
14 ratelimit: Option<RatelimitBuilder>,
15}
16
17impl OrdrClientBuilder {
18 /// Create a new builder to create a [`OrdrClient`].
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 //// Build an [`OrdrClient`].
24 #[must_use]
25 pub fn build(self) -> OrdrClient {
26 let connector = connector::create();
27 let http =
28 hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);
29
30 let ratelimit = match (self.verification.as_ref(), self.ratelimit) {
31 (None, None) => RatelimitBuilder::new(300_000, 1, 1), // One per 5 minutes
32 (None, Some(ratelimit)) => {
33 let ms_per_gain = ratelimit.interval / ratelimit.refill;
34
35 if ms_per_gain < 300_000 {
36 RatelimitBuilder::new(300_000, 1, 1)
37 } else {
38 RatelimitBuilder {
39 max: ratelimit.max.min(2),
40 ..ratelimit
41 }
42 }
43 }
44 (Some(Verification::Key(_)), None) => RatelimitBuilder::new(10_000, 1, 1), // One per 10 seconds
45 (
46 Some(
47 Verification::DevModeSuccess
48 | Verification::DevModeFail
49 | Verification::DevModeWsFail,
50 ),
51 None,
52 ) => RatelimitBuilder::new(1000, 1, 1), // One per second
53 (Some(_), Some(ratelimit)) => ratelimit,
54 };
55
56 OrdrClient {
57 inner: Arc::new(OrdrRef {
58 http,
59 ratelimiter: Ratelimiter::new(&ratelimit),
60 verification: self.verification,
61 }),
62 }
63 }
64
65 /// Specify a [`Verification`]
66 ///
67 /// Refer to its documentation for more information.
68 pub fn verification(self, verification: Verification) -> Self {
69 Self {
70 verification: Some(verification),
71 ..self
72 }
73 }
74
75 /// Specify a ratelimit that the client will uphold for the render endpoint.
76 /// Other endpoints won't be affected, they have a pre-set ratelimit.
77 ///
78 /// - `interval_ms`: How many milliseconds until the next refill
79 /// - `refill`: How many allowances are added per refill
80 /// - `max`: What's the maximum amount of available allowances
81 ///
82 /// If no [`Verification`] is specified, the ratelimit will be clamped up to one
83 /// per 5 minutes as per o!rdr rules.
84 /// If a dev mode [`Verification`] is specified, the ratelimit defaults to one per second.
85 /// If a verification key is specified, the ratelimit defaults to one per 10 seconds.
86 ///
87 /// # Panics
88 ///
89 /// Panics if `interval_ms` or `refill` are zero.
90 ///
91 /// # Example
92 /// ```
93 /// use rosu_render::OrdrClient;
94 ///
95 /// // Applying a ratelimit of 1 refill every 5 seconds, up to 2 charges
96 /// // which means 2 requests per 10 seconds.
97 /// let client = OrdrClient::builder()
98 /// .render_ratelimit(5000, 1, 2)
99 /// .build();
100 /// ```
101 pub fn render_ratelimit(self, interval_ms: u64, refill: u64, max: u64) -> Self {
102 Self {
103 ratelimit: Some(RatelimitBuilder::new(interval_ms, refill, max)),
104 ..self
105 }
106 }
107}
108
109pub(super) struct RatelimitBuilder {
110 pub interval: u64,
111 pub refill: u64,
112 pub max: u64,
113}
114
115impl RatelimitBuilder {
116 fn new(interval: u64, refill: u64, max: u64) -> Self {
117 Self {
118 interval,
119 refill,
120 max,
121 }
122 }
123}