From c20c1165aa48138d17aaf3d2d6d39fb69e546921 Mon Sep 17 00:00:00 2001 From: Xyon Date: Sun, 3 Nov 2024 22:24:22 +0000 Subject: [PATCH] Add initial support for pulling F1 championship standings --- Cargo.lock | 358 +++++++++++++++++++++++++++++++--- Cargo.toml | 5 +- config/production.badgey.json | 4 + src/badgey/commands/f1.rs | 62 ++++++ src/badgey/commands/mod.rs | 2 + src/badgey/models/f1.rs | 230 ++++++++++++++++++++++ src/badgey/models/mod.rs | 1 + 7 files changed, 635 insertions(+), 27 deletions(-) create mode 100644 src/badgey/commands/f1.rs create mode 100644 src/badgey/models/f1.rs diff --git a/Cargo.lock b/Cargo.lock index 61e973c..563a012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,12 @@ dependencies = [ "webpki-roots 0.22.6", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.4.0" @@ -166,7 +172,7 @@ dependencies = [ [[package]] name = "badgey" -version = "4.1.0" +version = "4.2.0" dependencies = [ "built", "clap", @@ -178,7 +184,10 @@ dependencies = [ "poise", "rand 0.8.5", "regex 1.11.0", + "reqwest 0.12.9", "rust-i18n", + "serde", + "serde_json", "to_markdown_table", "tokio", "url", @@ -202,6 +211,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -918,7 +933,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -976,6 +1010,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -983,7 +1028,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1015,9 +1083,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1029,6 +1097,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1036,13 +1124,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.5.0", + "hyper-util", + "rustls 0.23.16", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1050,12 +1155,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.0", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1270,7 +1410,8 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "manifold" -version = "6.1.0" +version = "6.1.1" +source = "git+https://code.orbiter-radio.uk/discord/manifold.git#fb74ae27bda12ae3bc8c9ad5c7f9339d7222a0ab" dependencies = [ "built", "chrono", @@ -1288,7 +1429,7 @@ dependencies = [ "r2d2", "rand 0.8.5", "regex 1.11.0", - "reqwest", + "reqwest 0.11.27", "rust-i18n", "serde", "serde_json", @@ -1952,12 +2093,12 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "hyper-tls", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "hyper-rustls 0.24.2", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -1968,12 +2109,12 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", - "system-configuration", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", @@ -1988,6 +2129,49 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.0", + "hyper-rustls 0.27.3", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "ring" version = "0.16.20" @@ -2132,10 +2316,23 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -2145,6 +2342,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2155,6 +2367,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -2274,9 +2497,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2342,7 +2565,7 @@ dependencies = [ "mime_guess", "parking_lot", "percent-encoding", - "reqwest", + "reqwest 0.11.27", "rustversion", "serde", "serde-value", @@ -2449,6 +2672,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -2477,6 +2706,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2485,7 +2723,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -2498,6 +2747,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.13.0" @@ -2662,6 +2921,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.16", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.12" @@ -2807,7 +3077,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -3107,6 +3377,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3312,3 +3612,9 @@ dependencies = [ "quote", "syn 2.0.79", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index b361fd3..75b446e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "badgey" -version = "4.1.0" +version = "4.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,6 +24,9 @@ rust-i18n = "3.1.2" to_markdown_table = "0.1.5" tokio = { version = "1.16.1", features = ["sync", "macros", "rt-multi-thread"] } url = "2.5.2" +serde = { version = "1.0.210", features = ["derive"] } +reqwest = "0.12.9" +serde_json = "1.0.132" [package.metadata.i18n] # The available locales for your application, default: ["en"]. diff --git a/config/production.badgey.json b/config/production.badgey.json index e09cc9c..886f452 100644 --- a/config/production.badgey.json +++ b/config/production.badgey.json @@ -44,6 +44,10 @@ "source_uri": "https://api.nasa.gov/planetary/apod?api_key=NZfKclpoaO9HnvfvaCjeJ3csDecvIqNiABVw2YvN", "cache_name": "nasa_apod", "cache_mode": "NoCache" + }, + "f1": { + "source_uri": "https://api.jolpi.ca/ergast/f1", + "cache_mode": "NoCache" } } } diff --git a/src/badgey/commands/f1.rs b/src/badgey/commands/f1.rs new file mode 100644 index 0000000..48758b7 --- /dev/null +++ b/src/badgey/commands/f1.rs @@ -0,0 +1,62 @@ +use manifold::error::{ManifoldError, ManifoldResult}; +use manifold::{ManifoldContext, ManifoldData}; +use poise::serenity_prelude::CreateEmbed; +use to_markdown_table::MarkdownTable; +use crate::badgey::models::f1::{F1Client, StandingsListType}; + +#[poise::command(slash_command, prefix_command, subcommands("standings"))] +async fn f1(_ctx: ManifoldContext<'_>) -> ManifoldResult<()> { + Ok(()) +} + +#[derive(poise::ChoiceParameter)] +pub enum Championships { + Drivers, + Constructors, +} + +#[poise::command(slash_command, prefix_command)] +async fn standings(ctx: ManifoldContext<'_>, championship: Championships) -> ManifoldResult<()> { + + let config = &ctx.data().bot_config; + let f1_api_client = config.services.get("f1").ok_or_else(|| ManifoldError::from("No F1 API client available"))?; + let mut embed = CreateEmbed::default(); + + if let Some(standings) = f1_api_client.get_standings("current".to_string(), championship.to_string()).await? { + let _ = embed.title(format!("F1 {season} {championship} Championship Standings after {round} rounds:", season = standings.season, round = standings.round)).to_owned(); + let mut leaderboard_headings = Vec::new(); + let mut leaderboard_rows = Vec::new(); + + standings.standings_lists.iter().for_each(|f| { + match f { + StandingsListType::ConstructorStandings(c) => { + leaderboard_headings = vec!["Pos".to_string(), "Team".to_string(), "Pts".to_string()]; + c.constructor_standings.iter().for_each(|r| { + leaderboard_rows.push(vec![r.position_text.clone(), r.constructor.name.clone(), r.points.clone()]) + }); + } + StandingsListType::DriversStandings(d) => { + leaderboard_headings = vec!["Pos".to_string(), "Driver".to_string(), "Team".to_string(), "Pts".to_string()]; + d.driver_standings.iter().for_each(|r| { + leaderboard_rows.push(vec![r.position_text.clone(), format!("{first} {last}", first = r.driver.given_name.clone(), last = r.driver.family_name.clone()), r.constructors.first().unwrap().name.clone(), r.points.clone()]) + }); + } + } + + let leaderboard_table = MarkdownTable::new(Some(leaderboard_headings.clone()), leaderboard_rows.clone()).unwrap(); + + embed.description(format!("```{table}```", table=leaderboard_table)); + }); + } + + ctx.send(|m| { + m.embeds = vec![embed]; + m + }).await?; + + Ok(()) +} + +pub fn commands() -> [poise::Command; 1] { + [f1()] +} diff --git a/src/badgey/commands/mod.rs b/src/badgey/commands/mod.rs index 4679804..ba6733e 100644 --- a/src/badgey/commands/mod.rs +++ b/src/badgey/commands/mod.rs @@ -5,12 +5,14 @@ use poise::Command; pub mod custom_responses; pub mod ranks; pub mod moderation; +pub mod f1; pub fn collect_commands() -> Vec> { commands().into_iter() .chain(custom_responses::commands()) .chain(ranks::commands()) .chain(moderation::commands()) + .chain(f1::commands()) .collect() } diff --git a/src/badgey/models/f1.rs b/src/badgey/models/f1.rs new file mode 100644 index 0000000..ccd887b --- /dev/null +++ b/src/badgey/models/f1.rs @@ -0,0 +1,230 @@ +use manifold::error::ManifoldResult; +use manifold::models::fueltank::FuelTank; +use reqwest::header::CONTENT_TYPE; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CircuitLocation { + pub lat: String, + pub long: String, + pub locality: String, + pub country: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Circuit { + pub circuit_id: String, + pub url: String, + pub circuit_name: String, + #[serde(alias = "Location")] + pub location: CircuitLocation, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RaceSession { + pub date: Option, + pub time: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Race { + pub season: String, + pub round: String, + pub url: String, + pub race_name: String, + #[serde(alias = "Circuit")] + pub circuit: Circuit, + pub date: String, + pub time: Option, + pub first_practice: Option, + pub second_practice: Option, + pub third_practice: Option, + pub qualifying: Option, + pub sprint: Option, + pub sprint_qualifying: Option, + pub sprint_shootout: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct PitStop { + pub driver_id: String, + pub lap: Option, + pub stop: Option, + pub time: Option, + pub duration: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Qualifying { + pub number: String, + pub position: Option, + pub driver: Driver, + pub constructor: Constructor, + pub q1: Option, + pub q2: Option, + pub q3: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Timing { + pub driver_id: String, + pub position: String, + pub time: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Lap { + pub number: String, + pub timings: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RaceResult { + pub number: String, + pub position: String, + pub position_text: String, + pub points: String, + pub driver: Driver, + pub constructor: Option, + pub grid: Option, + pub laps: Option, + pub status: Option, + pub fastest_lap: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Constructor { + pub constructor_id: Option, + pub url: Option, + pub name: String, + pub nationality: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ConstructorStandings { + pub position: Option, + pub position_text: String, + pub points: String, + pub wins: String, + #[serde(alias = "Constructor")] + pub constructor: Constructor, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Driver { + pub driver_id: String, + pub permanent_number: Option, + pub code: Option, + pub url: Option, + pub given_name: String, + pub family_name: String, + pub date_of_birth: Option, + pub nationality: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct DriverStandings { + pub position: Option, + pub position_text: String, + pub points: String, + pub wins: String, + #[serde(alias = "Driver")] + pub driver: Driver, + #[serde(alias = "Constructors")] + pub constructors: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct DriverStandingsList { + pub season: String, + pub round: String, + #[serde(alias = "DriverStandings")] + pub driver_standings: Vec +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ConstructorStandingsList { + pub season: String, + pub round: String, + #[serde(alias = "ConstructorStandings")] + pub constructor_standings: Vec +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(untagged, rename_all_fields = "camelCase")] +pub enum StandingsListType { + ConstructorStandings(ConstructorStandingsList), + DriversStandings(DriverStandingsList) +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct StandingsTable { + pub season: String, + pub round: String, + #[serde(alias = "StandingsLists")] + pub standings_lists: Vec +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Season { + pub season: String, + pub url: String, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct F1APIResponse { + #[serde(alias = "MRData")] + mrdata: MRData, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MRData { + pub series: String, + pub xmlns: String, + pub url: String, + pub limit: String, + pub offset: String, + pub total: String, + #[serde(alias = "StandingsTable")] + pub standings_table: Option +} + +pub type F1 = FuelTank; + +pub trait F1Client { + async fn get_standings(&self, season: String, championship: String) -> ManifoldResult>; +} + +impl F1Client for F1 { + async fn get_standings(&self, season: String, championship: String) -> ManifoldResult> { + let base_url = format!("{base}/{season}/{championship}tandings/", base = self.source_uri, season = season, championship = championship.to_lowercase()); + let client = reqwest::Client::new(); + let response = client.get(base_url) + .header(CONTENT_TYPE, "application/json") + .send() + .await? + .text() + .await?; + + let decoded_result: F1APIResponse = serde_json::from_str(&*response)?; + + Ok(decoded_result.mrdata.standings_table) + } +} \ No newline at end of file diff --git a/src/badgey/models/mod.rs b/src/badgey/models/mod.rs index f37855c..d17dd11 100644 --- a/src/badgey/models/mod.rs +++ b/src/badgey/models/mod.rs @@ -1,3 +1,4 @@ pub mod custom_response; pub mod xp; pub mod quarantine_channel; +pub mod f1;