Add dataset intervals

This commit is contained in:
Kiana Sheibani 2024-01-02 01:38:28 -05:00
parent d39c280310
commit 3368457096
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
5 changed files with 272 additions and 44 deletions

142
Cargo.lock generated
View file

@ -29,6 +29,21 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.5.0"
@ -155,6 +170,20 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.48.5",
]
[[package]]
name = "clap"
version = "4.4.5"
@ -594,6 +623,29 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -1154,6 +1206,7 @@ dependencies = [
name = "startrnr"
version = "0.2.0"
dependencies = [
"chrono",
"clap",
"cynic",
"cynic-codegen",
@ -1163,7 +1216,6 @@ dependencies = [
"schema",
"serde",
"sqlite",
"time-format",
]
[[package]]
@ -1233,12 +1285,6 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "time-format"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42baec394ad2773a90e037d7b6dfc7518d1f121b9dbaeebad42e19568c39f196"
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1504,13 +1550,22 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.5",
]
[[package]]
@ -1519,13 +1574,28 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
@ -1534,42 +1604,84 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winreg"
version = "0.50.0"

View file

@ -12,7 +12,7 @@ path = "src/main.rs"
[dependencies]
# CLI
clap = { version = "4.4", features = ["derive"] }
time-format = "1.1"
chrono = "0.4"
# GraphQL schema
schema.path = "schema"

View file

@ -4,6 +4,8 @@ use std::fs::{self, OpenOptions};
use std::path::{Path, PathBuf};
pub struct DatasetMetadata {
pub start: Timestamp,
pub end: Option<Timestamp>,
pub last_sync: Timestamp,
pub game_id: VideogameId,
@ -41,6 +43,8 @@ pub fn open_datasets(config_dir: &Path) -> sqlite::Result<Connection> {
let query = "
CREATE TABLE IF NOT EXISTS datasets (
name TEXT UNIQUE NOT NULL,
start INTEGER NOT NULL,
end INTEGER,
last_sync INTEGER NOT NULL,
game_id INTEGER NOT NULL,
game_name TEXT NOT NULL,
@ -100,6 +104,10 @@ pub fn list_datasets(connection: &Connection) -> sqlite::Result<Vec<(String, Dat
Ok((
r_.read::<&str, _>("name").to_owned(),
DatasetMetadata {
start: Timestamp(r_.read::<i64, _>("start") as u64),
end: r_
.read::<Option<i64>, _>("end")
.map(|x| Timestamp(x as u64)),
last_sync: Timestamp(r_.read::<i64, _>("last_sync") as u64),
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
game_name: r_.read::<&str, _>("game_name").to_owned(),
@ -150,7 +158,7 @@ pub fn new_dataset(
dataset: &str,
metadata: DatasetMetadata,
) -> sqlite::Result<()> {
let query1 = r#"INSERT INTO datasets VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#;
let query1 = r#"INSERT INTO datasets VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#;
let query2 = format!(
r#"CREATE TABLE "{0}_players" (
id INTEGER PRIMARY KEY REFERENCES players,
@ -193,17 +201,19 @@ CREATE INDEX "{0}_network_B" ON "{0}_network" (player_B);"#,
.prepare(query1)?
.into_iter()
.bind((1, dataset))?
.bind((2, metadata.last_sync.0 as i64))?
.bind((3, metadata.game_id.0 as i64))?
.bind((4, &metadata.game_name[..]))?
.bind((5, &metadata.game_slug[..]))?
.bind((6, metadata.country.as_deref()))?
.bind((7, metadata.state.as_deref()))?
.bind((8, metadata.set_limit as i64))?
.bind((9, metadata.decay_rate))?
.bind((10, metadata.adj_decay_rate))?
.bind((11, metadata.period))?
.bind((12, metadata.tau))?
.bind((2, metadata.start.0 as i64))?
.bind((3, metadata.end.map(|x| x.0 as i64)))?
.bind((4, metadata.last_sync.0 as i64))?
.bind((5, metadata.game_id.0 as i64))?
.bind((6, &metadata.game_name[..]))?
.bind((7, &metadata.game_slug[..]))?
.bind((8, metadata.country.as_deref()))?
.bind((9, metadata.state.as_deref()))?
.bind((10, metadata.set_limit as i64))?
.bind((11, metadata.decay_rate))?
.bind((12, metadata.adj_decay_rate))?
.bind((13, metadata.period))?
.bind((14, metadata.tau))?
.try_for_each(|x| x.map(|_| ()))?;
connection.execute(query2)
@ -223,6 +233,10 @@ pub fn get_metadata(
.map(|r| {
let r_ = r?;
Ok(DatasetMetadata {
start: Timestamp(r_.read::<i64, _>("start") as u64),
end: r_
.read::<Option<i64>, _>("end")
.map(|x| Timestamp(x as u64)),
last_sync: Timestamp(r_.read::<i64, _>("last_sync") as u64),
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
game_name: r_.read::<&str, _>("game_name").to_owned(),
@ -748,6 +762,8 @@ CREATE TABLE IF NOT EXISTS sets (
pub fn metadata() -> DatasetMetadata {
DatasetMetadata {
start: Timestamp(1),
end: None,
last_sync: Timestamp(1),
game_id: VideogameId(0),
game_name: String::from("Test Game"),

View file

@ -1,10 +1,10 @@
#![feature(iterator_try_collect)]
#![feature(extend_one)]
use chrono::{Local, TimeZone, Utc};
use clap::{Parser, Subcommand};
use sqlite::*;
use std::path::PathBuf;
use time_format::strftime_utc;
use std::{cmp::min, path::PathBuf};
mod queries;
use queries::*;
@ -117,7 +117,6 @@ fn main() {
let connection =
open_datasets(&config_dir).unwrap_or_else(|_| error("Could not open datasets file", 2));
#[allow(unreachable_patterns)]
match cli.subcommand {
Subcommands::Dataset {
subcommand: DatasetSC::List,
@ -171,15 +170,42 @@ fn dataset_list(connection: &Connection) {
println!("(Global)");
}
if metadata.last_sync.0 == 1 {
let start = if metadata.start.0 != 1 {
Some(
Utc.timestamp_opt(metadata.start.0 as i64, 0)
.unwrap()
.format("%m/%d/%Y"),
)
} else {
None
};
let end = metadata
.end
.map(|x| Utc.timestamp_opt(x.0 as i64, 0).unwrap().format("%m/%d/%Y"));
match (start, end) {
(None, None) => (),
(Some(s), None) => println!("after {}", s),
(None, Some(e)) => println!("until {}", e),
(Some(s), Some(e)) => println!("{} - {}", s, e),
}
if metadata.last_sync == metadata.start {
print!("\x1b[1m\x1b[91mUnsynced\x1b[0m");
} else if Some(metadata.last_sync) == metadata.end {
print!("\x1b[1m\x1b[92mComplete\x1b[0m");
} else {
print!(
"\x1b[1mLast synced:\x1b[0m {}",
strftime_utc("%b %e, %Y %I:%M %p", metadata.last_sync.0 as i64).unwrap()
Local
.timestamp_opt(metadata.last_sync.0 as i64, 0)
.unwrap()
.format("%b %e, %Y %r")
);
}
if current_time().0 - metadata.last_sync.0 > SECS_IN_WEEK {
if current_time().0 - metadata.last_sync.0 > SECS_IN_WEEK
&& Some(metadata.last_sync) != metadata.end
{
if name == "default" {
print!(" - \x1b[33mRun 'startrnr sync' to update!\x1b[0m");
} else {
@ -300,6 +326,70 @@ State/province to track ratings for (leave empty for none): "
None
};
// Interval
print!(
"
\x1b[1mStart Date\x1b[0m
The rating system will process tournaments starting at this date. If only a year
is entered, the date will be the start of that year.
Start date (year, m/y, or m/d/y): "
);
let start = {
let string = read_string();
if string.is_empty() {
Timestamp(1)
} else if string.chars().all(|c| c.is_ascii_digit() || c == '/') {
if let Some((y, m, d)) = match string.split('/').collect::<Vec<_>>()[..] {
[] => None,
[y] => Some((y.parse().unwrap(), 1, 1)),
[m, y] => Some((y.parse().unwrap(), m.parse().unwrap(), 1)),
[m, d, y] => Some((y.parse().unwrap(), m.parse().unwrap(), d.parse().unwrap())),
_ => error("Input is not a date", 1),
} {
Timestamp(Utc.with_ymd_and_hms(y, m, d, 0, 1, 1).unwrap().timestamp() as u64)
} else {
Timestamp(1)
}
} else {
error("Input is not a date", 1);
}
};
print!(
"
\x1b[1mEnd Date\x1b[0m
The rating system will stop processing tournaments when it reaches this date. If
only a year is entered, the date will be the end of that year.
End date (year, m/y, or m/d/y): "
);
let end = {
let string = read_string();
if string.is_empty() {
None
} else if string.chars().all(|c| c.is_ascii_digit() || c == '/') {
if let Some((y, m, d)) = match string.split('/').collect::<Vec<_>>()[..] {
[] => None,
[y] => Some((y.parse().unwrap(), 12, 31)),
[m, y] => Some((y.parse().unwrap(), m.parse().unwrap(), 30)),
[m, d, y] => Some((y.parse().unwrap(), m.parse().unwrap(), d.parse().unwrap())),
_ => error("Input is not a date", 1),
} {
Some(Timestamp(
Utc.with_ymd_and_hms(y, m, d, 11, 59, 59)
.unwrap()
.timestamp() as u64,
))
} else {
None
}
} else {
error("Input is not a date", 1);
}
};
// Set Limit
let mut set_limit = 0;
@ -426,7 +516,9 @@ Tau constant (default 0.4): "
connection,
&name,
DatasetMetadata {
last_sync: Timestamp(1),
start,
end,
last_sync: start,
game_id,
game_name,
game_slug,
@ -663,14 +755,22 @@ fn sync(connection: &Connection, auth: String, datasets: Vec<String>, all: bool)
let current_time = current_time();
for dataset in datasets {
let dataset_config = get_metadata(connection, &dataset)
let dataset_metadata = get_metadata(connection, &dataset)
.expect("Error communicating with SQLite")
.unwrap_or_else(|| error(&format!("Dataset {} does not exist!", dataset), 1));
sync_dataset(connection, &dataset, dataset_config, current_time, &auth)
let before = dataset_metadata
.end
.map(|end| min(end, current_time))
.unwrap_or(current_time);
sync_dataset(connection, &dataset, dataset_metadata, before, &auth)
.expect("Error communicating with SQLite");
update_last_sync(connection, &dataset, current_time)
.expect("Error communicating with SQLite");
update_last_sync(connection, &dataset, before).expect("Error communicating with SQLite");
}
}
fn ranking_create(connection: &Connection, dataset: Option<String>) {
let dataset = dataset.unwrap_or_else(|| String::from("default"));
}

View file

@ -125,7 +125,7 @@ fn get_event_sets(event: EventId, auth: &str) -> Option<Vec<SetData>> {
fn get_tournament_events(
metadata: &DatasetMetadata,
current_time: Timestamp,
before: Timestamp,
auth: &str,
) -> Option<Vec<EventData>> {
println!("Accessing tournaments...");
@ -135,7 +135,7 @@ fn get_tournament_events(
let tour_response = run_query::<TournamentEvents, _>(
TournamentEventsVars {
after_date: after,
before_date: current_time,
before_date: before,
game_id: metadata.game_id,
country: metadata.country.as_deref(),
state: metadata.state.as_deref(),
@ -160,7 +160,7 @@ fn get_tournament_events(
let next_response = run_query::<TournamentEvents, _>(
TournamentEventsVars {
after_date: after,
before_date: current_time,
before_date: before,
game_id: metadata.game_id,
country: metadata.country.as_deref(),
state: metadata.state.as_deref(),
@ -304,10 +304,10 @@ pub fn sync_dataset(
connection: &Connection,
dataset: &str,
metadata: DatasetMetadata,
current_time: Timestamp,
before: Timestamp,
auth: &str,
) -> sqlite::Result<()> {
let events = get_tournament_events(&metadata, current_time, auth)
let events = get_tournament_events(&metadata, before, auth)
.unwrap_or_else(|| error("Could not access start.gg", 1));
connection.execute("BEGIN;")?;