CGGItemSets/src/kb_data_source.rs

391 lines
12 KiB
Rust
Raw Normal View History

use crate::data_source::{Build, DataSource, Item};
2021-03-10 12:22:00 +01:00
#[cfg(test)]
use crate::time::Duration;
use indexmap::IndexMap;
use regex::Regex;
use serde_derive::Deserialize;
use serde_json::{json, Value};
2021-03-13 23:02:26 +01:00
use crate::ChampInfo;
pub struct KBDataSource {
token: Option<String>,
internal_classname_mapping: IndexMap<String, String>,
}
#[derive(Deserialize, Debug)]
struct ChampionResponse {
patches: Vec<Patch>,
champions: Vec<Champion>,
}
#[derive(Deserialize, Debug)]
struct Patch {
enabled: bool,
#[serde(rename = "patchVersion")]
patch_version: String,
patchid: u32,
start: String,
}
#[derive(Deserialize, Debug)]
struct Champion {
id: u32,
name: String,
#[serde(rename = "className")]
classname: String,
builds: Option<Position>,
}
#[derive(Deserialize, Debug)]
struct Position {
bot: u16,
jungle: u16,
mid: u16,
support: u16,
top: u16,
}
#[derive(Deserialize, Debug)]
struct BuildResponse {
builds2: Vec<KBBuild>,
}
#[derive(Deserialize, Debug)]
struct KBBuild {
item0: KBItem,
item1: KBItem,
item2: KBItem,
item3: KBItem,
item4: KBItem,
item5: KBItem,
item6: KBItem,
#[serde(rename = "startItem0")]
start_item0: KBItem,
#[serde(rename = "startItem1")]
start_item1: KBItem,
#[serde(rename = "startItem2")]
start_item2: KBItem,
#[serde(rename = "startItem3")]
start_item3: KBItem,
#[serde(rename = "startItem4")]
start_item4: KBItem,
#[serde(rename = "startItem5")]
start_item5: KBItem,
#[serde(rename = "skillOrder")]
skill_order: String,
wins: f64,
games: f64,
summoner: Summoner,
}
#[derive(Deserialize, Debug)]
struct KBItem {
#[serde(rename = "itemId")]
item_id: u32,
name: String,
}
#[derive(Deserialize, Debug)]
struct Summoner {
name: String,
}
impl KBDataSource {
2021-03-10 12:22:00 +01:00
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
}
// It will be better to use Result...
2021-03-10 12:22:00 +01:00
fn get_auth_token(&self, client: &ureq::Agent) -> Option<String> {
let bundle = match client.get("https://koreanbuilds.net/bundle.js").call() {
Ok(resp) => match resp.into_string() {
Ok(val) => val,
Err(_) => return None,
},
Err(_) => return None,
};
let regex = match Regex::new(r##"Authorization:\s*"(\w+)""##) {
Ok(reg) => reg,
Err(_) => return None,
};
let result = match regex.captures(&bundle) {
Some(res) => res,
None => return None,
};
return match result.get(1) {
Some(token) => Some(token.as_str().to_string()),
None => None,
};
}
2021-03-10 12:22:00 +01:00
fn get_classname_mapping(&self, client: &ureq::Agent) -> IndexMap<String, String> {
let mut mapping = IndexMap::new();
2021-03-11 00:00:04 +01:00
if let Some(data) = self.get_champion_response(client) {
for champ in data.champions {
mapping.insert(champ.classname, champ.name);
}
};
mapping
}
2021-03-10 12:22:00 +01:00
fn get_champion_response(&self, client: &ureq::Agent) -> Option<ChampionResponse> {
let token = match self.token.clone() {
Some(t) => t,
2021-03-11 00:00:04 +01:00
None => String::new(),
};
match client
.get("https://api.koreanbuilds.net/champions?patchid=-1")
2021-03-10 12:22:00 +01:00
.set("Accept", "application/json")
.set("Authorization", token.as_str())
.call()
{
2021-03-10 12:22:00 +01:00
Ok(resp) => match resp.into_json() {
2021-03-11 00:00:04 +01:00
Ok(val) => val,
Err(_) => None,
},
2021-03-11 00:00:04 +01:00
Err(_) => None,
}
}
fn get_positions(position: Option<Position>) -> Vec<String> {
let mut positions = Vec::new();
2021-03-11 00:00:04 +01:00
if let Some(pos) = position {
if pos.top > 0 {
positions.push("TOP".to_owned());
}
if pos.jungle > 0 {
positions.push("JUNGLE".to_owned());
}
if pos.mid > 0 {
positions.push("MID".to_owned());
}
if pos.bot > 0 {
positions.push("BOT".to_owned());
}
if pos.support > 0 {
positions.push("SUPPORT".to_owned());
}
}
positions
}
}
impl DataSource for KBDataSource {
fn get_alias(&self) -> &str {
"KB"
}
fn get_champs_with_positions_and_patch(
&self,
2021-03-10 12:22:00 +01:00
client: &ureq::Agent,
) -> (IndexMap<String, Vec<String>>, String) {
let mut champions = IndexMap::new();
let data: ChampionResponse = match self.get_champion_response(client) {
Some(val) => val,
None => {
return (champions, String::new());
}
};
let patch = match data.patches.get(0) {
Some(p) => p.patch_version.clone(),
None => return (champions, String::new()),
};
for champ in data.champions {
champions.insert(champ.classname, KBDataSource::get_positions(champ.builds));
}
(champions, patch)
}
fn get_champ_data_with_win_pourcentage(
&self,
2021-03-13 23:02:26 +01:00
champ: &ChampInfo,
position: &str,
2021-03-10 12:22:00 +01:00
client: &ureq::Agent,
) -> Option<(Vec<Value>, f64)> {
let token = match self.token.clone() {
Some(t) => t,
None => return None,
};
2021-03-13 23:02:26 +01:00
let map_id = match self.internal_classname_mapping.get(&champ.id) {
Some(m_id) => m_id,
None => return None,
};
let data: BuildResponse = match client
.get(&format!(
"https://api.koreanbuilds.net/builds?chmpname={}&patchid=-2&position={}",
map_id, position
))
2021-03-10 12:22:00 +01:00
.set("Accept", "application/json")
.set("Authorization", token.as_str())
.call()
{
2021-03-10 12:22:00 +01:00
Ok(resp) => match resp.into_json() {
Ok(val) => val,
Err(_) => {
return None;
}
},
Err(_) => {
return None;
}
};
let mut blocks = vec![];
2021-03-11 00:00:04 +01:00
let mut winrate = 0.0;
if data.builds2.len() > 0 {
winrate = (data.builds2[0].wins / data.builds2[0].games) * 100.;
let mut starting_items: Vec<Item> = vec![];
if data.builds2[0].start_item0.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item0.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].start_item1.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item1.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].start_item2.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item2.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].start_item3.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item3.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].start_item4.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item4.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].start_item5.item_id != 0 {
starting_items.push(Item {
id: data.builds2[0].start_item5.item_id.to_string(),
count: 1,
})
}
blocks.push(json!(Build {
type_: format!(
"Early game items | skillOrder : {}",
data.builds2[0].skill_order
),
items: starting_items
}));
let mut final_items: Vec<Item> = vec![];
if data.builds2[0].item0.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item0.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item1.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item1.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item2.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item2.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item3.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item3.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item4.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item4.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item5.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item5.item_id.to_string(),
count: 1,
})
}
if data.builds2[0].item6.item_id != 0 {
final_items.push(Item {
id: data.builds2[0].item6.item_id.to_string(),
count: 1,
})
}
blocks.push(json!(Build {
type_: format!(
"Item order by time finished | Summoner : {}",
data.builds2[0].summoner.name
),
items: final_items
}));
}
Some((blocks, winrate))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_auth_token() {
let datasource = KBDataSource {
token: None,
internal_classname_mapping: IndexMap::new(),
};
2021-03-10 12:22:00 +01:00
let client = ureq::AgentBuilder::new()
.timeout(Duration::from_secs(10))
2021-03-10 12:22:00 +01:00
.build();
match datasource.get_auth_token(&client) {
Some(token) => assert!(token.len() > 0),
None => assert!(false),
};
}
#[test]
fn test_get_champs_with_positions_and_patch() {
2021-03-10 12:22:00 +01:00
let client = ureq::AgentBuilder::new()
.timeout(Duration::from_secs(10))
2021-03-10 12:22:00 +01:00
.build();
let datasource = KBDataSource::new(&client);
let champs_with_positions_and_patch =
datasource.get_champs_with_positions_and_patch(&client);
assert!(champs_with_positions_and_patch.0.len() > 0);
}
#[test]
fn test_get_champ_data_with_win_pourcentage() {
2021-03-10 12:22:00 +01:00
let client = ureq::AgentBuilder::new()
.timeout(Duration::from_secs(10))
2021-03-10 12:22:00 +01:00
.build();
let datasource = KBDataSource::new(&client);
2021-03-13 23:02:26 +01:00
let champ = ChampInfo{id: String::from("Aatrox"), name: String::from("Aatrox"), key: String::from("1")};
let result = datasource.get_champ_data_with_win_pourcentage(&champ, "TOP", &client);
assert!(result.is_some());
match result {
Some(value) => {
assert!(value.0.len() > 0);
assert!(value.1 > 0.);
}
None => assert!(false),
}
}
}