lol_game_client_api/
api.rs

1//! Module containing all the necessary code to request `https://127.0.0.1:2999/liveclientdata/` endpoints.
2//! The official documentation can be found at [https://developer.riotgames.com/docs/lol#game-client-api]
3
4use crate::api;
5use crate::model::{Abilities, ActivePlayer, AllGameData, Events, FullRunes, GameData, Player};
6use reqwest::{Certificate, IntoUrl};
7use serde::Deserialize;
8use thiserror::Error;
9
10pub struct GameClient {
11    client: reqwest::Client,
12}
13
14/// Get the root certificate that is used to sign the SSL certificates.
15/// You need to trust this certificate to be able to make requests to the API.
16#[cold]
17pub fn get_riot_root_certificate() -> Certificate {
18    Certificate::from_pem(include_bytes!("riotgames.cer")).unwrap()
19}
20
21#[derive(Debug, Error)]
22pub enum QueryError {
23    #[error("Failed to query the API. Is the game running ? '{}'", _0)]
24    Reqwest(#[from] reqwest::Error), // An error of this type may suggests that the API specs as been updated and the crate is out-of-date. Please fill an issue !
25}
26
27impl Default for GameClient {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl GameClient {
34    /// Create a new `GameClient`using a `reqwest::Client`.
35    /// As Riot Games self-sign their SSL certificates, it would be great to trust them in the `reqwest::Client`.
36    pub fn new() -> Self {
37        GameClient::_from_certificate(get_riot_root_certificate()).unwrap()
38    }
39
40    /// This method should only be used if Riot updates its root certificate and the crate is not up-to-date.
41    /// Otherwise, use `GameClient::new`
42    pub fn _from_certificate(certificate: Certificate) -> Result<Self, QueryError> {
43        Ok(GameClient {
44            client: reqwest::ClientBuilder::new()
45                .add_root_certificate(certificate)
46                .build()?,
47        })
48    }
49
50    /// Query the endpoint and automagically deserialize the json into the desired type
51    async fn get_data<T: for<'de> Deserialize<'de>, U: IntoUrl>(
52        &self,
53        endpoint: U,
54    ) -> Result<T, QueryError> {
55        let data = self.client.get(endpoint).send().await?.json::<T>().await?;
56        Ok(data)
57    }
58}
59
60/// All the implemented endpoints
61impl GameClient {
62    /// Get all available data.
63    pub async fn all_game_data(&self) -> Result<AllGameData, QueryError> {
64        self.get_data(api!("allgamedata")).await
65    }
66
67    /// Get all data about the active player.
68    pub async fn active_player(&self) -> Result<ActivePlayer, QueryError> {
69        self.get_data(api!("activeplayer")).await
70    }
71
72    /// Returns the player name.
73    pub async fn active_player_name(&self) -> Result<String, QueryError> {
74        self.get_data(api!("activeplayername")).await
75    }
76
77    /// Get Abilities for the active player.
78    pub async fn active_player_abilities(&self) -> Result<Abilities, QueryError> {
79        self.get_data(api!("activeplayerabilities")).await
80    }
81
82    /// Retrieve the full list of runes for the active player.
83    pub async fn active_player_runes(&self) -> Result<FullRunes, QueryError> {
84        self.get_data(api!("activeplayerrunes")).await
85    }
86
87    /// Retrieve the list of heroes in the game and their stats.
88    pub async fn player_list(&self) -> Result<Vec<Player>, QueryError> {
89        self.get_data(api!("playerlist")).await
90    }
91
92    // TODO: Infos specific to a player.
93
94    /// Get a list of events that have occurred in the game.
95    pub async fn event_data(&self) -> Result<Events, QueryError> {
96        self.get_data(api!("eventdata")).await
97    }
98
99    /// Basic data about the game.
100    pub async fn game_stats(&self) -> Result<GameData, QueryError> {
101        self.get_data(api!("gamestats")).await
102    }
103}
104
105#[macro_export]
106macro_rules! api {
107    ($endpoint:expr) => {
108        concat!("https://127.0.0.1:2999/liveclientdata/", $endpoint)
109    };
110}