2024-03-14 19:41:40 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::cache::{self, get_api_key};
|
|
|
|
use crate::config::get_endpoint;
|
|
|
|
use serde::Deserialize;
|
|
|
|
#[derive(PartialEq)]
|
2024-03-16 00:29:32 +01:00
|
|
|
pub enum Status {
|
2024-03-14 19:41:40 +01:00
|
|
|
OK,
|
|
|
|
INVALID,
|
|
|
|
LIMIT,
|
|
|
|
ERROR,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
2024-03-16 00:29:32 +01:00
|
|
|
struct CurrencyCodes {
|
2024-03-14 19:41:40 +01:00
|
|
|
supported_codes: Vec<[String; 2]>,
|
|
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
2024-03-16 00:29:32 +01:00
|
|
|
struct ConversionRates {
|
2024-03-14 19:41:40 +01:00
|
|
|
base_code: String,
|
|
|
|
time_next_update_unix: u64,
|
|
|
|
|
|
|
|
conversion_rates: HashMap<String, serde_json::Value>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
2024-03-16 00:29:32 +01:00
|
|
|
struct Err {
|
2024-03-14 19:41:40 +01:00
|
|
|
#[serde(rename = "error-type")]
|
|
|
|
error_type: String,
|
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
fn mock_get_rates(code: &String) -> Result<Status, reqwest::Error> {
|
|
|
|
let response: ConversionRates = match code.as_str() {
|
|
|
|
"PLN" => serde_json::from_str(include_str!(concat!(
|
|
|
|
".",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"mock_data",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"PLN.json"
|
|
|
|
)))
|
|
|
|
.expect("Error when deserializng"),
|
|
|
|
"EUR" => serde_json::from_str(include_str!(concat!(
|
|
|
|
".",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"mock_data",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"EUR.json"
|
|
|
|
)))
|
|
|
|
.expect("Error when deserializng"),
|
|
|
|
_ => {
|
|
|
|
panic!("Unknown code")
|
2024-03-22 01:47:14 +01:00
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
};
|
|
|
|
cache::add_rates(
|
|
|
|
response.time_next_update_unix,
|
|
|
|
&response.base_code,
|
|
|
|
&response.conversion_rates,
|
|
|
|
)
|
|
|
|
.expect("Error while caching response");
|
|
|
|
Ok(Status::OK)
|
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn mock_get_currencies() -> Result<Status, reqwest::Error> {
|
|
|
|
let codes: CurrencyCodes = serde_json::from_str(include_str!(concat!(
|
|
|
|
".",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"mock_data",
|
|
|
|
crate::main_separator!(),
|
|
|
|
"codes.json"
|
|
|
|
)))
|
|
|
|
.expect("Error when deserializng");
|
|
|
|
for code in codes.supported_codes {
|
|
|
|
cache::add_code(code).expect("Error when adding code to cache");
|
|
|
|
}
|
|
|
|
return Ok(Status::OK);
|
|
|
|
}
|
2024-03-22 01:47:14 +01:00
|
|
|
|
2024-03-22 12:49:09 +01:00
|
|
|
pub fn get_rates(code: &String) -> Result<Status, reqwest::Error> {
|
|
|
|
if cfg!(test) {
|
|
|
|
#[cfg(test)]
|
|
|
|
return mock_get_rates(code);
|
2024-03-22 01:47:14 +01:00
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
let response = reqwest::blocking::get(format!(
|
|
|
|
"{}{}{}{}",
|
|
|
|
get_endpoint(),
|
|
|
|
get_api_key().expect("Error when getting api key from cache"),
|
|
|
|
"/latest/",
|
|
|
|
code.to_uppercase()
|
|
|
|
))?;
|
|
|
|
if response.status().is_success() {
|
|
|
|
let response: ConversionRates =
|
|
|
|
serde_json::from_str(&response.text()?).expect("Error when deserializng");
|
2024-03-14 19:41:40 +01:00
|
|
|
cache::add_rates(
|
|
|
|
response.time_next_update_unix,
|
|
|
|
&response.base_code,
|
|
|
|
&response.conversion_rates,
|
|
|
|
)
|
|
|
|
.expect("Error while caching response");
|
2024-03-22 12:49:09 +01:00
|
|
|
return Ok(Status::OK);
|
|
|
|
} else {
|
|
|
|
let err: Err = serde_json::from_str(&response.text()?).expect("Error when deserializng");
|
|
|
|
if err.error_type == "invalid-key" {
|
|
|
|
return Ok(Status::INVALID);
|
|
|
|
} else if err.error_type == "quota-reached" {
|
|
|
|
return Ok(Status::LIMIT);
|
|
|
|
}
|
2024-03-14 19:41:40 +01:00
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
|
|
|
|
Ok(Status::ERROR)
|
2024-03-14 19:41:40 +01:00
|
|
|
}
|
2024-03-21 11:33:32 +01:00
|
|
|
pub fn get_currencies() -> Result<Status, reqwest::Error> {
|
2024-03-22 12:49:09 +01:00
|
|
|
if cfg!(test) {
|
|
|
|
#[cfg(test)]
|
|
|
|
return mock_get_currencies();
|
2024-03-22 01:47:14 +01:00
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
let response = reqwest::blocking::get(format!(
|
|
|
|
"{}{}{}",
|
|
|
|
get_endpoint(),
|
|
|
|
get_api_key().expect("Error when getting api key from cache"),
|
|
|
|
"/codes"
|
|
|
|
))?;
|
|
|
|
if response.status().is_success() {
|
|
|
|
let codes: CurrencyCodes =
|
|
|
|
serde_json::from_str(&response.text()?).expect("Error when deserializng");
|
2024-03-14 19:41:40 +01:00
|
|
|
for code in codes.supported_codes {
|
|
|
|
cache::add_code(code).expect("Error when adding code to cache");
|
|
|
|
}
|
|
|
|
return Ok(Status::OK);
|
2024-03-22 12:49:09 +01:00
|
|
|
} else {
|
|
|
|
let err: Err = serde_json::from_str(&response.text()?).expect("Error when deserializng");
|
|
|
|
if err.error_type == "invalid-key" {
|
|
|
|
return Ok(Status::INVALID);
|
|
|
|
} else if err.error_type == "quota-reached" {
|
|
|
|
return Ok(Status::LIMIT);
|
|
|
|
}
|
2024-03-14 19:41:40 +01:00
|
|
|
}
|
2024-03-22 12:49:09 +01:00
|
|
|
|
|
|
|
Ok(Status::ERROR)
|
2024-03-14 19:41:40 +01:00
|
|
|
}
|