pub mod timetable;
#[cfg(test)]
mod test;
use timetable::Timetable;
use chrono::{Local, DateTime, Datelike};
use reqwest::{
header::{HeaderMap, HeaderValue},
Client, ClientBuilder,
};
use serde::Deserialize;
use thiserror::Error;
#[allow(dead_code)]
pub struct BklrClient {
access_token: String,
refresh_token: String,
expiry_date: i32,
url: String,
http_client: Client,
}
impl BklrClient {
pub async fn new(
username: &str,
password: &str,
url: &str,
) -> Result<BklrClient, crate::APIError> {
let client = Client::new();
let formatted_url = format!("{url}/api/login");
let response = client
.post(formatted_url)
.header(
"Content-Type",
"application/x-www-form-urlencoded"
.to_owned()
.parse::<HeaderValue>()
.unwrap(),
)
.body(format!("client_id=ANDR&grant_type=password&username={}&password={}",
username, password))
.send()
.await?;
let json = response.json::<Response>().await?;
let mut default_headers = HeaderMap::new();
default_headers.append(
"Content-Type",
"application/x-www-form-urlencoded".parse().unwrap(),
);
default_headers.append(
"Authorization",
format!("Bearer {}", json.access_token).parse().unwrap(),
);
let client = ClientBuilder::new()
.default_headers(default_headers)
.build()?;
Ok(BklrClient {
access_token: json.access_token,
refresh_token: json.refresh_token,
expiry_date: json.expires_in,
url: url.to_owned(),
http_client: client,
})
}
pub async fn get_timetable(&self) -> Result<Timetable, crate::APIError> {
let date: DateTime<Local> = chrono::Local::now();
let formatted_url = format!("{}/api/3/timetable/actual?date={}-{}-{}",
self.url,
date.year(),
date.month(),
date.day()
);
let response = self.http_client.get(formatted_url).send().await?;
Ok(response.json::<Timetable>().await?)
}
}
#[derive(Deserialize, Debug)]
struct Response {
pub access_token: String,
pub refresh_token: String,
pub expires_in: i32,
}
#[derive(Error, Debug)]
pub enum APIError {
#[error("API returned an unexpected field: {0}")]
UnexpectedField(#[from] serde_json::Error),
#[error("Request error: {0}")]
RequestError(#[from] reqwest::Error),
#[error("Unable to parse API response: {0}")]
ParseError(String),
#[error("Invalid credentials")]
InvalidCredentials,
}