1use http::header::{HeaderMap, HeaderValue, USER_AGENT};
2use http::uri::Authority;
3
4use crate::error::{self, Error};
5use crate::types::id::{GameId, UserId};
6use crate::types::{TargetPlatform, TargetPortal};
7
8use super::host::Host;
9use super::{Client, HDR_X_MODIO_PLATFORM, HDR_X_MODIO_PORTAL};
10
11use super::service::Svc;
12
13pub struct Builder {
15 host: Option<Host>,
16 api_key: Box<str>,
17 token: Option<Box<str>>,
18 headers: HeaderMap,
19 error: Option<Error>,
20}
21
22impl Builder {
23 pub fn new(api_key: String) -> Self {
25 Self {
26 host: None,
27 api_key: api_key.into_boxed_str(),
28 token: None,
29 headers: HeaderMap::new(),
30 error: None,
31 }
32 }
33
34 pub fn build(self) -> Result<Client, Error> {
36 if let Some(e) = self.error {
37 return Err(e);
38 }
39
40 let http = Svc::new();
41
42 let host = self.host.unwrap_or_default();
43
44 Ok(Client {
45 http,
46 host,
47 api_key: self.api_key,
48 token: self.token,
49 headers: self.headers,
50 })
51 }
52
53 pub fn token(mut self, token: String) -> Self {
55 self.token = Some(create_token(token));
56 self
57 }
58
59 pub fn use_default_env(mut self) -> Self {
61 self.host = Some(Host::Default);
62 self
63 }
64
65 pub fn use_test_env(mut self) -> Self {
67 self.host = Some(Host::Test);
68 self
69 }
70
71 pub fn game_host(mut self, game_id: GameId) -> Self {
73 self.host = Some(Host::Game(game_id));
74 self
75 }
76
77 pub fn user_host(mut self, user_id: UserId) -> Self {
79 self.host = Some(Host::User(user_id));
80 self
81 }
82
83 pub fn dynamic_game_host(mut self) -> Self {
86 self.host = Some(Host::Dynamic);
87 self
88 }
89
90 pub fn dynamic_game_host_with_custom<V>(mut self, host: V) -> Self
93 where
94 V: TryInto<Authority>,
95 V::Error: Into<http::Error>,
96 {
97 match host.try_into() {
98 Ok(host) => {
99 self.host = Some(Host::DynamicWithCustom(host));
100 }
101 Err(err) => {
102 self.error = Some(error::builder(err.into()));
103 }
104 }
105 self
106 }
107
108 pub fn host<V>(mut self, host: V) -> Self
112 where
113 V: TryInto<Authority>,
114 V::Error: Into<http::Error>,
115 {
116 match host.try_into() {
117 Ok(host) => {
118 self.host = Some(Host::Custom(host));
119 }
120 Err(err) => {
121 self.error = Some(error::builder(err.into()));
122 }
123 }
124 self
125 }
126
127 pub fn user_agent<V>(mut self, value: V) -> Self
129 where
130 V: TryInto<HeaderValue>,
131 V::Error: Into<http::Error>,
132 {
133 match value.try_into() {
134 Ok(value) => {
135 self.headers.insert(USER_AGENT, value);
136 }
137 Err(err) => {
138 self.error = Some(error::builder(err.into()));
139 }
140 }
141 self
142 }
143
144 pub fn target_platform(mut self, platform: TargetPlatform) -> Self {
148 match HeaderValue::from_str(platform.as_str()) {
149 Ok(value) => {
150 self.headers.insert(HDR_X_MODIO_PLATFORM, value);
151 }
152 Err(err) => {
153 self.error = Some(error::builder(err));
154 }
155 }
156 self
157 }
158
159 pub fn target_portal(mut self, portal: TargetPortal) -> Self {
163 match HeaderValue::from_str(portal.as_str()) {
164 Ok(value) => {
165 self.headers.insert(HDR_X_MODIO_PORTAL, value);
166 }
167 Err(err) => {
168 self.error = Some(error::builder(err));
169 }
170 }
171 self
172 }
173}
174
175pub(super) fn create_token(mut token: String) -> Box<str> {
176 if !token.starts_with("Bearer ") {
177 token.insert_str(0, "Bearer ");
178 }
179 token.into_boxed_str()
180}
181
182#[cfg(test)]
183mod tests {
184 use super::create_token;
185
186 #[test]
187 fn test_create_token() {
188 assert_eq!("Bearer token", &*create_token("token".to_owned()));
189 assert_eq!("Bearer token", &*create_token("Bearer token".to_owned()));
190 }
191}