use crate::{config::HttpsConfig, Error, Price, TradingPair};
use iqhttp::{HttpsClient, Query};
use rust_decimal::prelude::FromPrimitive;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
pub const API_HOST: &str = "api.currencylayer.com";
pub struct CurrencylayerSource {
https_client: HttpsClient,
access_key: String,
}
pub struct CurrencylayerParams {
source: String,
currencies: String,
access_key: String,
}
impl CurrencylayerParams {
pub fn to_request_uri(&self) -> Query {
let mut query = Query::new();
query.add("source".to_owned(), self.source.to_string());
query.add("currencies".to_owned(), self.currencies.to_string());
query.add("access_key".to_owned(), self.access_key.to_string());
query
}
}
impl CurrencylayerSource {
pub fn new(access_key: impl Into<String>, config: &HttpsConfig) -> Result<Self, Error> {
let https_client = config.new_client(API_HOST)?;
Ok(Self {
https_client,
access_key: access_key.into(),
})
}
pub async fn trading_pairs(&self, pair: &TradingPair) -> Result<Price, Error> {
let params = CurrencylayerParams {
source: pair.0.to_string(),
currencies: pair.1.to_string(),
access_key: self.access_key.clone(),
};
let query = params.to_request_uri();
let resp: Response = self.https_client.get_json("/live", &query).await?;
let price = resp
.quotes
.values()
.into_iter()
.last()
.expect("expected currencylayer to return one value");
let dec_price = Decimal::from_f64(*price)
.expect("expected currencylayer response to convert to a decimal");
Price::new(dec_price)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Response {
success: bool,
terms: String,
privacy: String,
timestamp: i64,
source: String,
quotes: std::collections::HashMap<String, f64>,
}
#[cfg(test)]
mod tests {
use super::CurrencylayerSource;
#[tokio::test]
#[ignore]
async fn trading_pairs_ok() {
let pair = "KRW/USD".parse().unwrap();
let _response = CurrencylayerSource::new(
&std::env::var("CURRENCYLAYER_API")
.expect("Please set the CURRENCYLAYER_API env variable"),
&Default::default(),
)
.unwrap()
.trading_pairs(&pair)
.await
.unwrap();
}
}