1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! rosu is a rust wrapper for [osu!](https://osu.ppy.sh/home).
//!
//! The wrapper provides access to the [osu!api](https://github.com/ppy/osu-api/wiki)'s
//! beatmap, user, score, user-best, user-recent, and match endpoints.
//! *Note:* Only v1 of the osu!api is supported.
//!
//! An API key can be generated [here](https://github.com/ppy/osu-api/wiki#requesting-access).
//!
//! Simply initialize an [`Osu`](crate::Osu) client with the api key, call any of its `get_*` methods
//! and await its result.
//!
//! ## Examples
//!
//! ```no_run
//! use chrono::{offset::TimeZone, DateTime, Utc};
//! use rosu::{
//!     model::*,
//!     Osu, OsuResult,
//! };
//!
//! #[tokio::main]
//! async fn main() -> OsuResult<()> {
//!     // Initialize the client
//!     # let osu: Osu = {
//!     # /*
//!     let osu = Osu::new("osu_api_key");
//!     # */
//!     # panic!()
//!     # };
//!     // If `cache` feature enabled:
//!     // let osu = Osu::new("osu_api_key", redis_pool, rosu::OsuCached::User);
//!
//!     // --- Retrieving top scores ---
//!
//!     // Accumulate all important arguments for the request
//!     let request = osu.top_scores("Badewanne3")
//!         .mode(GameMode::MNA)
//!         .limit(4);
//!     // Await the request
//!     let mut scores: Vec<Score> = request.await?;
//!     match scores.pop() {
//!         Some(score) => {
//!             // Retrieve user of the score
//!             let user = score.get_user(&osu).mode(GameMode::STD).await?;
//!             // ...
//!         }
//!         None => println!("No top scores found"),
//!     }
//!
//!     // --- Retrieving beatmaps ---
//!
//!     let since_date: DateTime<Utc> = Utc
//!         .datetime_from_str("2018-11-13 23:01:28", "%Y-%m-%d %H:%M:%S")
//!         .unwrap();
//!     let request = osu.beatmaps()
//!         .mode(GameMode::MNA)
//!         .limit(3)
//!         .since(since_date)
//!         .mapset_id(945496);
//!     let mut maps: Vec<Beatmap> = request.await?;
//!     if let Some(map) = maps.pop() {
//!         let leaderboard: Vec<Score> = map.get_global_leaderboard(&osu).limit(13).await?;
//!         // ...
//!     }
//!
//!     // --- Retrieving user ---
//!
//!     let user: Option<User> = osu.user("Badewanne3").await?;
//!     // ...
//!
//!     // --- Retrieving match ---
//!
//!     let osu_match: Match = osu.osu_match(58494587).await?;
//!     // ...
//!
//!     Ok(())
//! }
//! ```
//!
//! ### Features
//!
//! | Flag        | Description                                            | deps                                                |
//! | ----------- | ------------------------------------------------------ | --------------------------------------------------- |
//! | `serialize` | Provides serialization for all structs in the `models` dir | [serde-repr](https://github.com/dtolnay/serde-repr) |
//! | `metrics`   | Make the client count each request type and enable a method on the client to get a `prometheus::IntCounterVec` | [prometheus](https://github.com/tikv/rust-prometheus)
//! | `cache`     | Cache API results through a redis connection for a given duration | [darkredis](https://github.com/Bunogi/darkredis), `serialize` |
//!
//! ### Error handling
//! [`OsuError`](crate::OsuError)s are nested through their source errors. To read them, one can use a small unwind macro such as:
//!
//! ```no_run
//! #[macro_export]
//! # /*
//! macro_rules! unwind_error {
//!     ($log:ident, $err:ident, $($arg:tt)+) => {
//!         {
//!             $log!($($arg)+, $err);
//!             let mut err: &dyn ::std::error::Error = &$err;
//!             while let Some(source) = err.source() {
//!                 $log!("  - caused by: {}", source);
//!                 err = source;
//!             }
//!         }
//!     };
//! }
//! # */
//!
//! use rosu::{Osu, OsuResult, model::GameMode};
//!
//! #[tokio::main]
//! async fn main() {
//!     # let osu: Osu = {
//!     # /*
//!     let osu = Osu::new("osu_api_key");
//!     # */
//!     # panic!()
//!     # };
//!     let mode = GameMode::STD;
//!     if let Err(why) = osu.user("badewanne3").mode(mode).await {
//!         # /*
//!         unwind_error!(println, why, "Error while retrieving user for mode {}", mode);
//!         # */
//!     }
//! }
//! ```

#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;

/// Contains the Osu client
mod client;
/// Contains any kind of OsuError that can occur
mod error;
#[cfg(feature = "metrics")]
/// Contains the struct that keeps track of the amount of requests the client does
pub(crate) mod metrics;
/// Contains structs that are parsed from the osu!api
pub mod model;
/// Re-exporting a bunch of things
pub mod prelude;
/// Contains the ratelimiter for the client
pub(crate) mod ratelimit;
/// Contains the Future structs that request the data
pub mod request;
/// Contains the Route enum, responsible for generating the url
mod routing;
/// Contains methods and implementations to (de)serialize structs
pub(crate) mod serde;

pub use error::{OsuError, OsuResult};

pub use client::{Osu, OsuBuilder};

#[cfg(feature = "cache")]
pub use client::OsuCached;