Implement basic logic for syncing
This commit is contained in:
parent
3ed8c6ad71
commit
cd98f0cd26
|
@ -4,8 +4,8 @@ use std::fs::{self, OpenOptions};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
/// Return the default path to the datasets file.
|
/// Return the path to the datasets file.
|
||||||
fn default_datasets_path(config_dir: &Path) -> io::Result<PathBuf> {
|
fn datasets_path(config_dir: &Path) -> io::Result<PathBuf> {
|
||||||
let mut path = config_dir.to_owned();
|
let mut path = config_dir.to_owned();
|
||||||
path.push("ggelo");
|
path.push("ggelo");
|
||||||
|
|
||||||
|
@ -21,11 +21,12 @@ fn default_datasets_path(config_dir: &Path) -> io::Result<PathBuf> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_datasets(config_dir: &Path) -> sqlite::Result<Connection> {
|
pub fn open_datasets(config_dir: &Path) -> sqlite::Result<Connection> {
|
||||||
let path = default_datasets_path(config_dir).unwrap();
|
let path = datasets_path(config_dir).unwrap();
|
||||||
|
|
||||||
let query = "
|
let query = "
|
||||||
CREATE TABLE IF NOT EXISTS datasets (
|
CREATE TABLE IF NOT EXISTS datasets (
|
||||||
name TEXT UNIQUE NOT NULL
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
last_sync INTEGER NOT NULL DEFAULT 1
|
||||||
) STRICT;";
|
) STRICT;";
|
||||||
|
|
||||||
let connection = sqlite::open(path)?;
|
let connection = sqlite::open(path)?;
|
||||||
|
@ -71,6 +72,29 @@ pub fn new_dataset(connection: &Connection, dataset: &str) -> sqlite::Result<()>
|
||||||
connection.execute(query)
|
connection.execute(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_last_sync(connection: &Connection, dataset: &str) -> sqlite::Result<Option<u64>> {
|
||||||
|
let query = "SELECT last_sync FROM datasets WHERE name = ?";
|
||||||
|
|
||||||
|
Ok(connection
|
||||||
|
.prepare(query)?
|
||||||
|
.into_iter()
|
||||||
|
.bind((1, dataset))?
|
||||||
|
.map(|x| x.map(|r| r.read::<i64, _>("last_sync").to_owned() as u64))
|
||||||
|
.next()
|
||||||
|
.and_then(Result::ok))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_last_sync(connection: &Connection, dataset: &str, sync: u64) -> sqlite::Result<()> {
|
||||||
|
let query = "UPDATE datasets SET last_sync = :sync WHERE name = :dataset";
|
||||||
|
|
||||||
|
connection
|
||||||
|
.prepare(query)?
|
||||||
|
.into_iter()
|
||||||
|
.bind((":sync", sync as i64))?
|
||||||
|
.bind((":dataset", dataset))?
|
||||||
|
.try_for_each(|x| x.map(|_| ()))
|
||||||
|
}
|
||||||
|
|
||||||
// Score calculation
|
// Score calculation
|
||||||
|
|
||||||
/// Calculate the collective expected score for each team.
|
/// Calculate the collective expected score for each team.
|
||||||
|
@ -163,11 +187,7 @@ pub fn update_ratings(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_from_set(
|
fn update_from_set(connection: &Connection, dataset: &str, results: SetData) -> sqlite::Result<()> {
|
||||||
connection: &Connection,
|
|
||||||
dataset: &str,
|
|
||||||
results: SetData,
|
|
||||||
) -> sqlite::Result<()> {
|
|
||||||
let players_data = results.teams;
|
let players_data = results.teams;
|
||||||
add_players(connection, dataset, &players_data)?;
|
add_players(connection, dataset, &players_data)?;
|
||||||
|
|
||||||
|
@ -180,3 +200,24 @@ pub fn update_from_set(
|
||||||
);
|
);
|
||||||
update_ratings(connection, dataset, elos)
|
update_ratings(connection, dataset, elos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_from_tournament(
|
||||||
|
connection: &Connection,
|
||||||
|
dataset: &str,
|
||||||
|
results: TournamentData,
|
||||||
|
) -> sqlite::Result<()> {
|
||||||
|
results
|
||||||
|
.sets
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|set| update_from_set(connection, dataset, set))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_from_tournaments(
|
||||||
|
connection: &Connection,
|
||||||
|
dataset: &str,
|
||||||
|
results: Vec<TournamentData>,
|
||||||
|
) -> sqlite::Result<()> {
|
||||||
|
results
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|tour| update_from_tournament(connection, dataset, tour))
|
||||||
|
}
|
||||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
mod queries;
|
mod queries;
|
||||||
use queries::*;
|
use queries::*;
|
||||||
mod state;
|
|
||||||
use state::*;
|
|
||||||
mod datasets;
|
mod datasets;
|
||||||
use datasets::*;
|
use datasets::*;
|
||||||
|
|
||||||
|
@ -35,6 +34,12 @@ enum Subcommands {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
subcommand: DatasetSC,
|
subcommand: DatasetSC,
|
||||||
},
|
},
|
||||||
|
Sync {
|
||||||
|
#[arg(group = "datasets")]
|
||||||
|
names: Vec<String>,
|
||||||
|
#[arg(short, long, group = "datasets")]
|
||||||
|
all: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
@ -57,6 +62,8 @@ fn main() {
|
||||||
Subcommands::Dataset {
|
Subcommands::Dataset {
|
||||||
subcommand: DatasetSC::Delete { name },
|
subcommand: DatasetSC::Delete { name },
|
||||||
} => dataset_delete(name),
|
} => dataset_delete(name),
|
||||||
|
|
||||||
|
Subcommands::Sync { names, all } => sync(names, all, cli.auth_token),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,3 +109,41 @@ fn dataset_delete(name: Option<String>) {
|
||||||
let connection = open_datasets(&config_dir).unwrap();
|
let connection = open_datasets(&config_dir).unwrap();
|
||||||
delete_dataset(&connection, &name).unwrap();
|
delete_dataset(&connection, &name).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sync(names: Vec<String>, all: bool, auth_token: Option<String>) {
|
||||||
|
let config_dir = dirs::config_dir().unwrap();
|
||||||
|
|
||||||
|
let auth = auth_token.or_else(|| get_auth_token(&config_dir)).unwrap();
|
||||||
|
|
||||||
|
let connection = open_datasets(&config_dir).unwrap();
|
||||||
|
|
||||||
|
let names = if all {
|
||||||
|
list_datasets(&connection).unwrap()
|
||||||
|
} else {
|
||||||
|
names
|
||||||
|
};
|
||||||
|
|
||||||
|
for name in names {
|
||||||
|
let last_sync = get_last_sync(&connection, &name).unwrap().unwrap();
|
||||||
|
|
||||||
|
let results = run_query::<TournamentSets, _>(
|
||||||
|
TournamentSetsVars {
|
||||||
|
last_query: Timestamp(last_sync),
|
||||||
|
game_id: VideogameId(1),
|
||||||
|
country: None,
|
||||||
|
state: None,
|
||||||
|
},
|
||||||
|
&auth,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
update_from_tournaments(&connection, &name, results).unwrap();
|
||||||
|
|
||||||
|
let current_time = SystemTime::now()
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs();
|
||||||
|
|
||||||
|
update_last_sync(&connection, &name, current_time).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use schema::schema;
|
||||||
|
|
||||||
// Auth key
|
// Auth key
|
||||||
|
|
||||||
pub fn get_auth_key(config_dir: &Path) -> Option<String> {
|
pub fn get_auth_token(config_dir: &Path) -> Option<String> {
|
||||||
use std::env::{var, VarError};
|
use std::env::{var, VarError};
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ pub trait QueryUnwrap<Vars>: 'static + QueryBuilder<Vars> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic function for running start.gg queries
|
// Generic function for running start.gg queries
|
||||||
pub fn run_query<Builder, Vars>(vars: Vars, state: &AppState) -> Option<Builder::Unwrapped>
|
pub fn run_query<Builder, Vars>(vars: Vars, auth_token: &str) -> Option<Builder::Unwrapped>
|
||||||
where
|
where
|
||||||
Builder: QueryUnwrap<Vars>,
|
Builder: QueryUnwrap<Vars>,
|
||||||
Vars: Serialize,
|
Vars: Serialize,
|
||||||
|
@ -78,7 +78,7 @@ where
|
||||||
|
|
||||||
let response = reqwest::blocking::Client::new()
|
let response = reqwest::blocking::Client::new()
|
||||||
.post("https://api.start.gg/gql/alpha")
|
.post("https://api.start.gg/gql/alpha")
|
||||||
.header("Authorization", String::from("Bearer ") + &state.auth_token)
|
.header("Authorization", String::from("Bearer ") + auth_token)
|
||||||
.run_graphql(query);
|
.run_graphql(query);
|
||||||
|
|
||||||
Builder::unwrap_response(response.unwrap())
|
Builder::unwrap_response(response.unwrap())
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
pub struct AppState {
|
|
||||||
pub config_dir: PathBuf,
|
|
||||||
pub auth_token: String,
|
|
||||||
}
|
|
Loading…
Reference in a new issue