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::path::{Path, PathBuf};
|
||||
|
||||
/// Return the default path to the datasets file.
|
||||
fn default_datasets_path(config_dir: &Path) -> io::Result<PathBuf> {
|
||||
/// Return the path to the datasets file.
|
||||
fn datasets_path(config_dir: &Path) -> io::Result<PathBuf> {
|
||||
let mut path = config_dir.to_owned();
|
||||
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> {
|
||||
let path = default_datasets_path(config_dir).unwrap();
|
||||
let path = datasets_path(config_dir).unwrap();
|
||||
|
||||
let query = "
|
||||
CREATE TABLE IF NOT EXISTS datasets (
|
||||
name TEXT UNIQUE NOT NULL
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
last_sync INTEGER NOT NULL DEFAULT 1
|
||||
) STRICT;";
|
||||
|
||||
let connection = sqlite::open(path)?;
|
||||
|
@ -71,6 +72,29 @@ pub fn new_dataset(connection: &Connection, dataset: &str) -> sqlite::Result<()>
|
|||
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
|
||||
|
||||
/// Calculate the collective expected score for each team.
|
||||
|
@ -163,11 +187,7 @@ pub fn update_ratings(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn update_from_set(
|
||||
connection: &Connection,
|
||||
dataset: &str,
|
||||
results: SetData,
|
||||
) -> sqlite::Result<()> {
|
||||
fn update_from_set(connection: &Connection, dataset: &str, results: SetData) -> sqlite::Result<()> {
|
||||
let players_data = results.teams;
|
||||
add_players(connection, dataset, &players_data)?;
|
||||
|
||||
|
@ -180,3 +200,24 @@ pub fn update_from_set(
|
|||
);
|
||||
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 std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
mod queries;
|
||||
use queries::*;
|
||||
mod state;
|
||||
use state::*;
|
||||
mod datasets;
|
||||
use datasets::*;
|
||||
|
||||
|
@ -35,6 +34,12 @@ enum Subcommands {
|
|||
#[command(subcommand)]
|
||||
subcommand: DatasetSC,
|
||||
},
|
||||
Sync {
|
||||
#[arg(group = "datasets")]
|
||||
names: Vec<String>,
|
||||
#[arg(short, long, group = "datasets")]
|
||||
all: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
|
@ -57,6 +62,8 @@ fn main() {
|
|||
Subcommands::Dataset {
|
||||
subcommand: DatasetSC::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();
|
||||
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
|
||||
|
||||
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::fs::read_to_string;
|
||||
|
||||
|
@ -66,7 +66,7 @@ pub trait QueryUnwrap<Vars>: 'static + QueryBuilder<Vars> {
|
|||
}
|
||||
|
||||
// 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
|
||||
Builder: QueryUnwrap<Vars>,
|
||||
Vars: Serialize,
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
|
||||
let response = reqwest::blocking::Client::new()
|
||||
.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);
|
||||
|
||||
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