diff --git a/src/cgg_data_source.rs b/src/cgg_data_source.rs index 2fe8787..72b9a36 100644 --- a/src/cgg_data_source.rs +++ b/src/cgg_data_source.rs @@ -95,6 +95,8 @@ fn extract_json(pattern: &str, page: &str) -> String { } impl DataSource for CGGDataSource { + fn init(&self, _client: &ureq::Agent) {} + fn get_alias(&self) -> &str { "CGG" } diff --git a/src/data_source.rs b/src/data_source.rs index 93963a5..2b62d2b 100644 --- a/src/data_source.rs +++ b/src/data_source.rs @@ -38,6 +38,8 @@ pub struct Stat { } pub trait DataSource { + fn init(&self, client: &ureq::Agent); + fn get_alias(&self) -> &str; fn get_timeout(&self) -> u64; diff --git a/src/kb_data_source.rs b/src/kb_data_source.rs index 98ec863..fdd9175 100644 --- a/src/kb_data_source.rs +++ b/src/kb_data_source.rs @@ -3,13 +3,12 @@ use crate::data_source::{Build, DataSource, Item, Stat}; use crate::time::Duration; use crate::ChampInfo; use indexmap::IndexMap; +use lazy_static::lazy_static; use serde_derive::Deserialize; use serde_json::{json, Value}; +use std::sync::Mutex; -pub struct KBDataSource { - token: Option, - internal_classname_mapping: IndexMap, -} +pub struct KBDataSource; #[derive(Deserialize, Debug)] struct ChampionResponse { @@ -90,17 +89,12 @@ struct Summoner { name: String, } -impl KBDataSource { - pub fn new(client: &ureq::Agent) -> KBDataSource { - let mut datasource = KBDataSource { - token: None, - internal_classname_mapping: IndexMap::new(), - }; - datasource.token = datasource.get_auth_token(client); - datasource.internal_classname_mapping = datasource.get_classname_mapping(client); - datasource - } +lazy_static! { + static ref TOKEN: Mutex> = Mutex::new(None); + static ref INTERNAL_CLASSNAME_MAPPING: Mutex> = Mutex::new(IndexMap::new()); +} +impl KBDataSource { // It will be better to use Result... fn get_auth_token(&self, client: &ureq::Agent) -> Option { let mut bundle = match client.get("https://koreanbuilds.net/bundle.js").call() { @@ -137,22 +131,21 @@ impl KBDataSource { } fn get_champion_response(&self, client: &ureq::Agent) -> Option { - let token = match self.token.clone() { - Some(t) => t, - None => String::new(), - }; - match client - .get("https://api.koreanbuilds.net/champions?patchid=-1") - .set("Accept", "application/json") - .set("Authorization", token.as_str()) - .call() - { - Ok(resp) => match resp.into_json() { - Ok(val) => val, + if let Some(token) = TOKEN.lock().unwrap().as_ref() { + return match client + .get("https://api.koreanbuilds.net/champions?patchid=-1") + .set("Accept", "application/json") + .set("Authorization", token.as_str()) + .call() + { + Ok(resp) => match resp.into_json() { + Ok(val) => val, + Err(_) => None, + }, Err(_) => None, - }, - Err(_) => None, + }; } + None } fn get_positions(position: Option) -> Vec { @@ -294,6 +287,16 @@ impl KBDataSource { } impl DataSource for KBDataSource { + fn init(&self, client: &ureq::Agent) { + if let Some(t) = self.get_auth_token(client) { + TOKEN.lock().unwrap().replace(t); + } + + for v in self.get_classname_mapping(client) { + INTERNAL_CLASSNAME_MAPPING.lock().unwrap().insert(v.0, v.1); + } + } + fn get_alias(&self) -> &str { "KB" } @@ -330,8 +333,8 @@ impl DataSource for KBDataSource { client: &ureq::Agent, ) -> Vec<(String, Vec, Stat)> { let mut champ_data = vec![]; - if let Some(token) = self.token.clone() { - if let Some(map_id) = self.internal_classname_mapping.get(&champ.id) { + if let Some(token) = TOKEN.lock().unwrap().as_ref() { + if let Some(map_id) = INTERNAL_CLASSNAME_MAPPING.lock().unwrap().get(&champ.id) { let data: BuildResponse = match client .get(&format!( "https://api.koreanbuilds.net/builds?chmpname={}&patchid=-2&position=COMPOSITE", @@ -361,14 +364,13 @@ impl DataSource for KBDataSource { break; } } - if let Some(b) = build { champ_data.push(self.get_build(&b)); } } } - }; + } champ_data } } @@ -379,10 +381,7 @@ mod tests { #[test] fn test_get_auth_token() { - let datasource = KBDataSource { - token: None, - internal_classname_mapping: IndexMap::new(), - }; + let datasource = KBDataSource; let client = ureq::AgentBuilder::new() .timeout(Duration::from_secs(10)) .build(); diff --git a/src/main.rs b/src/main.rs index 05bbf2c..82f1e85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ use indexmap::IndexMap; -use lazy_static::lazy_static; #[cfg(target_os = "windows")] use log::debug; use log::{error, info, LevelFilter}; @@ -75,56 +74,47 @@ fn main() -> Result<(), Box> { .init()?; info!("CGG Item Sets"); - lazy_static! { - static ref LOL_CHAMPS_DIR: PathBuf = match lol_champ_dir() { - Ok(x) => x, - Err(_e) => PathBuf::from(DEFAULT_LOL_CHAMPS_DIR), - }; - static ref CLIENT: ureq::Agent = ureq::AgentBuilder::new() - .user_agent(USER_AGENT_VALUE) - .timeout(Duration::from_secs(10)) - .build(); - static ref REALM: Realm = CLIENT - .get("https://ddragon.leagueoflegends.com/realms/euw.json") - .call() - .unwrap() - .into_json() - .unwrap(); - static ref CHAMPION: Champion = CLIENT - .get(&format!( - "https://ddragon.leagueoflegends.com/cdn/{}/data/en_US/champion.json", - REALM.v - )) - .call() - .unwrap() - .into_json() - .unwrap(); - static ref DATA_SOURCES: Vec> = vec![ - Box::new(PBDataSource), - Box::new(CGGDataSource), - Box::new(KBDataSource::new(&CLIENT)), - ]; - } + let lol_champs_dir: PathBuf = match lol_champ_dir() { + Ok(x) => x, + Err(_e) => PathBuf::from(DEFAULT_LOL_CHAMPS_DIR), + }; + info!("LoL Champs Folder: {}", lol_champs_dir.to_str().unwrap()); - info!("LoL Champs Folder: {}", LOL_CHAMPS_DIR.to_str().unwrap()); - info!("LoL version: {}", REALM.v); - info!("LoL numbers of champs: {}", CHAMPION.data.len()); + let client: ureq::Agent = ureq::AgentBuilder::new() + .user_agent(USER_AGENT_VALUE) + .timeout(Duration::from_secs(10)) + .build(); - let mut threads = vec![]; - for data_source in DATA_SOURCES.iter() { - threads.push(thread::spawn(move || { - let init = Instant::now(); - execute_data_source(&data_source, &CLIENT, &CHAMPION, &LOL_CHAMPS_DIR); - info!( - "{}: done in {} ms", - data_source.get_alias(), - init.elapsed().as_millis() - ); - })); - } - for child in threads { - let _ = child.join(); - } + let realm: Realm = client + .get("https://ddragon.leagueoflegends.com/realms/euw.json") + .call()? + .into_json()?; + info!("LoL version: {}", realm.v); + + let champion: Champion = client + .get(&format!( + "https://ddragon.leagueoflegends.com/cdn/{}/data/en_US/champion.json", + realm.v + )) + .call()? + .into_json()?; + info!("LoL numbers of champs: {}", champion.data.len()); + + static DATA_SOURCES: [&'static (dyn DataSource + Sync + Send); 3] = [ + &PBDataSource, + &CGGDataSource, + &KBDataSource, + ]; + DATA_SOURCES.par_iter().for_each(|data_source| { + + let init = Instant::now(); + execute_data_source(*data_source, &client, &champion, &lol_champs_dir); + info!( + "{}: done in {} ms", + data_source.get_alias(), + init.elapsed().as_millis() + ); + }); Ok(()) } @@ -138,11 +128,13 @@ fn get_champ_from_key(champs: &Champion, key: &str) -> Option { } fn execute_data_source( - data_source: &Box, + data_source: &(dyn DataSource + Sync + Send), client: &ureq::Agent, champion: &Champion, lol_champs_dir: &PathBuf, ) { + data_source.init(client); + let (champs, patch) = data_source.get_champs_with_positions_and_patch(&client); info!("{} version: {}", data_source.get_alias(), patch); @@ -181,7 +173,7 @@ fn execute_data_source( } fn get_and_write_item_set( - data_source: &Box, + data_source: &(dyn DataSource + Sync + Send), client: &ureq::Agent, champion: &Champion, lol_champs_dir: &PathBuf, diff --git a/src/pb_data_source.rs b/src/pb_data_source.rs index 615189b..f070481 100644 --- a/src/pb_data_source.rs +++ b/src/pb_data_source.rs @@ -6,6 +6,8 @@ use crate::ChampInfo; pub struct PBDataSource; impl DataSource for PBDataSource { + fn init(&self, _client: &ureq::Agent) {} + fn get_alias(&self) -> &str { "PB" }