diff --git a/src/datasets.rs b/src/datasets.rs index 264a600..155b930 100644 --- a/src/datasets.rs +++ b/src/datasets.rs @@ -126,6 +126,7 @@ pub fn new_dataset( id INTEGER PRIMARY KEY, name TEXT, prefix TEXT, + slug TEXT NOT NULL, last_played INTEGER NOT NULL, deviation REAL NOT NULL, volatility REAL NOT NULL, @@ -248,20 +249,49 @@ pub fn add_players( ) -> sqlite::Result<()> { let query = format!( r#"INSERT OR IGNORE INTO "{}_players" - (id, name, prefix, last_played, deviation, volatility, sets_won, sets_lost) - VALUES (?, ?, ?, ?, 2.01, 0.06, '', '')"#, + (id, name, prefix, slug, last_played, deviation, volatility, sets_won, sets_lost) + VALUES (?, ?, ?, ?, ?, 2.01, 0.06, '', '')"#, dataset ); teams.iter().try_for_each(|team| { - team.iter().try_for_each(|PlayerData { id, name, prefix }| { - let mut statement = connection.prepare(&query)?; - statement.bind((1, id.0 as i64))?; - statement.bind((2, name.as_ref().map(|x| &x[..])))?; - statement.bind((3, prefix.as_ref().map(|x| &x[..])))?; - statement.bind((4, time.0 as i64))?; - statement.into_iter().try_for_each(|x| x.map(|_| ())) - }) + team.iter().try_for_each( + |PlayerData { + id, + name, + prefix, + slug, + }| { + let mut statement = connection.prepare(&query)?; + statement.bind((1, id.0 as i64))?; + statement.bind((2, &name[..]))?; + statement.bind((3, prefix.as_ref().map(|x| &x[..])))?; + statement.bind((4, &slug[..]))?; + statement.bind((5, time.0 as i64))?; + statement.into_iter().try_for_each(|x| x.map(|_| ())) + }, + ) + }) +} + +pub fn get_player( + connection: &Connection, + dataset: &str, + player: PlayerId, +) -> sqlite::Result { + let query = format!( + r#"SELECT name, prefix, slug FROM "{}_players" WHERE id = ?"#, + dataset + ); + + let mut statement = connection.prepare(&query)?; + statement.bind((1, player.0 as i64))?; + statement.next()?; + Ok(PlayerData { + id: player, + name: statement.read::("name")?, + prefix: statement.read::, _>("prefix")?, + slug: statement.read::("slug")?, }) } @@ -599,8 +629,9 @@ CREATE TABLE IF NOT EXISTS datasets ( (1..=num) .map(|i| PlayerData { id: PlayerId(i), - name: Some(format!("{}", i)), + name: format!("{}", i), prefix: None, + slug: String::from("a"), }) .collect() } diff --git a/src/main.rs b/src/main.rs index 1503e08..cfb4c31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ #![feature(extend_one)] use clap::{Parser, Subcommand}; -use std::io::{self, Write}; use std::path::PathBuf; use std::time::SystemTime; use time_format::strftime_utc; @@ -23,7 +22,7 @@ use util::*; #[command(name = "StartRNR")] #[command(author = "Kiana Sheibani ")] #[command(version = "0.2.0")] -#[command(about = "StartRNR - Elo rating calculator for start.gg tournaments", long_about = None)] +#[command(about = "StartRNR - Rating system for video games based on start.gg", long_about = None)] struct Cli { #[command(subcommand)] subcommand: Subcommands, @@ -63,8 +62,8 @@ enum Subcommands { #[command( about = "Sync player ratings", long_about = "Pull recent tournament data off of start.gg and use it to -update the network. This command will automatically keep track of the last time each -dataset was synced to ensure that each tournament is only accounted for once." +update player ratings. This command will automatically keep track of the last time +each dataset was synced to ensure that each tournament is only accounted for once." )] Sync { #[arg( @@ -77,6 +76,19 @@ created if it does not already exist." #[arg(short, long, help = "Sync all stored databases")] all: bool, }, + #[command(about = "Access player information")] + Player { + #[command(subcommand)] + subcommand: PlayerSC, + #[arg( + short, + long, + value_name = "DATASET", + global = true, + help = "The dataset to access" + )] + dataset: Option, + }, } #[derive(Subcommand)] @@ -89,9 +101,16 @@ enum DatasetSC { Delete { name: Option }, } +#[derive(Subcommand)] +enum PlayerSC { + #[command(about = "Get info of player")] + Info { player: String }, +} + fn main() { let cli = Cli::parse(); + #[allow(unreachable_patterns)] match cli.subcommand { Subcommands::Dataset { subcommand: DatasetSC::List, @@ -103,10 +122,19 @@ fn main() { subcommand: DatasetSC::Delete { name }, } => dataset_delete(name), + Subcommands::Player { + subcommand: PlayerSC::Info { player }, + dataset, + } => player_info(dataset, player), + Subcommands::Sync { datasets, all } => sync(datasets, all, cli.auth_token), + + _ => println!("This feature is currently unimplemented."), } } +// Datasets + fn dataset_list() { let config_dir = dirs::config_dir().expect("Could not determine config directory"); @@ -431,6 +459,35 @@ fn dataset_delete(name: Option) { delete_dataset(&connection, &name).unwrap_or_else(|_| error("That dataset does not exist!", 1)); } +// Players + +fn player_info(dataset: Option, player: String) { + let config_dir = dirs::config_dir().expect("Could not determine config directory"); + let dataset = dataset.unwrap_or_else(|| String::from("default")); + let connection = + open_datasets(&config_dir).unwrap_or_else(|_| error("Could not open datasets file", 2)); + + let player_id = PlayerId(player.parse::().unwrap()); + + let PlayerData { + id, + name, + prefix, + slug, + } = get_player(&connection, &dataset, player_id).unwrap(); + + let (deviation, volatility, last_played) = + get_player_data(&connection, &dataset, player_id).unwrap(); + + print!("\n\x1b]8;;https://www.start.gg/{}\x1b\\", slug); + if let Some(pre) = prefix { + print!("\x1b[2m{}\x1b[0m ", pre); + } + println!("\x1b[1m{}\x1b[0m\x1b]8;;\x1b\\ ({})", name, id.0); +} + +// Sync + fn sync(datasets: Vec, all: bool, auth_token: Option) { let config_dir = dirs::config_dir().unwrap(); diff --git a/src/queries/event_sets.rs b/src/queries/event_sets.rs index 7f4f223..ed4f150 100644 --- a/src/queries/event_sets.rs +++ b/src/queries/event_sets.rs @@ -25,7 +25,7 @@ pub struct EventSets { #[derive(cynic::QueryFragment, Debug)] #[cynic(variables = "EventSetsVars")] struct Event { - #[arguments(page: $page, perPage: 30, sortType: RECENT)] + #[arguments(page: $page, perPage: 25, sortType: RECENT)] sets: Option, } @@ -74,6 +74,12 @@ struct Player { id: Option, gamer_tag: Option, prefix: Option, + user: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +struct User { + slug: Option, } // Unwrap @@ -121,8 +127,9 @@ impl QueryUnwrap for EventSets { let p_ = p.player?; Some(PlayerData { id: p_.id?, - name: p_.gamer_tag, - prefix: p_.prefix, + name: p_.gamer_tag?, + prefix: p_.prefix.filter(|pr| !pr.is_empty()), + slug: p_.user?.slug?, }) }) .try_collect() diff --git a/src/queries/player_info.rs b/src/queries/player_info.rs index 0d8085d..eb86987 100644 --- a/src/queries/player_info.rs +++ b/src/queries/player_info.rs @@ -23,6 +23,12 @@ struct Player { id: Option, gamer_tag: Option, prefix: Option, + user: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +struct User { + slug: Option, } // Unwrapping @@ -30,8 +36,9 @@ struct Player { #[derive(Debug, Clone)] pub struct PlayerData { pub id: PlayerId, - pub name: Option, + pub name: String, pub prefix: Option, + pub slug: String, } impl QueryUnwrap for PlayerInfo { @@ -41,8 +48,9 @@ impl QueryUnwrap for PlayerInfo { let player = response.data?.player?; Some(PlayerData { id: player.id?, - name: player.gamer_tag, + name: player.gamer_tag?, prefix: player.prefix.filter(|pr| !pr.is_empty()), + slug: player.user?.slug?, }) } }