mangadex_api/v5/at_home/server/id/
get.rs1use derive_builder::Builder;
32use serde::Serialize;
33use uuid::Uuid;
34
35use crate::HttpClientRef;
36use mangadex_api_schema::v5::AtHomeServer;
37
38#[cfg_attr(
39 feature = "deserializable-endpoint",
40 derive(serde::Deserialize, getset::Getters, getset::Setters)
41)]
42#[derive(Debug, Serialize, Clone, Builder)]
43#[serde(rename_all = "camelCase")]
44#[builder(
45 setter(into, strip_option),
46 build_fn(error = "mangadex_api_types::error::BuilderError")
47)]
48pub struct GetAtHomeServer {
49 #[doc(hidden)]
51 #[serde(skip)]
52 #[builder(pattern = "immutable")]
53 #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
54 pub http_client: HttpClientRef,
55
56 #[serde(skip_serializing)]
57 pub chapter_id: Uuid,
58
59 #[builder(default)]
67 pub force_port_443: bool,
68}
69
70endpoint! {
71 GET ("/at-home/server/{}", chapter_id),
72 #[query] GetAtHomeServer,
73 #[rate_limited] AtHomeServer,
74 GetAtHomeServerBuilder
75}
76
77#[cfg(test)]
78mod tests {
79 use fake::faker::internet::en::Password;
80 use fake::Fake;
81 use mangadex_api_types::error::Error;
82 use serde_json::json;
83 use url::Url;
84 use uuid::Uuid;
85 use wiremock::matchers::{method, path_regex};
86 use wiremock::{Mock, MockServer, ResponseTemplate};
87
88 use crate::{HttpClient, MangaDexClient};
89
90 #[tokio::test]
91 async fn activate_fires_a_request_to_base_url() -> anyhow::Result<()> {
92 let mock_server = MockServer::start().await;
93 let http_client = HttpClient::builder()
94 .base_url(Url::parse(&mock_server.uri())?)
95 .build()?;
96 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
97
98 let chapter_id = Uuid::new_v4();
99 let hash: String = Password(16..24).fake();
100
101 let response_body = json!({
102 "result": "ok",
103 "baseUrl": "https://example.org",
104 "chapter": {
105 "hash": hash,
106 "data": [
107 "1.jpg"
108 ],
109 "dataSaver": [
110 "1.jpg"
111 ],
112 }
113 });
114
115 Mock::given(method("GET"))
116 .and(path_regex(r"/at-home/server/[0-9a-fA-F-]+"))
117 .respond_with(
118 ResponseTemplate::new(200)
119 .insert_header("x-ratelimit-retry-after", "1698723860")
120 .insert_header("x-ratelimit-limit", "40")
121 .insert_header("x-ratelimit-remaining", "39")
122 .set_body_json(response_body),
123 )
124 .expect(1)
125 .mount(&mock_server)
126 .await;
127
128 let resp = mangadex_client
129 .at_home()
130 .server()
131 .id(chapter_id)
132 .get()
133 .force_port_443(true)
134 .build()?
135 .send()
136 .await?;
137
138 let rate_limit = resp.rate_limit;
139
140 assert_eq!(rate_limit.limit, 40);
141 assert_eq!(rate_limit.remaining, 39);
142 println!("{}", rate_limit.retry_after);
143
144 let res = resp.body;
145
146 assert_eq!(res.base_url, Url::parse("https://example.org")?);
147 assert_eq!(res.chapter.hash, hash);
148 assert_eq!(res.chapter.data, vec!["1.jpg"]);
149 assert_eq!(res.chapter.data_saver, vec!["1.jpg"]);
150
151 Ok(())
152 }
153
154 #[tokio::test]
155 async fn handle_missing_header() -> anyhow::Result<()> {
156 let mock_server = MockServer::start().await;
157 let http_client = HttpClient::builder()
158 .base_url(Url::parse(&mock_server.uri())?)
159 .build()?;
160 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
161
162 let chapter_id = Uuid::new_v4();
163 let hash: String = Password(16..24).fake();
164
165 let response_body = json!({
166 "result": "ok",
167 "baseUrl": "https://example.org",
168 "chapter": {
169 "hash": hash,
170 "data": [
171 "1.jpg"
172 ],
173 "dataSaver": [
174 "1.jpg"
175 ],
176 }
177 });
178
179 Mock::given(method("GET"))
180 .and(path_regex(r"/at-home/server/[0-9a-fA-F-]+"))
181 .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
182 .expect(1)
183 .mount(&mock_server)
184 .await;
185
186 let resp = mangadex_client
187 .at_home()
188 .server()
189 .id(chapter_id)
190 .get()
191 .force_port_443(true)
192 .build()?
193 .send()
194 .await
195 .unwrap_err();
196 if let Error::RateLimitParseError(_) = resp {
197 Ok(())
198 } else {
199 panic!("Invalid Error Received")
200 }
201 }
202}