adds racetime.gg race polling and tracking
parent
8c77b9f059
commit
35b0d8f065
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub mod race;
|
||||||
|
use race::{Race, Races};
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use serenity::prelude::*;
|
||||||
|
use serde_json::Value;
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
pub async fn poll_races(ctx: Arc<Context>)
|
||||||
|
{
|
||||||
|
let race_data = match fetch_race_data(ctx.clone()).await
|
||||||
|
{
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(why) => { utils::Logger::log_error((*ctx).clone(), &format!("Failed to query racetime.gg: {}", why)).await; return; }
|
||||||
|
};
|
||||||
|
|
||||||
|
let race_array = match race_data["races"].as_array()
|
||||||
|
{
|
||||||
|
Some(arr) => arr,
|
||||||
|
None => { utils::Logger::log_error((*ctx).clone(), &format!("Race data was not an array")).await; return; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut data = ctx.data.write().await;
|
||||||
|
let mut races = match data.get_mut::<Races>()
|
||||||
|
{
|
||||||
|
Some(r) => r.write().await,
|
||||||
|
None => { utils::Logger::log_error((*ctx).clone(), &format!("Couldn't get Races HashMap from the data type map")).await; return; }
|
||||||
|
};
|
||||||
|
|
||||||
|
for race in race_array
|
||||||
|
{
|
||||||
|
//println!("\tGame: {}\n\tCategory: {}", race["category"]["name"], race["goal"]["name"]);
|
||||||
|
let key = race["name"].to_string().strip_prefix("\"").unwrap().to_string();
|
||||||
|
if key.starts_with("sm") || key.starts_with("smr") || key.starts_with("smz3")
|
||||||
|
{
|
||||||
|
let race = Race::from_json(race);
|
||||||
|
if !races.contains_key(&key)
|
||||||
|
{
|
||||||
|
races.insert(key.clone(), race.clone());
|
||||||
|
|
||||||
|
// TODO: Send announcement to sm server
|
||||||
|
|
||||||
|
// TEST ANNOUNCEMENT
|
||||||
|
// utils::Logger::log_message((*ctx).clone(), &format!("New race started for: {} - **goal:** {} - **url:** {}", races[&key].game, races[&key].goal, races[&key].url)).await;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if races[&key].status != race.status
|
||||||
|
{
|
||||||
|
races.get_mut(&key).unwrap().status = race.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if races[&key].goal != race.goal
|
||||||
|
{
|
||||||
|
races.get_mut(&key).unwrap().goal = race.goal;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Send announcement to sm server
|
||||||
|
|
||||||
|
// TEST ANNOUNCEMENT
|
||||||
|
//utils::Logger::log_message((*ctx).clone(), &format!("Goal set: {} for: {}", races[&key].goal, races[&key].url)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////// HELPERS
|
||||||
|
async fn fetch_race_data(ctx: Arc<Context>) -> Result<Value, String>
|
||||||
|
{
|
||||||
|
let result = reqwest::get("https://racetime.gg/races/data").await;
|
||||||
|
let response = match result
|
||||||
|
{
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(why) => { return Err(format!("Failed to query racetime.gg: {}", why)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// let response: Value = serde_json::from_str(res.text().await.expect("reqwest::text() failed").as_str()).expect("Failed to convert to json");
|
||||||
|
let body_result = response.text().await;
|
||||||
|
let body = match body_result
|
||||||
|
{
|
||||||
|
Ok(b) => b,
|
||||||
|
Err(why) => { return Err(format!("Failed to query racetime.gg: {}", why)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_json: Value = match serde_json::from_str(body.as_str())
|
||||||
|
{
|
||||||
|
Ok(j) => j,
|
||||||
|
Err(why) => {return Err(format!("Failed to convert racetime query to json: {}", why)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(body_json)
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use serenity::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum Status
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Invitational,
|
||||||
|
Pending,
|
||||||
|
InProgress,
|
||||||
|
Finished,
|
||||||
|
Cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Race
|
||||||
|
{
|
||||||
|
pub name: String,
|
||||||
|
pub game: String,
|
||||||
|
pub goal: String,
|
||||||
|
pub status: String,
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Race
|
||||||
|
{
|
||||||
|
pub fn new(name: String, game: String, goal: String, status: String, url: String) -> Race
|
||||||
|
{
|
||||||
|
Race { name, game, goal, status, url }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_json(json: &Value) -> Race
|
||||||
|
{
|
||||||
|
let url = String::from("https://racetime.gg") + json["url"].as_str().unwrap();
|
||||||
|
Race {
|
||||||
|
name: json["name"].to_string(),
|
||||||
|
game: json["category"]["name"].to_string(),
|
||||||
|
goal: json["goal"]["name"].to_string(),
|
||||||
|
status: json["status"]["value"].to_string(),
|
||||||
|
url: url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Races;
|
||||||
|
|
||||||
|
impl TypeMapKey for Races
|
||||||
|
{
|
||||||
|
// HashMap key is the name of the race
|
||||||
|
type Value = Arc<RwLock<HashMap<String, Race>>>;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue