rte_france/
lib.rs

1use oauth2::reqwest::http_client;
2use oauth2::AccessToken;
3use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, TokenResponse, TokenUrl};
4
5pub mod api;
6//use api::generation::GenerationForecast;
7
8const PRODUCTION_BASE_URL: &str = "https://digital.iservices.rte-france.com/";
9
10#[derive(Debug)]
11enum ApiException {
12    /// Invalid cliend id or secret
13    InvalidToken,
14    /// Too many requests
15    TooManyRequests,
16    /// The application (api endpoint) has not be registered with the oauth application
17    ApplicationNotRegistered,
18    UnknownError,
19}
20
21pub trait ApiClient {
22    fn http_get(
23        &self,
24        path: &str,
25        query_string: &[(String, String)],
26        //) -> Result<reqwest::blocking::Response, reqwest::Error>;
27    ) -> Result<String, anyhow::Error>;
28}
29
30#[derive(Debug)]
31pub struct RteApi {
32    client_id: ClientId,
33    client_secret: ClientSecret,
34    base_url: String,
35
36    token: Option<AccessToken>,
37}
38
39impl RteApi {
40    pub fn new(client_id: String, client_secret: String) -> Self {
41        RteApi {
42            client_id: ClientId::new(client_id),
43            client_secret: ClientSecret::new(client_secret),
44            base_url: PRODUCTION_BASE_URL.to_string(),
45            token: None,
46        }
47    }
48
49    pub fn from_env_values() -> Self {
50        let client_id = std::env::var("CLIENT_ID").expect("CLIENT_ID must be set");
51        let client_secret = std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET must be set");
52
53        RteApi::new(client_id, client_secret)
54    }
55
56    pub fn with_base_url(mut self, base_url: String) -> Self {
57        self.base_url = base_url;
58        self
59    }
60
61    pub fn authenticate(&mut self) -> anyhow::Result<()> {
62        let auth_url = format!("{}/oauth/authorize", self.base_url);
63        let token_url = format!("{}/oauth/token", self.base_url);
64        let client = BasicClient::new(
65            self.client_id.clone(),
66            Some(self.client_secret.clone()),
67            AuthUrl::new(auth_url)?,
68            Some(TokenUrl::new(token_url)?),
69        );
70
71        let token_result = client.exchange_client_credentials().request(http_client)?;
72
73        self.token = Some(token_result.access_token().clone());
74
75        Ok(())
76    }
77
78    pub fn get_token(&self) -> &String {
79        self.token.as_ref().unwrap().secret()
80    }
81}
82
83impl ApiClient for RteApi {
84    fn http_get(
85        &self,
86        path: &str,
87        query_string: &[(String, String)],
88    ) -> Result<String, anyhow::Error> {
89        let url = format!("{}{}", self.base_url, path);
90        let token = self.token.as_ref().unwrap().secret();
91
92        let http_client = reqwest::blocking::Client::new();
93
94        println!("url: {:?}", url);
95        let response = http_client
96            .get(&url)
97            .query(&query_string)
98            .bearer_auth(token)
99            .send()?;
100
101        let status_code = response.status();
102
103        let body = response.text()?;
104        println!("response: {:?}", body);
105        if !status_code.is_success() {
106            let status = match status_code.as_u16() {
107                401 => ApiException::InvalidToken,
108                429 => ApiException::TooManyRequests,
109                403 => ApiException::ApplicationNotRegistered,
110                _ => ApiException::UnknownError,
111            };
112            eprintln!(
113                "Error HTTP {} ({:?}): {}",
114                status_code.as_str(),
115                status,
116                body
117            );
118            return Err(anyhow::Error::msg(format!("Request failed: {}", 42)));
119        }
120
121        Ok(body)
122    }
123}