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::{Client, DEFAULT_HOST, HDR_X_MODIO_PLATFORM, HDR_X_MODIO_PORTAL, TEST_HOST};
9
10use super::service::Svc;
11
12pub struct Builder {
14 host: Option<Box<str>>,
15 api_key: Box<str>,
16 token: Option<Box<str>>,
17 headers: HeaderMap,
18 error: Option<Error>,
19}
20
21impl Builder {
22 pub fn new(api_key: String) -> Self {
24 Self {
25 host: None,
26 api_key: api_key.into_boxed_str(),
27 token: None,
28 headers: HeaderMap::new(),
29 error: None,
30 }
31 }
32
33 pub fn build(self) -> Result<Client, Error> {
35 if let Some(e) = self.error {
36 return Err(e);
37 }
38
39 let http = Svc::new();
40
41 let host = self.host.unwrap_or_else(|| Box::from(DEFAULT_HOST));
42
43 Ok(Client {
44 http,
45 host,
46 api_key: self.api_key,
47 token: self.token,
48 headers: self.headers,
49 })
50 }
51
52 pub fn token(mut self, token: String) -> Self {
54 self.token = Some(create_token(token));
55 self
56 }
57
58 pub fn use_default_env(mut self) -> Self {
60 self.host = Some(Box::from(DEFAULT_HOST));
61 self
62 }
63
64 pub fn use_test_env(mut self) -> Self {
66 self.host = Some(Box::from(TEST_HOST));
67 self
68 }
69
70 pub fn game_host(mut self, game_id: GameId) -> Self {
72 self.host = Some(format!("g-{game_id}.modapi.io").into_boxed_str());
73 self
74 }
75
76 pub fn user_host(mut self, user_id: UserId) -> Self {
78 self.host = Some(format!("u-{user_id}.modapi.io").into_boxed_str());
79 self
80 }
81
82 pub fn host<V>(mut self, host: V) -> Self
86 where
87 V: TryInto<Authority>,
88 V::Error: Into<http::Error>,
89 {
90 match host.try_into() {
91 Ok(host) => {
92 self.host = Some(Box::from(host.as_str()));
93 }
94 Err(err) => {
95 self.error = Some(error::builder(err.into()));
96 }
97 }
98 self
99 }
100
101 pub fn user_agent<V>(mut self, value: V) -> Self
103 where
104 V: TryInto<HeaderValue>,
105 V::Error: Into<http::Error>,
106 {
107 match value.try_into() {
108 Ok(value) => {
109 self.headers.insert(USER_AGENT, value);
110 }
111 Err(err) => {
112 self.error = Some(error::builder(err.into()));
113 }
114 }
115 self
116 }
117
118 pub fn target_platform(mut self, platform: TargetPlatform) -> Self {
122 match HeaderValue::from_str(platform.as_str()) {
123 Ok(value) => {
124 self.headers.insert(HDR_X_MODIO_PLATFORM, value);
125 }
126 Err(err) => {
127 self.error = Some(error::builder(err));
128 }
129 }
130 self
131 }
132
133 pub fn target_portal(mut self, portal: TargetPortal) -> Self {
137 match HeaderValue::from_str(portal.as_str()) {
138 Ok(value) => {
139 self.headers.insert(HDR_X_MODIO_PORTAL, value);
140 }
141 Err(err) => {
142 self.error = Some(error::builder(err));
143 }
144 }
145 self
146 }
147}
148
149pub(super) fn create_token(mut token: String) -> Box<str> {
150 if !token.starts_with("Bearer ") {
151 token.insert_str(0, "Bearer ");
152 }
153 token.into_boxed_str()
154}
155
156#[cfg(test)]
157mod tests {
158 use super::create_token;
159
160 #[test]
161 fn test_create_token() {
162 assert_eq!("Bearer token", &*create_token("token".to_owned()));
163 assert_eq!("Bearer token", &*create_token("Bearer token".to_owned()));
164 }
165}