use std::env::temp_dir; use std::fmt::Debug; use std::fs; use std::path::PathBuf; use std::io::{SeekFrom, Seek}; use reqwest::Client; use reqwest::header::{ACCEPT, CONTENT_TYPE}; use serde::de::DeserializeOwned; use serde::Serialize; use crate::error::{ManifoldError, ManifoldResult}; const CACHE_VERSION: &'static str = "1"; pub trait Pump { fn pump(&mut self) -> Option; fn len(&self) -> usize; } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FuelTank { pub source_uri: String, cache_name: Option, pub api_key: Option, cache_mode: TankMode, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum TankMode { Cache, NoCache, } impl FuelTank { pub async fn next_or_fill(&self) -> ManifoldResult where T: DeserializeOwned, U: Serialize, U: DeserializeOwned, U: Pump { let path = PathBuf::new() .join(temp_dir()) .join(format!("manifold-{}-cache-{}.json", self.cache_name.clone().unwrap(), CACHE_VERSION)); let mut fuel = match self.cache_mode { TankMode::Cache => { // Read cache only if we have one debug!("Filling tank!"); let mut cache = { debug!("Cache path: {:?}", &path); fs::OpenOptions::new() .read(true) .write(true) .create(true) .open(&path) .map_err(|e| { error!("Error creating cache file: {}", e); ManifoldError::from("CACHE ERROR") })? }; debug!("Cache: {:?}", &cache); let json: Result = serde_json::from_reader(&mut cache); debug!("Json: {:?}", &json); match json { Ok(contents) => { match contents.len() { 0 => self.emit().await?, _ => contents, } } _ => self.emit().await?, } }, TankMode::NoCache => { self.emit().await? }, }; debug!("Got tips: {:?}", &fuel); let single = fuel.pump().ok_or(ManifoldError::from("CACHE ERROR"))?; debug!("Got single tip: {:?}", &single); if self.cache_mode == TankMode::Cache { // Write cache only if we have one let mut cache = { debug!("Cache path: {:?}", &path); fs::OpenOptions::new() .write(true) .create(true) .open(&path) .map_err(|e| { error!("Error creating cache file: {}", e); ManifoldError::from("CACHE ERROR") })? }; cache .set_len(0) .and_then(|_| cache.seek(SeekFrom::Start(0)))?; debug!("Writing cache"); serde_json::to_writer(cache, &fuel)?; } Ok(single) } pub async fn emit(&self) -> ManifoldResult where U: DeserializeOwned { debug!("Getting new tips"); let result: U; let mut client = Client::new().get(&self.source_uri) .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json"); if let Some(api_key) = &self.api_key { client = client.header("X-API-KEY", api_key); } result = client.send().await?.json().await?; debug!("Result: {:?}", &result); Ok(result) } }