diff --git a/Cargo.toml b/Cargo.toml index a90dc1f..b62ec97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,16 +6,16 @@ version = "1.0.0" include = ["src/**/*"] [dependencies] -chrono = {version = "0.4.41", features = ["std"], default-features = false} -indexmap = {version = "2.2", features = ["serde", "rayon"]} +chrono = { version = "0.4.41", features = ["std"], default-features = false } +indexmap = { version = "2.2", features = ["serde", "rayon"] } log = "0.4" logsy = "1.0.1" rayon = "1.10" -regex = {version = "1.11.1", features = ["std"], default-features = false} +regex = { version = "1.11.1", features = ["std"], default-features = false } serde = "1.0" serde_derive = "1.0" -serde_json = {version = "1.0", features = ["preserve_order"]} -ureq = {version = "3.0", features = ["json"]} +serde_json = { version = "1.0", features = ["preserve_order"] } +ureq = { version = "3.0", features = ["json"] } [target.'cfg(windows)'.dependencies] winreg = { version = "0.55" } diff --git a/src/data_source.rs b/src/data_source.rs index a57e88d..3f37b71 100644 --- a/src/data_source.rs +++ b/src/data_source.rs @@ -49,13 +49,21 @@ pub struct Stat { pub patch: String, } +pub struct Data { + pub position: String, + pub items: Vec, + pub stat: Stat, +} + /// Trait for a data source that can provide champion item set data. pub trait DataSource { /// Returns the alias of the data source. fn get_alias(&self) -> &str; /// Returns the timeout for the data source. - fn get_timeout(&self) -> u64; + fn get_timeout(&self) -> u64 { + 300 + } /// Returns a map of champion IDs to their possible positions. fn get_champs_with_positions(&self, champion: &Champion) -> IndexMap>; @@ -68,12 +76,29 @@ pub trait DataSource { }) } + /// Logs missing roles for which data could not be retrieved. + fn log_missing_roles(&self, champ: &ChampInfo, positions: &[String], data: &[Data]) { + let missing_roles: Vec<_> = positions + .iter() + .filter(|pos| !data.iter().any(|build| &build.position == *pos)) + .cloned() + .collect(); + if !missing_roles.is_empty() { + error!( + "{}: Can't get data for {} at {}", + self.get_alias(), + champ.id, + missing_roles.join(", ") + ); + } + } + /// Returns champion data with win percentage for the given positions. fn get_champ_data_with_win_pourcentage( &self, champ: &ChampInfo, positions: &[String], - ) -> Vec<(String, Vec, Stat)>; + ) -> Vec; /// Writes item sets for the given champion and positions to the specified path. fn write_item_set( @@ -90,59 +115,47 @@ pub trait DataSource { ); let data = self.get_champ_data_with_win_pourcentage(champ, positions); - let missing_roles: Vec<_> = positions - .iter() - .filter(|pos| !data.iter().any(|build| &build.0 == *pos)) - .cloned() - .collect(); - if !missing_roles.is_empty() { - error!( - "{}: Can't get data for {} at {}", - self.get_alias(), - champ.id, - missing_roles.join(", ") - ); - } + self.log_missing_roles(champ, positions, &data); for build in data { let item_set = ItemSet { title: format!( "{} {} {} - {:.2}% wins - {} games - {:.2} kda", self.get_alias(), - build.0, - build.2.patch, - build.2.win_rate, - build.2.games, - build.2.kda + build.position, + build.stat.patch, + build.stat.win_rate, + build.stat.games, + build.stat.kda ), - type_: "custom".to_string(), - map: "any".to_string(), - mode: "any".to_string(), + type_: "custom".to_owned(), + map: "any".to_owned(), + mode: "any".to_owned(), priority: false, sortrank: 0, - blocks: build.1, + blocks: build.items, }; info!( "{}: Writing item set for {} at {}", self.get_alias(), champ.name, - build.0 + build.position ); let json_string = serde_json::to_string_pretty(&item_set) - .map_err(|e| format!("Failed to serialize item set: {}", e))?; + .map_err(|e| format!("Failed to serialize item set: {e}"))?; fs::write( path.join(format!( "{}_{}_{}.json", self.get_alias(), champ.id, - build.0 + build.position )), json_string, ) - .map_err(|e| format!("Failed to write item set file: {}", e))?; + .map_err(|e| format!("Failed to write item set file: {e}"))?; } Ok(()) } diff --git a/src/kb_data_source.rs b/src/kb_data_source.rs index 0481544..daa2490 100644 --- a/src/kb_data_source.rs +++ b/src/kb_data_source.rs @@ -1,10 +1,9 @@ use crate::ChampInfo; use crate::Champion as ChampionLoL; -use crate::data_source::{DataSource, Item, Stat}; +use crate::data_source::{Data, DataSource, Item, Stat}; use indexmap::IndexMap; use log::error; use serde_derive::Deserialize; -use serde_json::Value; pub struct KBDataSource { client: ureq::Agent, @@ -140,7 +139,7 @@ impl KBDataSource { let start = bundle.find(auth_marker)? + auth_marker.len(); let after_marker = bundle[start..].find('"')? + start + 1; let end = bundle[after_marker..].find('"')? + after_marker; - Some(bundle[after_marker..end].to_string()) + Some(bundle[after_marker..end].to_owned()) } fn get_champion_response(&self) -> Option { @@ -178,7 +177,7 @@ impl KBDataSource { } } - fn get_build(&self, build: &KBBuild) -> (String, Vec, Stat) { + fn get_build(&self, build: &KBBuild) -> Data { let mut starting_items: Vec = vec![]; let mut blocks = vec![]; for i in 0..6 { @@ -229,16 +228,16 @@ impl KBDataSource { ), )); - ( - build.position.position_name.to_uppercase(), - blocks, - Stat { + Data { + position: build.position.position_name.to_uppercase(), + items: blocks, + stat: Stat { win_rate: (build.wins as f32 / build.games as f32) * 100f32, games: build.games, kda: build.kda, patch: build.patch.patch_version.to_owned(), }, - ) + } } } @@ -247,10 +246,6 @@ impl DataSource for KBDataSource { "KB" } - fn get_timeout(&self) -> u64 { - 300 - } - fn get_champs_with_positions(&self, _champion: &ChampionLoL) -> IndexMap> { let mut champions = IndexMap::new(); let data: ChampionResponse = match self.get_champion_response() { @@ -269,7 +264,7 @@ impl DataSource for KBDataSource { &self, champ: &ChampInfo, position: &[String], - ) -> Vec<(String, Vec, Stat)> { + ) -> Vec { let mut champ_data = vec![]; if let Some(token) = &self.token { let url = format!( @@ -286,12 +281,12 @@ impl DataSource for KBDataSource { Ok(mut resp) => match resp.body_mut().read_json() { Ok(val) => val, Err(x) => { - error!("Cant json: {}", x); + error!("Cant json: {x}"); return vec![]; } }, Err(x) => { - error!("Call failed for URL: {}, error: {}", url, x); + error!("Call failed for URL: {url}, error: {x}"); return vec![]; } }; @@ -343,9 +338,9 @@ mod tests { key: 1, }; let result = - DATASOURCE.get_champ_data_with_win_pourcentage(&champ, &vec!["MID".to_string()]); + DATASOURCE.get_champ_data_with_win_pourcentage(&champ, &vec!["MID".to_owned()]); assert!(!result.is_empty()); - assert!(!result[0].1.is_empty()); - assert!(result[0].2.win_rate > 0.); + assert!(!result[0].items.is_empty()); + assert!(result[0].stat.win_rate > 0.); } } diff --git a/src/ms_data_source.rs b/src/ms_data_source.rs index c247419..6d8cdd4 100644 --- a/src/ms_data_source.rs +++ b/src/ms_data_source.rs @@ -2,12 +2,11 @@ use indexmap::IndexMap; use log::{error, warn}; use regex::Regex; use serde_derive::Deserialize; -use serde_json::Value; use std::sync::LazyLock; use crate::ChampInfo; use crate::Champion; -use crate::data_source::{DataSource, Stat}; +use crate::data_source::{Data, DataSource, Stat}; pub struct MSDataSource { client: ureq::Agent, @@ -76,13 +75,10 @@ fn extract_items_from_section(page: &str, section_title: &str) -> Vec { .map(|cap| cap[1].to_owned()) .collect(); } else { - warn!( - "Failed to find matching for section '{}'", - section_title - ); + warn!("Failed to find matching for section '{section_title}'"); } } - Vec::new() + vec![] } fn extract_skill_order_from_table(page: &str) -> String { @@ -145,10 +141,6 @@ impl DataSource for MSDataSource { "MS" } - fn get_timeout(&self) -> u64 { - 300 - } - fn get_champs_with_positions(&self, champion: &Champion) -> IndexMap> { let mut champs = IndexMap::new(); @@ -160,7 +152,7 @@ impl DataSource for MSDataSource { { Ok(champs) => champs, Err(e) => { - error!("Failed to fetch champions from MetaSRC: {}", e); + error!("Failed to fetch champions from MetaSRC: {e}"); return champs; } }; @@ -189,7 +181,7 @@ impl DataSource for MSDataSource { &self, champ: &ChampInfo, positions: &[String], - ) -> Vec<(String, Vec, Stat)> { + ) -> Vec { let mut builds = vec![]; let rep = self @@ -236,9 +228,9 @@ impl DataSource for MSDataSource { let items = extract_items_from_section(&page, "Item Purchase Order"); let starting_items = extract_items_from_section(&page, "Starting Items"); - builds.push(( - positions[0].to_owned(), - vec![ + builds.push(Data { + position: positions[0].to_owned(), + items: vec![ self.make_item_set( starting_items, format!( @@ -248,13 +240,13 @@ impl DataSource for MSDataSource { ), self.make_item_set(items, "Item Purchase Order".to_owned()), ], - Stat { + stat: Stat { win_rate, games, kda, patch, }, - )); + }); } else { warn!( "Failed to fetch build page for champ {} at position {}",