Implement basic player info command

This commit is contained in:
Kiana Sheibani 2023-11-26 14:25:14 -05:00
parent 3836ccfb9f
commit c06c18c0ba
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
4 changed files with 123 additions and 20 deletions

View file

@ -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<PlayerData> {
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::<String, _>("name")?,
prefix: statement.read::<Option<String>, _>("prefix")?,
slug: statement.read::<String, _>("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()
}

View file

@ -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 <kiana.a.sheibani@gmail.com>")]
#[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<String>,
},
}
#[derive(Subcommand)]
@ -89,9 +101,16 @@ enum DatasetSC {
Delete { name: Option<String> },
}
#[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<String>) {
delete_dataset(&connection, &name).unwrap_or_else(|_| error("That dataset does not exist!", 1));
}
// Players
fn player_info(dataset: Option<String>, 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::<u64>().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<String>, all: bool, auth_token: Option<String>) {
let config_dir = dirs::config_dir().unwrap();

View file

@ -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<SetConnection>,
}
@ -74,6 +74,12 @@ struct Player {
id: Option<PlayerId>,
gamer_tag: Option<String>,
prefix: Option<String>,
user: Option<User>,
}
#[derive(cynic::QueryFragment, Debug)]
struct User {
slug: Option<String>,
}
// Unwrap
@ -121,8 +127,9 @@ impl QueryUnwrap<EventSetsVars> 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()

View file

@ -23,6 +23,12 @@ struct Player {
id: Option<PlayerId>,
gamer_tag: Option<String>,
prefix: Option<String>,
user: Option<User>,
}
#[derive(cynic::QueryFragment, Debug)]
struct User {
slug: Option<String>,
}
// Unwrapping
@ -30,8 +36,9 @@ struct Player {
#[derive(Debug, Clone)]
pub struct PlayerData {
pub id: PlayerId,
pub name: Option<String>,
pub name: String,
pub prefix: Option<String>,
pub slug: String,
}
impl QueryUnwrap<PlayerInfoVars> for PlayerInfo {
@ -41,8 +48,9 @@ impl QueryUnwrap<PlayerInfoVars> 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?,
})
}
}