CGGItemSets/src/cgg_data_source.rs
2021-03-14 11:21:49 +01:00

209 lines
6.2 KiB
Rust

use indexmap::IndexMap;
use lazy_static::lazy_static;
use regex::Regex;
use serde_derive::Deserialize;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::sync::Mutex;
use crate::data_source::DataSource;
use crate::ChampInfo;
#[derive(Deserialize, Debug)]
struct BuildResponse {
lol: Lol,
}
#[derive(Deserialize, Debug)]
struct Lol {
#[serde(rename = "championsReport")]
champions_report: Vec<ChampionReport>,
}
#[derive(Deserialize, Debug)]
struct ChampionReport {
champion_id: u32,
role: String,
patch: String,
stats: Stats,
}
#[derive(Deserialize, Debug)]
struct Stats {
starting_items: Build,
core_builds: Build,
big_item_builds: Build,
skills: Build,
most_common_starting_items: Build,
most_common_core_builds: Build,
most_common_big_item_builds: Build,
most_common_skills: Build,
}
#[derive(Deserialize, Debug)]
struct Build {
build: Vec<u32>,
win_rate: f64,
games: u32,
}
#[derive(Deserialize, Debug, Clone)]
struct ChampStat {
champion_id: Option<u32>,
stats: Option<Info>,
matchups: Option<Vec<Info>>,
#[serde(rename = "winRate")]
win_rate: Option<f64>,
games: Option<u32>,
kda: Option<f64>,
}
#[derive(Deserialize, Debug, Clone)]
struct Info {
id: String,
}
lazy_static! {
static ref CHAMPIONS_REPORT: Mutex<Vec<ChampionReport>> = Mutex::new(Vec::new());
static ref CHAMPIONS_STATS: Mutex<HashMap<String, ChampStat>> = Mutex::new(HashMap::new());
}
pub struct CGGDataSource;
impl CGGDataSource {
fn make_item_set(&self, build: &Build, label: &str) -> Value {
json!({
"items": build.build.iter().map(|x| json!({"id": x.to_string(), "count": 1})).collect::<Vec<Value>>(),
"type": format!("{} ({:.2}% - {} games)", label, build.win_rate * 100., build.games)
})
}
fn make_item_set_from_list(&self, build: &Build, label: &str, skills: &Build) -> Value {
let key_order = skills
.build
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("");
self.make_item_set(build, [label, &key_order.as_str()].join(" ").as_str())
}
}
impl DataSource for CGGDataSource {
fn get_alias(&self) -> &str {
"CGG"
}
fn get_timeout(&self) -> u64 {
0
}
fn get_champs_with_positions_and_patch(
&self,
client: &ureq::Agent,
) -> (IndexMap<String, Vec<String>>, String) {
let req = client.get("https://champion.gg").call().unwrap();
lazy_static! {
static ref RE: Regex =
Regex::new(r"(?m)^\s+window.__PRELOADED_STATE__ = (.*);$").unwrap();
static ref RE2: Regex =
Regex::new(r"(?m)^\s+window.__FLASH_CMS_APOLLO_STATE__ = (.*);$").unwrap();
}
let page = &req.into_string().unwrap();
let datas: BuildResponse =
serde_json::from_str(&RE.captures(&page).unwrap()[1].replace("undefined", "null"))
.unwrap();
let champs_stats: HashMap<String, ChampStat> =
serde_json::from_str(&RE2.captures(&page).unwrap()[1].replace("undefined", "null"))
.unwrap();
for entry in champs_stats.iter() {
CHAMPIONS_STATS
.lock()
.unwrap()
.insert(entry.0.clone(), entry.1.clone());
}
let patch = datas.lol.champions_report[0].patch.clone();
let mut champions: IndexMap<String, Vec<String>> = IndexMap::new();
for champ in &datas.lol.champions_report {
let id = champ.champion_id.to_string();
let mut roles: Vec<String> = Vec::new();
if champions.contains_key(&id) {
let c = champions.get(&id).unwrap();
let mut new_roles = c.clone();
new_roles.push(champ.role.clone());
} else {
roles.push(champ.role.clone());
}
champions.insert(id, roles);
}
for report in datas.lol.champions_report {
CHAMPIONS_REPORT.lock().unwrap().push(report);
}
(champions, patch)
}
fn get_champ_data_with_win_pourcentage(
&self,
champ: &ChampInfo,
position: &str,
_client: &ureq::Agent,
) -> Option<(Vec<Value>, f64)> {
let mut some_champ: Option<&ChampionReport> = None;
let reports = CHAMPIONS_REPORT.lock().unwrap();
for champion in reports.iter() {
if champion.champion_id.to_string() == champ.key && champion.role == position {
some_champ = Some(champion);
}
}
if let Some(champ) = some_champ {
let mut blocks = vec![];
blocks.push(self.make_item_set_from_list(
&champ.stats.starting_items,
"Highest % Win Starting Items | Skills: ",
&champ.stats.skills,
));
blocks.push(
self.make_item_set(&champ.stats.core_builds, "Highest % Win Core Build Path:"),
);
blocks
.push(self.make_item_set(&champ.stats.big_item_builds, "Highest % Win Big Items:"));
blocks.push(self.make_item_set_from_list(
&champ.stats.most_common_starting_items,
"Most Frequent Starting Items | Skills: ",
&champ.stats.most_common_skills,
));
blocks.push(self.make_item_set(
&champ.stats.most_common_core_builds,
"Most Frequent Build Path",
));
blocks.push(self.make_item_set(
&champ.stats.most_common_big_item_builds,
"Most Frequent Big Items:",
));
let mut key: String = String::new();
let champs_stats = CHAMPIONS_STATS.lock().unwrap();
for val in champs_stats.values() {
if val.champion_id.is_some() && val.champion_id.unwrap() == champ.champion_id {
key = val.stats.as_ref().unwrap().id.clone();
}
}
let win_rate = champs_stats.get(&key).unwrap().win_rate;
return Some((blocks, win_rate.unwrap()));
}
None
}
}