1pub mod api_client;
2pub mod at_home;
3pub mod auth;
4pub mod author;
5pub mod captcha;
6pub mod chapter;
7pub mod cover;
8pub mod custom_list;
9pub mod feed;
10pub mod forums;
11pub mod legacy;
12pub mod manga;
13cfg_oauth! {
14 pub mod oauth;
15}
16pub mod ping;
17pub mod rating;
18pub mod report;
19pub mod scanlation_group;
20pub mod search;
21pub mod settings;
22pub mod statistics;
23pub mod upload;
24pub mod user;
25
26#[cfg(all(feature = "multi-thread", not(feature = "tokio-multi-thread")))]
27use futures::lock::Mutex;
28pub use mangadex_api_schema::v5 as schema;
29use mangadex_api_schema::v5::oauth::ClientInfo;
30pub(crate) use mangadex_api_schema::v5::AuthTokens;
31use mangadex_api_types::error::Result;
32
33use reqwest::Client;
34#[cfg(all(
35 not(feature = "multi-thread"),
36 not(feature = "tokio-multi-thread"),
37 not(feature = "rw-multi-thread")
38))]
39use std::cell::RefCell;
40#[cfg(all(
41 not(feature = "multi-thread"),
42 not(feature = "tokio-multi-thread"),
43 not(feature = "rw-multi-thread")
44))]
45use std::rc::Rc;
46#[cfg(any(
47 feature = "multi-thread",
48 feature = "tokio-multi-thread",
49 feature = "rw-multi-thread"
50))]
51use std::sync::Arc;
52#[cfg(feature = "tokio-multi-thread")]
53use tokio::sync::Mutex;
54#[cfg(feature = "rw-multi-thread")]
55use tokio::sync::RwLock;
56
57#[cfg(feature = "utils")]
58use crate::utils::download::DownloadBuilder;
59use crate::v5::api_client::ApiClientEndpoint;
60use crate::v5::at_home::AtHomeBuilder;
61use crate::v5::auth::AuthBuilder;
62use crate::v5::author::AuthorBuilder;
63use crate::v5::captcha::CaptchaBuilder;
64use crate::v5::chapter::ChapterBuilder;
65use crate::v5::cover::CoverBuilder;
66use crate::v5::custom_list::CustomListBuilder;
67use crate::v5::feed::FeedBuilder;
68use crate::v5::forums::ForumsEndpoint;
69use crate::v5::legacy::LegacyBuilder;
70use crate::v5::manga::MangaBuilder;
71#[cfg(feature = "oauth")]
72use crate::v5::oauth::OAuthBuider;
73use crate::v5::ping::PingEndpointBuilder;
74use crate::v5::rating::RatingBuilder;
75use crate::v5::report::ReportBuilder;
76use crate::v5::scanlation_group::ScanlationGroupBuilder;
77use crate::v5::search::SearchBuilder;
78use crate::v5::settings::SettingsBuilder;
79use crate::v5::statistics::StatisticsBuilder;
80use crate::v5::upload::UploadBuilder;
81use crate::v5::user::UserBuilder;
82use crate::HttpClient;
83use crate::HttpClientRef;
84
85#[derive(Clone, Debug)]
87pub struct MangaDexClient {
88 pub http_client: HttpClientRef,
89}
90
91impl Default for MangaDexClient {
92 fn default() -> Self {
107 Self::new_with_http_client(HttpClient::default())
108 }
109}
110
111impl MangaDexClient {
112 pub fn new(client: Client) -> Self {
131 Self::new_with_http_client_ref(create_ref_counted_http_client(HttpClient::new(client)))
132 }
133
134 pub fn new_with_http_client_ref(http_client: HttpClientRef) -> Self {
136 Self { http_client }
137 }
138 pub fn new_with_http_client(http_client: HttpClient) -> Self {
168 Self::new_with_http_client_ref(create_ref_counted_http_client(http_client))
169 }
170
171 pub fn get_http_client(&self) -> HttpClientRef {
177 self.http_client.clone()
178 }
179 #[cfg(all(
180 not(feature = "multi-thread"),
181 not(feature = "tokio-multi-thread"),
182 not(feature = "rw-multi-thread")
183 ))]
184 pub async fn set_auth_tokens(&mut self, auth_tokens: &AuthTokens) -> Result<()> {
185 let client = &mut self.http_client.try_borrow_mut()?;
186 client.set_auth_tokens(auth_tokens);
187 Ok(())
188 }
189 #[cfg(any(
190 feature = "multi-thread",
191 feature = "tokio-multi-thread",
192 feature = "rw-multi-thread"
193 ))]
194 pub async fn set_auth_tokens(&self, auth_tokens: &AuthTokens) -> Result<()> {
195 let mut client = {
196 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
197 {
198 self.http_client.lock().await
199 }
200 #[cfg(feature = "rw-multi-thread")]
201 {
202 self.http_client.write().await
203 }
204 };
205 client.set_auth_tokens(auth_tokens);
206 Ok(())
207 }
208
209 #[cfg(all(
210 not(feature = "multi-thread"),
211 not(feature = "tokio-multi-thread"),
212 not(feature = "rw-multi-thread")
213 ))]
214 pub async fn clear_auth_tokens(&mut self) -> Result<()> {
215 let client = {
216 #[cfg(all(
217 not(feature = "multi-thread"),
218 not(feature = "tokio-multi-thread"),
219 not(feature = "rw-multi-thread")
220 ))]
221 {
222 &mut self.http_client.try_borrow_mut()?
223 }
224 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
225 {
226 &mut self.http_client.lock().await
227 }
228 #[cfg(feature = "rw-multi-thread")]
229 {
230 &mut self.http_client.write().await
231 }
232 };
233 client.clear_auth_tokens();
234 Ok(())
235 }
236 #[cfg(any(
237 feature = "multi-thread",
238 feature = "tokio-multi-thread",
239 feature = "rw-multi-thread"
240 ))]
241 pub async fn clear_auth_tokens(&self) -> Result<()> {
242 let mut client = {
243 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
244 {
245 self.http_client.lock().await
246 }
247 #[cfg(feature = "rw-multi-thread")]
248 {
249 self.http_client.write().await
250 }
251 };
252 client.clear_auth_tokens();
253 Ok(())
254 }
255 pub async fn get_auth_tokens(&self) -> Result<AuthTokens> {
256 let client = {
257 #[cfg(all(
258 not(feature = "multi-thread"),
259 not(feature = "tokio-multi-thread"),
260 not(feature = "rw-multi-thread")
261 ))]
262 {
263 &self.http_client.try_borrow()?
264 }
265 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
266 {
267 &self.http_client.lock().await
268 }
269 #[cfg(feature = "rw-multi-thread")]
270 {
271 &self.http_client.read().await
272 }
273 };
274 client
275 .get_tokens()
276 .cloned()
277 .ok_or(mangadex_api_types::error::Error::MissingTokens)
278 }
279
280 #[cfg(all(
281 not(feature = "multi-thread"),
282 not(feature = "tokio-multi-thread"),
283 not(feature = "rw-multi-thread")
284 ))]
285 pub async fn set_captcha<A: Into<String>>(&mut self, captcha: A) -> Result<()> {
286 let client = &mut self.http_client.try_borrow_mut()?;
287 client.set_captcha(captcha);
288 Ok(())
289 }
290 #[cfg(any(
291 feature = "multi-thread",
292 feature = "tokio-multi-thread",
293 feature = "rw-multi-thread"
294 ))]
295 pub async fn set_captcha<A: Into<String>>(&self, captcha: A) -> Result<()> {
296 let mut client = {
297 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
298 {
299 self.http_client.lock().await
300 }
301 #[cfg(feature = "rw-multi-thread")]
302 {
303 self.http_client.write().await
304 }
305 };
306 client.set_captcha(captcha);
307 Ok(())
308 }
309 pub async fn get_captcha(&self) -> Result<String> {
310 let client = {
311 #[cfg(all(
312 not(feature = "multi-thread"),
313 not(feature = "tokio-multi-thread"),
314 not(feature = "rw-multi-thread")
315 ))]
316 {
317 &self.http_client.try_borrow()?
318 }
319 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
320 {
321 &self.http_client.lock().await
322 }
323 #[cfg(feature = "rw-multi-thread")]
324 {
325 &self.http_client.read().await
326 }
327 };
328 client
329 .get_captcha()
330 .cloned()
331 .ok_or(mangadex_api_types::error::Error::MissingCaptcha)
332 }
333 #[cfg(all(
334 not(feature = "multi-thread"),
335 not(feature = "tokio-multi-thread"),
336 not(feature = "rw-multi-thread")
337 ))]
338 pub async fn clear_captcha(&mut self) -> Result<()> {
339 let client = &mut self.http_client.try_borrow_mut()?;
340 client.clear_captcha();
341 Ok(())
342 }
343 #[cfg(any(
344 feature = "multi-thread",
345 feature = "tokio-multi-thread",
346 feature = "rw-multi-thread"
347 ))]
348 pub async fn clear_captcha(&self) -> Result<()> {
349 let mut client = {
350 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
351 {
352 self.http_client.lock().await
353 }
354 #[cfg(feature = "rw-multi-thread")]
355 {
356 self.http_client.write().await
357 }
358 };
359 client.clear_captcha();
360 Ok(())
361 }
362
363 cfg_oauth! {
364 pub async fn get_client_info(&self) -> Result<ClientInfo> {
365 let client = {
366 #[cfg(all(
367 not(feature = "multi-thread"),
368 not(feature = "tokio-multi-thread"),
369 not(feature = "rw-multi-thread")
370 ))]
371 {
372 &self.http_client.try_borrow()?
373 }
374 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
375 {
376 &self.http_client.lock().await
377 }
378 #[cfg(feature = "rw-multi-thread")]
379 {
380 &self.http_client.read().await
381 }
382 };
383 client
384 .get_client_info()
385 .cloned()
386 .ok_or(mangadex_api_types::error::Error::MissingClientInfo)
387 }
388 }
389 pub fn at_home(&self) -> AtHomeBuilder {
393 AtHomeBuilder::new(self.http_client.clone())
394 }
395
396 pub fn auth(&self) -> AuthBuilder {
402 AuthBuilder::new(self.http_client.clone())
403 }
404
405 pub fn author(&self) -> AuthorBuilder {
409 AuthorBuilder::new(self.http_client.clone())
410 }
411
412 pub fn captcha(&self) -> CaptchaBuilder {
416 CaptchaBuilder::new(self.http_client.clone())
417 }
418
419 pub fn chapter(&self) -> ChapterBuilder {
423 ChapterBuilder::new(self.http_client.clone())
424 }
425
426 pub fn client(&self) -> ApiClientEndpoint {
427 ApiClientEndpoint::new(self.http_client.clone())
428 }
429
430 pub fn cover(&self) -> CoverBuilder {
434 CoverBuilder::new(self.http_client.clone())
435 }
436
437 pub fn custom_list(&self) -> CustomListBuilder {
441 CustomListBuilder::new(self.http_client.clone())
442 }
443
444 pub fn feed(&self) -> FeedBuilder {
448 FeedBuilder::new(self.http_client.clone())
449 }
450
451 pub fn ping(&self) -> PingEndpointBuilder {
455 PingEndpointBuilder::new(self.http_client.clone())
456 }
457
458 pub fn legacy(&self) -> LegacyBuilder {
462 LegacyBuilder::new(self.http_client.clone())
463 }
464
465 pub fn manga(&self) -> MangaBuilder {
469 MangaBuilder::new(self.http_client.clone())
470 }
471
472 pub fn rating(&self) -> RatingBuilder {
476 RatingBuilder::new(self.http_client.clone())
477 }
478
479 pub fn report(&self) -> ReportBuilder {
483 ReportBuilder::new(self.http_client.clone())
484 }
485
486 pub fn scanlation_group(&self) -> ScanlationGroupBuilder {
490 ScanlationGroupBuilder::new(self.http_client.clone())
491 }
492
493 pub fn search(&self) -> SearchBuilder {
497 SearchBuilder::new(self.http_client.clone())
498 }
499
500 pub fn settings(&self) -> SettingsBuilder {
505 SettingsBuilder::new(self.http_client.clone())
506 }
507
508 pub fn statistics(&self) -> StatisticsBuilder {
512 StatisticsBuilder::new(self.http_client.clone())
513 }
514
515 pub fn upload(&self) -> UploadBuilder {
519 UploadBuilder::new(self.http_client.clone())
520 }
521
522 pub fn user(&self) -> UserBuilder {
526 UserBuilder::new(self.http_client.clone())
527 }
528
529 pub fn api_dev_client() -> Self {
532 Self::new_with_http_client(HttpClient::api_dev_client())
533 }
534 cfg_utils! {
535 pub fn download(&self) -> DownloadBuilder {
536 DownloadBuilder::new(self.http_client.clone())
537 }
538 }
539
540 pub fn forums(&self) -> ForumsEndpoint {
541 ForumsEndpoint::new(self.http_client.clone())
542 }
543
544 cfg_oauth! {
545 pub fn oauth(&self) -> OAuthBuider {
546 OAuthBuider::new(self.http_client.clone())
547 }
548 }
549}
550
551fn create_ref_counted_http_client(http_client: HttpClient) -> HttpClientRef {
553 #[cfg(all(
554 not(feature = "multi-thread"),
555 not(feature = "tokio-multi-thread"),
556 not(feature = "rw-multi-thread")
557 ))]
558 {
559 Rc::new(RefCell::new(http_client))
560 }
561 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
562 {
563 Arc::new(Mutex::new(http_client))
564 }
565 #[cfg(feature = "rw-multi-thread")]
566 {
567 Arc::new(RwLock::new(http_client))
568 }
569}
570
571#[cfg(all(
572 feature = "oauth",
573 all(
574 not(feature = "multi-thread"),
575 not(feature = "tokio-multi-thread"),
576 not(feature = "rw-multi-thread")
577 )
578))]
579#[cfg_attr(
580 docsrs,
581 doc(cfg(all(
582 feature = "oauth",
583 all(
584 not(feature = "multi-thread"),
585 not(feature = "tokio-multi-thread"),
586 not(feature = "rw-multi-thread")
587 )
588 )))
589)]
590impl MangaDexClient {
591 pub async fn set_client_info(&mut self, client_info: &ClientInfo) -> Result<()> {
592 let client = &mut self.http_client.try_borrow_mut()?;
593
594 client.set_client_info(client_info);
595 Ok(())
596 }
597 pub async fn clear_client_info(&mut self) -> Result<()> {
598 let client = &mut self.http_client.try_borrow_mut()?;
599 client.clear_client_info();
600 Ok(())
601 }
602}
603
604#[cfg(all(
605 feature = "oauth",
606 any(
607 feature = "multi-thread",
608 feature = "tokio-multi-thread",
609 feature = "rw-multi-thread"
610 )
611))]
612#[cfg_attr(
613 docsrs,
614 doc(all(
615 feature = "oauth",
616 any(
617 feature = "multi-thread",
618 feature = "tokio-multi-thread",
619 feature = "rw-multi-thread"
620 )
621 ))
622)]
623impl MangaDexClient {
624 pub async fn set_client_info(&self, client_info: &ClientInfo) -> Result<()> {
625 let mut client = {
626 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
627 {
628 self.http_client.lock().await
629 }
630 #[cfg(feature = "rw-multi-thread")]
631 {
632 self.http_client.write().await
633 }
634 };
635 client.set_client_info(client_info);
636 Ok(())
637 }
638 pub async fn clear_client_info(&self) -> Result<()> {
639 let mut client = {
640 #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
641 {
642 self.http_client.lock().await
643 }
644 #[cfg(feature = "rw-multi-thread")]
645 {
646 self.http_client.write().await
647 }
648 };
649 client.clear_client_info();
650 Ok(())
651 }
652}