Compare commits

...

3 Commits

Author SHA1 Message Date
Joey Pollack 478e532ce9 fixes some warnings 2 years ago
Joey Pollack d952c618e1 Merge branch 'main' into racetime 2 years ago
Joey Pollack 35b0d8f065 adds racetime.gg race polling and tracking 2 years ago

@ -9,3 +9,5 @@ edition = "2021"
rand = "0.8.5" rand = "0.8.5"
serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } serenity = { version = "0.11.6", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] }
tokio = { version = "1.21.1", features = ["full"] } tokio = { version = "1.21.1", features = ["full"] }
reqwest = { version = "0.11", features = ["json"] }
serde_json = "1.0"

@ -1,4 +1,6 @@
#![allow(dead_code, unused_imports, unused_variables)]
use serenity::prelude::*; use serenity::prelude::*;
use serenity::model::prelude::*; use serenity::model::prelude::*;
use serenity::model::channel::Message; use serenity::model::channel::Message;

@ -18,7 +18,7 @@ const ROLE_ID_PURPLE: u64 = 284310454908747787;
pub async fn parse_command(ctx: Context, msg: Message, server_id: GuildId) pub async fn parse_command(ctx: Context, msg: Message, server_id: GuildId)
{ {
if handle_meme(ctx.clone(), msg.clone(), server_id).await if handle_meme(ctx.clone(), msg.clone()).await
{ {
return; return;
} }
@ -95,7 +95,7 @@ async fn set_color(ctx: Context, msg: Message, role_id: RoleId, server_id: Guild
} }
} }
async fn handle_meme(ctx: Context, msg: Message, server_id: GuildId) -> bool async fn handle_meme(ctx: Context, msg: Message) -> bool
{ {
let command_lower = msg.content.to_lowercase(); let command_lower = msg.content.to_lowercase();

@ -55,4 +55,9 @@ pub async fn parse_command(ctx: Context, msg: Message, server_id: GuildId)
return; return;
} }
if msg.content == ".race_test"
{
// TODO: Get race data from ctx.data and print it to main log channel
}
} }

@ -2,8 +2,11 @@
mod commands; mod commands;
mod data_loader; mod data_loader;
mod utils; mod utils;
mod racetime;
// use std::collections::HashSet; use racetime::{race::Races};
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::AtomicU64; use std::sync::atomic::AtomicU64;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -11,7 +14,6 @@ use std::time::Duration;
use serenity::async_trait; use serenity::async_trait;
use serenity::prelude::*; use serenity::prelude::*;
// use serenity::model::prelude::*;
use serenity::model::channel::Message; use serenity::model::channel::Message;
use serenity::model::gateway::Ready; use serenity::model::gateway::Ready;
use serenity::model::id::GuildId; use serenity::model::id::GuildId;
@ -86,8 +88,9 @@ impl EventHandler for Handler
// TODO: function we want to run called here // TODO: function we want to run called here
// Run racetime.gg and twitch api checks // Run racetime.gg and twitch api checks
// Post new stuff to discord channel // Post new stuff to discord channel
racetime::poll_races(Arc::clone(&ctx1)).await;
tokio::time::sleep(Duration::from_secs(120)).await; tokio::time::sleep(Duration::from_secs(60)).await;
} }
}); });
@ -116,12 +119,13 @@ async fn main()
}; };
//let race = Race { name: String::from("Test"), game: String::from("Test"), goal: String::from("Test"), status: Status::Open };
println!("Connecting..."); println!("Connecting...");
let intents = GatewayIntents::GUILD_MESSAGES let intents = GatewayIntents::GUILD_MESSAGES
| GatewayIntents::DIRECT_MESSAGES | GatewayIntents::DIRECT_MESSAGES
| GatewayIntents::GUILDS
| GatewayIntents::MESSAGE_CONTENT; | GatewayIntents::MESSAGE_CONTENT;
// Create a new instance of the Client, logging in as a bot. This will // Create a new instance of the Client, logging in as a bot. This will
@ -140,6 +144,7 @@ async fn main()
let mut data = client.data.write().await; let mut data = client.data.write().await;
data.insert::<Owner>(Arc::new(AtomicU64::new(owner.into()))); data.insert::<Owner>(Arc::new(AtomicU64::new(owner.into())));
data.insert::<Races>(Arc::new(RwLock::new(HashMap::new())));
} }

@ -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().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() -> 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>>>;
}

@ -1,6 +1,6 @@
use rand::prelude::*; use rand::prelude::*;
use serenity::{client::Context, model::{user::User, prelude::{Role, ChannelId, GuildId, RoleId, UserId}, guild}}; use serenity::{client::Context, model::prelude::{Role, ChannelId, GuildId, RoleId, UserId}};
pub const SM_SERVER_ID: u64 = 98929157894836224; pub const SM_SERVER_ID: u64 = 98929157894836224;

Loading…
Cancel
Save