twilight_http/client/
builder.rs1use super::Token;
2use crate::{client::connector, Client};
3use http::header::HeaderMap;
4use hyper_util::rt::TokioExecutor;
5use std::{
6 sync::{atomic::AtomicBool, Arc},
7 time::Duration,
8};
9use twilight_http_ratelimiting::{InMemoryRatelimiter, Ratelimiter};
10use twilight_model::channel::message::AllowedMentions;
11
12#[derive(Debug)]
14#[must_use = "has no effect if not built into a Client"]
15pub struct ClientBuilder {
16 pub(crate) default_allowed_mentions: Option<AllowedMentions>,
17 pub(crate) proxy: Option<Box<str>>,
18 pub(crate) ratelimiter: Option<Box<dyn Ratelimiter>>,
19 remember_invalid_token: bool,
20 pub(crate) default_headers: Option<HeaderMap>,
21 pub(crate) timeout: Duration,
22 pub(super) token: Option<Token>,
23 pub(crate) use_http: bool,
24}
25
26impl ClientBuilder {
27 pub fn new() -> Self {
29 Self::default()
30 }
31
32 pub fn build(self) -> Client {
34 let connector = connector::create();
35
36 let http =
37 hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);
38
39 let token_invalidated = if self.remember_invalid_token {
40 Some(Arc::new(AtomicBool::new(false)))
41 } else {
42 None
43 };
44
45 Client {
46 http,
47 default_headers: self.default_headers,
48 proxy: self.proxy,
49 ratelimiter: self.ratelimiter,
50 timeout: self.timeout,
51 token_invalidated,
52 token: self.token,
53 default_allowed_mentions: self.default_allowed_mentions,
54 use_http: self.use_http,
55 }
56 }
57
58 pub fn default_allowed_mentions(mut self, allowed_mentions: AllowedMentions) -> Self {
61 self.default_allowed_mentions.replace(allowed_mentions);
62
63 self
64 }
65
66 pub fn proxy(mut self, proxy_url: String, use_http: bool) -> Self {
87 self.proxy.replace(proxy_url.into_boxed_str());
88 self.use_http = use_http;
89
90 self
91 }
92
93 #[allow(clippy::missing_const_for_fn)]
101 pub fn ratelimiter(mut self, ratelimiter: Option<Box<dyn Ratelimiter>>) -> Self {
102 self.ratelimiter = ratelimiter;
103
104 self
105 }
106
107 pub const fn timeout(mut self, duration: Duration) -> Self {
111 self.timeout = duration;
112
113 self
114 }
115
116 pub fn default_headers(mut self, headers: HeaderMap) -> Self {
118 self.default_headers.replace(headers);
119
120 self
121 }
122
123 pub const fn remember_invalid_token(mut self, remember: bool) -> Self {
131 self.remember_invalid_token = remember;
132
133 self
134 }
135
136 pub fn token(mut self, mut token: String) -> Self {
138 let is_bot = token.starts_with("Bot ");
139 let is_bearer = token.starts_with("Bearer ");
140
141 if !is_bot && !is_bearer {
144 token.insert_str(0, "Bot ");
145 }
146
147 self.token.replace(Token::new(token.into_boxed_str()));
148
149 self
150 }
151}
152
153impl Default for ClientBuilder {
154 fn default() -> Self {
155 #[allow(clippy::box_default)]
156 Self {
157 default_allowed_mentions: None,
158 default_headers: None,
159 proxy: None,
160 ratelimiter: Some(Box::new(InMemoryRatelimiter::default())),
161 remember_invalid_token: true,
162 timeout: Duration::from_secs(10),
163 token: None,
164 use_http: false,
165 }
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::ClientBuilder;
172 use static_assertions::assert_impl_all;
173 use std::fmt::Debug;
174
175 assert_impl_all!(ClientBuilder: Debug, Default, Send, Sync);
176
177 #[test]
178 fn client_debug() {
179 assert!(
180 format!("{:?}", ClientBuilder::new().token("Bot foo".to_owned()))
181 .contains("token: Some(<redacted>)")
182 );
183 assert!(format!("{:?}", ClientBuilder::new()).contains("token: None"));
184 }
185}