Compare commits
10 commits
d33aa89ff6
...
aed935e1ac
Author | SHA1 | Date | |
---|---|---|---|
Kiana Sheibani | aed935e1ac | ||
Kiana Sheibani | ff2ede0178 | ||
Kiana Sheibani | e05f117def | ||
Kiana Sheibani | 3368457096 | ||
Kiana Sheibani | d39c280310 | ||
Kiana Sheibani | 26c2813b09 | ||
Kiana Sheibani | 54696c1b0e | ||
Kiana Sheibani | 47da06e3d6 | ||
Kiana Sheibani | ebec5f086d | ||
Kiana Sheibani | 3e8c79b5f0 |
142
Cargo.lock
generated
142
Cargo.lock
generated
|
@ -29,6 +29,21 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
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]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -155,6 +170,20 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.5"
|
version = "4.4.5"
|
||||||
|
@ -594,6 +623,29 @@ dependencies = [
|
||||||
"tokio-native-tls",
|
"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]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1154,6 +1206,7 @@ dependencies = [
|
||||||
name = "startrnr"
|
name = "startrnr"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"cynic",
|
"cynic",
|
||||||
"cynic-codegen",
|
"cynic-codegen",
|
||||||
|
@ -1163,7 +1216,6 @@ dependencies = [
|
||||||
"schema",
|
"schema",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlite",
|
"sqlite",
|
||||||
"time-format",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1233,12 +1285,6 @@ dependencies = [
|
||||||
"syn 2.0.29",
|
"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]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -1504,13 +1550,22 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1519,13 +1574,28 @@ version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.48.5",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.48.5",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.48.5",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.48.5",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
"windows_x86_64_msvc",
|
"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]]
|
[[package]]
|
||||||
|
@ -1534,42 +1604,84 @@ version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
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]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
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]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
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]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.50.0"
|
version = "0.50.0"
|
||||||
|
|
|
@ -12,7 +12,7 @@ path = "src/main.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# CLI
|
# CLI
|
||||||
clap = { version = "4.4", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
time-format = "1.1"
|
chrono = "0.4"
|
||||||
|
|
||||||
# GraphQL schema
|
# GraphQL schema
|
||||||
schema.path = "schema"
|
schema.path = "schema"
|
||||||
|
|
28
README.md
28
README.md
|
@ -12,11 +12,11 @@ rankings automatically.
|
||||||
|
|
||||||
**All of these features work for any game, in any region, without restriction.**
|
**All of these features work for any game, in any region, without restriction.**
|
||||||
|
|
||||||
> **Warning**<br>
|
> [!WARNING]
|
||||||
> StartRNR is unstable and under active development. The design and user
|
> StartRNR is unstable and under active development. The design and user
|
||||||
> interface of this program is experimental and may be subject to change.
|
> interface of this program is experimental and may be subject to change.
|
||||||
>
|
>
|
||||||
> Currently, only generating datasets has been implemented.
|
> Currently, the power ranking and seeding features have not been implemented.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -34,6 +34,30 @@ Alternatively, if you use Nix:
|
||||||
nix profile install github:kiana-S/StartRNR
|
nix profile install github:kiana-S/StartRNR
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Once StartRNR is installed, run:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
startrnr sync
|
||||||
|
```
|
||||||
|
|
||||||
|
The program will walk you through creating a dataset, then run its rating
|
||||||
|
algorithm. **This may take up to a few hours to finish running!**
|
||||||
|
|
||||||
|
Once the rating data has been generated, these commands can be used to access it:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
# Access a player's data
|
||||||
|
startrnr player info <player>
|
||||||
|
|
||||||
|
# Analyze matchup of two players
|
||||||
|
startrnr player matchup <player1> <player2>
|
||||||
|
```
|
||||||
|
|
||||||
|
A player can be specified by their tag or by their
|
||||||
|
[discriminator](https://help.start.gg/en/articles/4855957-discriminators-on-start-gg).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
StartRNR stores its rating databases in its config directory, which is located at:
|
StartRNR stores its rating databases in its config directory, which is located at:
|
||||||
|
|
117
src/database.rs
117
src/database.rs
|
@ -4,6 +4,8 @@ use std::fs::{self, OpenOptions};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub struct DatasetMetadata {
|
pub struct DatasetMetadata {
|
||||||
|
pub start: Timestamp,
|
||||||
|
pub end: Option<Timestamp>,
|
||||||
pub last_sync: Timestamp,
|
pub last_sync: Timestamp,
|
||||||
|
|
||||||
pub game_id: VideogameId,
|
pub game_id: VideogameId,
|
||||||
|
@ -38,10 +40,11 @@ fn datasets_path(config_dir: &Path) -> std::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 = datasets_path(config_dir).unwrap();
|
let path = datasets_path(config_dir).unwrap();
|
||||||
|
|
||||||
let query = "PRAGMA foreign_keys = ON;
|
let query = "
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS datasets (
|
CREATE TABLE IF NOT EXISTS datasets (
|
||||||
name TEXT UNIQUE NOT NULL,
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
start INTEGER NOT NULL,
|
||||||
|
end INTEGER,
|
||||||
last_sync INTEGER NOT NULL,
|
last_sync INTEGER NOT NULL,
|
||||||
game_id INTEGER NOT NULL,
|
game_id INTEGER NOT NULL,
|
||||||
game_name TEXT NOT NULL,
|
game_name TEXT NOT NULL,
|
||||||
|
@ -68,10 +71,9 @@ CREATE TABLE IF NOT EXISTS events (
|
||||||
) STRICT;
|
) STRICT;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS sets (
|
CREATE TABLE IF NOT EXISTS sets (
|
||||||
id TEXT UNIQUE NOT NULL,
|
id TEXT PRIMARY KEY,
|
||||||
event INTEGER NOT NULL,
|
event INTEGER NOT NULL REFERENCES events
|
||||||
FOREIGN KEY(event) REFERENCES events
|
) STRICT, WITHOUT ROWID;
|
||||||
) STRICT;
|
|
||||||
";
|
";
|
||||||
|
|
||||||
let connection = sqlite::open(path)?;
|
let connection = sqlite::open(path)?;
|
||||||
|
@ -102,6 +104,10 @@ pub fn list_datasets(connection: &Connection) -> sqlite::Result<Vec<(String, Dat
|
||||||
Ok((
|
Ok((
|
||||||
r_.read::<&str, _>("name").to_owned(),
|
r_.read::<&str, _>("name").to_owned(),
|
||||||
DatasetMetadata {
|
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),
|
last_sync: Timestamp(r_.read::<i64, _>("last_sync") as u64),
|
||||||
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
|
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
|
||||||
game_name: r_.read::<&str, _>("game_name").to_owned(),
|
game_name: r_.read::<&str, _>("game_name").to_owned(),
|
||||||
|
@ -139,8 +145,6 @@ pub fn rename_dataset(connection: &Connection, old: &str, new: &str) -> sqlite::
|
||||||
r#"UPDATE datasets SET name = '{1}' WHERE name = '{0}';
|
r#"UPDATE datasets SET name = '{1}' WHERE name = '{0}';
|
||||||
ALTER TABLE "{0}_players" RENAME TO "{1}_players";
|
ALTER TABLE "{0}_players" RENAME TO "{1}_players";
|
||||||
ALTER TABLE "{0}_network" RENAME TO "{1}_network";
|
ALTER TABLE "{0}_network" RENAME TO "{1}_network";
|
||||||
DROP INDEX "{0}_network_A";
|
|
||||||
CREATE INDEX "{1}_network_A" ON "{1}_network" (player_A);
|
|
||||||
DROP INDEX "{0}_network_B";
|
DROP INDEX "{0}_network_B";
|
||||||
CREATE INDEX "{1}_network_B" ON "{1}_network" (player_B);"#,
|
CREATE INDEX "{1}_network_B" ON "{1}_network" (player_B);"#,
|
||||||
old, new
|
old, new
|
||||||
|
@ -154,10 +158,10 @@ pub fn new_dataset(
|
||||||
dataset: &str,
|
dataset: &str,
|
||||||
metadata: DatasetMetadata,
|
metadata: DatasetMetadata,
|
||||||
) -> sqlite::Result<()> {
|
) -> sqlite::Result<()> {
|
||||||
let query1 = r#"INSERT INTO datasets VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#;
|
let query1 = r#"INSERT INTO datasets VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#;
|
||||||
let query2 = format!(
|
let query2 = format!(
|
||||||
r#"CREATE TABLE "{0}_players" (
|
r#"CREATE TABLE "{0}_players" (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY REFERENCES players,
|
||||||
last_played INTEGER NOT NULL,
|
last_played INTEGER NOT NULL,
|
||||||
deviation REAL NOT NULL,
|
deviation REAL NOT NULL,
|
||||||
volatility REAL NOT NULL,
|
volatility REAL NOT NULL,
|
||||||
|
@ -182,14 +186,13 @@ CREATE TABLE "{0}_network" (
|
||||||
sets TEXT AS (sets_A || sets_B),
|
sets TEXT AS (sets_A || sets_B),
|
||||||
sets_count INTEGER AS (sets_count_A + sets_count_B),
|
sets_count INTEGER AS (sets_count_A + sets_count_B),
|
||||||
|
|
||||||
UNIQUE (player_A, player_B),
|
PRIMARY KEY (player_A, player_B),
|
||||||
CHECK (player_A < player_B),
|
CHECK (player_A < player_B),
|
||||||
FOREIGN KEY(player_A) REFERENCES "{0}_players"
|
FOREIGN KEY(player_A) REFERENCES "{0}_players"
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
FOREIGN KEY(player_B) REFERENCES "{0}_players"
|
FOREIGN KEY(player_B) REFERENCES "{0}_players"
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
) STRICT;
|
) STRICT;
|
||||||
CREATE INDEX "{0}_network_A" ON "{0}_network" (player_A);
|
|
||||||
CREATE INDEX "{0}_network_B" ON "{0}_network" (player_B);"#,
|
CREATE INDEX "{0}_network_B" ON "{0}_network" (player_B);"#,
|
||||||
dataset
|
dataset
|
||||||
);
|
);
|
||||||
|
@ -198,17 +201,19 @@ CREATE INDEX "{0}_network_B" ON "{0}_network" (player_B);"#,
|
||||||
.prepare(query1)?
|
.prepare(query1)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.bind((1, dataset))?
|
.bind((1, dataset))?
|
||||||
.bind((2, metadata.last_sync.0 as i64))?
|
.bind((2, metadata.start.0 as i64))?
|
||||||
.bind((3, metadata.game_id.0 as i64))?
|
.bind((3, metadata.end.map(|x| x.0 as i64)))?
|
||||||
.bind((4, &metadata.game_name[..]))?
|
.bind((4, metadata.last_sync.0 as i64))?
|
||||||
.bind((5, &metadata.game_slug[..]))?
|
.bind((5, metadata.game_id.0 as i64))?
|
||||||
.bind((6, metadata.country.as_deref()))?
|
.bind((6, &metadata.game_name[..]))?
|
||||||
.bind((7, metadata.state.as_deref()))?
|
.bind((7, &metadata.game_slug[..]))?
|
||||||
.bind((8, metadata.set_limit as i64))?
|
.bind((8, metadata.country.as_deref()))?
|
||||||
.bind((9, metadata.decay_rate))?
|
.bind((9, metadata.state.as_deref()))?
|
||||||
.bind((10, metadata.adj_decay_rate))?
|
.bind((10, metadata.set_limit as i64))?
|
||||||
.bind((11, metadata.period))?
|
.bind((11, metadata.decay_rate))?
|
||||||
.bind((12, metadata.tau))?
|
.bind((12, metadata.adj_decay_rate))?
|
||||||
|
.bind((13, metadata.period))?
|
||||||
|
.bind((14, metadata.tau))?
|
||||||
.try_for_each(|x| x.map(|_| ()))?;
|
.try_for_each(|x| x.map(|_| ()))?;
|
||||||
|
|
||||||
connection.execute(query2)
|
connection.execute(query2)
|
||||||
|
@ -228,6 +233,10 @@ pub fn get_metadata(
|
||||||
.map(|r| {
|
.map(|r| {
|
||||||
let r_ = r?;
|
let r_ = r?;
|
||||||
Ok(DatasetMetadata {
|
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),
|
last_sync: Timestamp(r_.read::<i64, _>("last_sync") as u64),
|
||||||
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
|
game_id: VideogameId(r_.read::<i64, _>("game_id") as u64),
|
||||||
game_name: r_.read::<&str, _>("game_name").to_owned(),
|
game_name: r_.read::<&str, _>("game_name").to_owned(),
|
||||||
|
@ -612,7 +621,7 @@ pub fn hypothetical_advantage(
|
||||||
decay_rate: f64,
|
decay_rate: f64,
|
||||||
adj_decay_rate: f64,
|
adj_decay_rate: f64,
|
||||||
) -> sqlite::Result<f64> {
|
) -> sqlite::Result<f64> {
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashSet, VecDeque};
|
||||||
|
|
||||||
// Check trivial cases
|
// Check trivial cases
|
||||||
if player1 == player2 || either_isolated(connection, dataset, player1, player2)? {
|
if player1 == player2 || either_isolated(connection, dataset, player1, player2)? {
|
||||||
|
@ -620,48 +629,62 @@ pub fn hypothetical_advantage(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visited: HashSet<PlayerId> = HashSet::new();
|
let mut visited: HashSet<PlayerId> = HashSet::new();
|
||||||
let mut queue: HashMap<PlayerId, (f64, f64)> = HashMap::from([(player1, (0.0, 1.0))]);
|
let mut queue: VecDeque<(PlayerId, Vec<(f64, f64)>)> =
|
||||||
|
VecDeque::from([(player1, Vec::from([(0.0, 1.0)]))]);
|
||||||
|
|
||||||
|
let mut final_paths = Vec::new();
|
||||||
|
|
||||||
|
while !queue.is_empty() && final_paths.len() < 100 {
|
||||||
|
let (visiting, paths) = queue.pop_front().unwrap();
|
||||||
|
|
||||||
while !queue.is_empty() {
|
|
||||||
let visiting = *queue
|
|
||||||
.iter()
|
|
||||||
.max_by(|a, b| a.1 .1.partial_cmp(&b.1 .1).unwrap())
|
|
||||||
.unwrap()
|
|
||||||
.0;
|
|
||||||
let (adv_v, decay_v) = queue.remove(&visiting).unwrap();
|
|
||||||
let connections = get_edges(connection, dataset, visiting)?;
|
let connections = get_edges(connection, dataset, visiting)?;
|
||||||
|
|
||||||
for (id, adv, sets) in connections
|
for (id, adv, sets) in connections
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(id, _, _)| !visited.contains(id))
|
.filter(|(id, _, _)| !visited.contains(id))
|
||||||
{
|
{
|
||||||
let advantage = adv_v + adv;
|
let rf = if id == player2 {
|
||||||
|
&mut final_paths
|
||||||
|
} else if let Some(r) = queue.iter_mut().find(|(id_, _)| id == *id_) {
|
||||||
|
&mut r.1
|
||||||
|
} else {
|
||||||
|
queue.push_back((id, Vec::new()));
|
||||||
|
&mut queue.back_mut().unwrap().1
|
||||||
|
};
|
||||||
|
|
||||||
if id == player2 {
|
if rf.len() < 100 {
|
||||||
return Ok(advantage * decay_v);
|
let decay = if sets >= set_limit {
|
||||||
}
|
|
||||||
|
|
||||||
let decay = decay_v
|
|
||||||
* if sets >= set_limit {
|
|
||||||
decay_rate
|
decay_rate
|
||||||
} else {
|
} else {
|
||||||
adj_decay_rate
|
adj_decay_rate
|
||||||
};
|
};
|
||||||
|
let iter = paths.iter().map(|(a, d)| (a + adv, d * decay));
|
||||||
|
|
||||||
if queue
|
rf.extend(iter);
|
||||||
.get(&id)
|
rf.truncate(100);
|
||||||
.map(|(_, decay_old)| *decay_old < decay)
|
|
||||||
.unwrap_or(true)
|
|
||||||
{
|
|
||||||
queue.insert(id, (advantage, decay));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visited.insert(visiting);
|
visited.insert(visiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No path found
|
let max_decay = final_paths
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.1)
|
||||||
|
.max_by(|d1, d2| d1.partial_cmp(d2).unwrap());
|
||||||
|
|
||||||
|
if let Some(mdec) = max_decay {
|
||||||
|
let sum_decay = final_paths.iter().map(|x| x.1).sum::<f64>();
|
||||||
|
Ok(final_paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|(adv, dec)| adv * dec)
|
||||||
|
.sum::<f64>()
|
||||||
|
/ sum_decay
|
||||||
|
* mdec)
|
||||||
|
} else {
|
||||||
|
// No paths found
|
||||||
Ok(0.0)
|
Ok(0.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_edge(
|
pub fn initialize_edge(
|
||||||
|
@ -739,6 +762,8 @@ CREATE TABLE IF NOT EXISTS sets (
|
||||||
|
|
||||||
pub fn metadata() -> DatasetMetadata {
|
pub fn metadata() -> DatasetMetadata {
|
||||||
DatasetMetadata {
|
DatasetMetadata {
|
||||||
|
start: Timestamp(1),
|
||||||
|
end: None,
|
||||||
last_sync: Timestamp(1),
|
last_sync: Timestamp(1),
|
||||||
game_id: VideogameId(0),
|
game_id: VideogameId(0),
|
||||||
game_name: String::from("Test Game"),
|
game_name: String::from("Test Game"),
|
||||||
|
|
136
src/main.rs
136
src/main.rs
|
@ -1,10 +1,10 @@
|
||||||
#![feature(iterator_try_collect)]
|
#![feature(iterator_try_collect)]
|
||||||
#![feature(extend_one)]
|
#![feature(extend_one)]
|
||||||
|
|
||||||
|
use chrono::{Local, TimeZone, Utc};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use sqlite::*;
|
use sqlite::*;
|
||||||
use std::path::PathBuf;
|
use std::{cmp::min, path::PathBuf};
|
||||||
use time_format::strftime_utc;
|
|
||||||
|
|
||||||
mod queries;
|
mod queries;
|
||||||
use queries::*;
|
use queries::*;
|
||||||
|
@ -117,7 +117,6 @@ fn main() {
|
||||||
let connection =
|
let connection =
|
||||||
open_datasets(&config_dir).unwrap_or_else(|_| error("Could not open datasets file", 2));
|
open_datasets(&config_dir).unwrap_or_else(|_| error("Could not open datasets file", 2));
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
match cli.subcommand {
|
match cli.subcommand {
|
||||||
Subcommands::Dataset {
|
Subcommands::Dataset {
|
||||||
subcommand: DatasetSC::List,
|
subcommand: DatasetSC::List,
|
||||||
|
@ -145,7 +144,12 @@ fn main() {
|
||||||
sync(&connection, get_auth_token(&config_dir), datasets, all)
|
sync(&connection, get_auth_token(&config_dir), datasets, all)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => println!("This feature is currently unimplemented."),
|
Subcommands::Ranking {
|
||||||
|
subcommand: RankingSC::Create,
|
||||||
|
dataset,
|
||||||
|
} => ranking_create(&connection, dataset),
|
||||||
|
|
||||||
|
_ => eprintln!("This feature is currently unimplemented."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +160,7 @@ fn dataset_list(connection: &Connection) {
|
||||||
|
|
||||||
for (name, metadata) in datasets {
|
for (name, metadata) in datasets {
|
||||||
print!(
|
print!(
|
||||||
"\n· \x1b[1m\x1b[34m{}\x1b[0m
|
"· \x1b[1m\x1b[34m{}\x1b[0m
|
||||||
\x1b[4m\x1b]8;;https://www.start.gg/{}\x1b\\{}\x1b]8;;\x1b\\\x1b[0m ",
|
\x1b[4m\x1b]8;;https://www.start.gg/{}\x1b\\{}\x1b]8;;\x1b\\\x1b[0m ",
|
||||||
name, metadata.game_slug, metadata.game_name
|
name, metadata.game_slug, metadata.game_name
|
||||||
);
|
);
|
||||||
|
@ -171,15 +175,42 @@ fn dataset_list(connection: &Connection) {
|
||||||
println!("(Global)");
|
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");
|
print!("\x1b[1m\x1b[91mUnsynced\x1b[0m");
|
||||||
|
} else if Some(metadata.last_sync) == metadata.end {
|
||||||
|
print!("\x1b[1m\x1b[92mComplete\x1b[0m");
|
||||||
} else {
|
} else {
|
||||||
print!(
|
print!(
|
||||||
"\x1b[1mLast synced:\x1b[0m {}",
|
"\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" {
|
if name == "default" {
|
||||||
print!(" - \x1b[33mRun 'startrnr sync' to update!\x1b[0m");
|
print!(" - \x1b[33mRun 'startrnr sync' to update!\x1b[0m");
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,7 +235,7 @@ fn dataset_list(connection: &Connection) {
|
||||||
"\x1b[1mRating Period:\x1b[0m {} days",
|
"\x1b[1mRating Period:\x1b[0m {} days",
|
||||||
metadata.period / SECS_IN_DAY as f64
|
metadata.period / SECS_IN_DAY as f64
|
||||||
);
|
);
|
||||||
println!("\x1b[1mTau Constant:\x1b[0m {}", metadata.tau);
|
println!("\x1b[1mTau Constant:\x1b[0m {}\n", metadata.tau);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +331,70 @@ State/province to track ratings for (leave empty for none): "
|
||||||
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
|
// Set Limit
|
||||||
|
|
||||||
let mut set_limit = 0;
|
let mut set_limit = 0;
|
||||||
|
@ -426,7 +521,9 @@ Tau constant (default 0.4): "
|
||||||
connection,
|
connection,
|
||||||
&name,
|
&name,
|
||||||
DatasetMetadata {
|
DatasetMetadata {
|
||||||
last_sync: Timestamp(1),
|
start,
|
||||||
|
end,
|
||||||
|
last_sync: start,
|
||||||
game_id,
|
game_id,
|
||||||
game_name,
|
game_name,
|
||||||
game_slug,
|
game_slug,
|
||||||
|
@ -496,7 +593,6 @@ fn player_info(connection: &Connection, dataset: Option<String>, player: String)
|
||||||
let (won, lost) = get_player_set_counts(connection, &dataset, id)
|
let (won, lost) = get_player_set_counts(connection, &dataset, id)
|
||||||
.unwrap_or_else(|_| error("Could not find player", 1));
|
.unwrap_or_else(|_| error("Could not find player", 1));
|
||||||
|
|
||||||
println!();
|
|
||||||
if let Some(pre) = prefix {
|
if let Some(pre) = prefix {
|
||||||
print!("\x1b[2m{}\x1b[22m ", pre);
|
print!("\x1b[2m{}\x1b[22m ", pre);
|
||||||
}
|
}
|
||||||
|
@ -518,7 +614,6 @@ fn player_info(connection: &Connection, dataset: Option<String>, player: String)
|
||||||
println!("\x1b[1mVolatility:\x1b[0m {}", volatility);
|
println!("\x1b[1mVolatility:\x1b[0m {}", volatility);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Finish
|
|
||||||
fn player_matchup(
|
fn player_matchup(
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
dataset: Option<String>,
|
dataset: Option<String>,
|
||||||
|
@ -583,7 +678,6 @@ fn player_matchup(
|
||||||
let len1 = prefix1.as_deref().map(|s| s.len() + 1).unwrap_or(0) + name1.len();
|
let len1 = prefix1.as_deref().map(|s| s.len() + 1).unwrap_or(0) + name1.len();
|
||||||
let len2 = prefix2.as_deref().map(|s| s.len() + 1).unwrap_or(0) + name2.len();
|
let len2 = prefix2.as_deref().map(|s| s.len() + 1).unwrap_or(0) + name2.len();
|
||||||
|
|
||||||
println!();
|
|
||||||
if let Some(pre) = prefix1 {
|
if let Some(pre) = prefix1 {
|
||||||
print!("\x1b[2m{}\x1b[22m ", pre);
|
print!("\x1b[2m{}\x1b[22m ", pre);
|
||||||
}
|
}
|
||||||
|
@ -663,14 +757,22 @@ fn sync(connection: &Connection, auth: String, datasets: Vec<String>, all: bool)
|
||||||
let current_time = current_time();
|
let current_time = current_time();
|
||||||
|
|
||||||
for dataset in datasets {
|
for dataset in datasets {
|
||||||
let dataset_config = get_metadata(connection, &dataset)
|
let dataset_metadata = get_metadata(connection, &dataset)
|
||||||
.expect("Error communicating with SQLite")
|
.expect("Error communicating with SQLite")
|
||||||
.unwrap_or_else(|| error(&format!("Dataset {} does not exist!", dataset), 1));
|
.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");
|
.expect("Error communicating with SQLite");
|
||||||
|
|
||||||
update_last_sync(connection, &dataset, current_time)
|
update_last_sync(connection, &dataset, before).expect("Error communicating with SQLite");
|
||||||
.expect("Error communicating with SQLite");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ranking_create(connection: &Connection, dataset: Option<String>) {
|
||||||
|
let dataset = dataset.unwrap_or_else(|| String::from("default"));
|
||||||
|
}
|
||||||
|
|
10
src/sync.rs
10
src/sync.rs
|
@ -125,7 +125,7 @@ fn get_event_sets(event: EventId, auth: &str) -> Option<Vec<SetData>> {
|
||||||
|
|
||||||
fn get_tournament_events(
|
fn get_tournament_events(
|
||||||
metadata: &DatasetMetadata,
|
metadata: &DatasetMetadata,
|
||||||
current_time: Timestamp,
|
before: Timestamp,
|
||||||
auth: &str,
|
auth: &str,
|
||||||
) -> Option<Vec<EventData>> {
|
) -> Option<Vec<EventData>> {
|
||||||
println!("Accessing tournaments...");
|
println!("Accessing tournaments...");
|
||||||
|
@ -135,7 +135,7 @@ fn get_tournament_events(
|
||||||
let tour_response = run_query::<TournamentEvents, _>(
|
let tour_response = run_query::<TournamentEvents, _>(
|
||||||
TournamentEventsVars {
|
TournamentEventsVars {
|
||||||
after_date: after,
|
after_date: after,
|
||||||
before_date: current_time,
|
before_date: before,
|
||||||
game_id: metadata.game_id,
|
game_id: metadata.game_id,
|
||||||
country: metadata.country.as_deref(),
|
country: metadata.country.as_deref(),
|
||||||
state: metadata.state.as_deref(),
|
state: metadata.state.as_deref(),
|
||||||
|
@ -160,7 +160,7 @@ fn get_tournament_events(
|
||||||
let next_response = run_query::<TournamentEvents, _>(
|
let next_response = run_query::<TournamentEvents, _>(
|
||||||
TournamentEventsVars {
|
TournamentEventsVars {
|
||||||
after_date: after,
|
after_date: after,
|
||||||
before_date: current_time,
|
before_date: before,
|
||||||
game_id: metadata.game_id,
|
game_id: metadata.game_id,
|
||||||
country: metadata.country.as_deref(),
|
country: metadata.country.as_deref(),
|
||||||
state: metadata.state.as_deref(),
|
state: metadata.state.as_deref(),
|
||||||
|
@ -304,10 +304,10 @@ pub fn sync_dataset(
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
dataset: &str,
|
dataset: &str,
|
||||||
metadata: DatasetMetadata,
|
metadata: DatasetMetadata,
|
||||||
current_time: Timestamp,
|
before: Timestamp,
|
||||||
auth: &str,
|
auth: &str,
|
||||||
) -> sqlite::Result<()> {
|
) -> 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));
|
.unwrap_or_else(|| error("Could not access start.gg", 1));
|
||||||
|
|
||||||
connection.execute("BEGIN;")?;
|
connection.execute("BEGIN;")?;
|
||||||
|
|
|
@ -10,12 +10,12 @@ pub const SECS_IN_DAY: u64 = SECS_IN_HR * 24;
|
||||||
pub const SECS_IN_WEEK: u64 = SECS_IN_DAY * 7;
|
pub const SECS_IN_WEEK: u64 = SECS_IN_DAY * 7;
|
||||||
|
|
||||||
pub fn error(msg: &str, code: i32) -> ! {
|
pub fn error(msg: &str, code: i32) -> ! {
|
||||||
println!("\nERROR: {}", msg);
|
eprintln!("\nERROR: {}", msg);
|
||||||
exit(code)
|
exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn issue(msg: &str, code: i32) -> ! {
|
pub fn issue(msg: &str, code: i32) -> ! {
|
||||||
println!("\n{}", msg);
|
eprintln!("\n{}", msg);
|
||||||
exit(code)
|
exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue