Add transit betting

This commit is contained in:
Joey Hines 2025-04-20 18:33:33 -06:00
parent cda4339386
commit 32fa1a11d1
Signed by: joeyahines
GPG Key ID: 38BA6F25C94C9382
9 changed files with 445 additions and 55 deletions

186
Cargo.lock generated
View File

@ -735,6 +735,19 @@ dependencies = [
"typenum",
]
[[package]]
name = "cta-api"
version = "0.2.0"
source = "registry+https://git.ahines.net/joeyahines/_cargo-index.git"
checksum = "7f85231a3e0c11c63ef5a5675e7f6e16f5eac05f67a0dd94fc0984dd06ba250b"
dependencies = [
"reqwest 0.12.15",
"serde",
"serde_json",
"thiserror 2.0.12",
"url",
]
[[package]]
name = "ctr"
version = "0.9.2"
@ -1080,13 +1093,14 @@ dependencies = [
[[package]]
name = "fren"
version = "1.3.1"
version = "1.4.0"
dependencies = [
"axum 0.8.1",
"base64 0.22.1",
"chrono",
"chrono-tz 0.10.1",
"config",
"cta-api",
"emojis",
"j_db",
"json",
@ -1098,7 +1112,7 @@ dependencies = [
"raas_types",
"rand 0.9.0",
"regex",
"reqwest 0.12.9",
"reqwest 0.12.15",
"serde",
"serde_json",
"sha3",
@ -1923,9 +1937,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.76"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
@ -2430,7 +2444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
dependencies = [
"memchr",
"thiserror 2.0.9",
"thiserror 2.0.12",
"ucd-trie",
]
@ -2785,7 +2799,7 @@ dependencies = [
"rustc-hash 2.1.1",
"rustls 0.23.20",
"socket2",
"thiserror 2.0.9",
"thiserror 2.0.12",
"tokio",
"tracing",
]
@ -2804,7 +2818,7 @@ dependencies = [
"rustls 0.23.20",
"rustls-pki-types",
"slab",
"thiserror 2.0.9",
"thiserror 2.0.12",
"tinyvec",
"tracing",
"web-time",
@ -3022,9 +3036,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.9"
version = "0.12.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
dependencies = [
"base64 0.22.1",
"bytes",
@ -3061,6 +3075,7 @@ dependencies = [
"tokio-native-tls",
"tokio-rustls 0.26.1",
"tokio-util",
"tower 0.5.2",
"tower-service",
"url",
"wasm-bindgen",
@ -3408,9 +3423,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.216"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
@ -3447,9 +3462,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.216"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
@ -3458,9 +3473,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.134"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
@ -3732,7 +3747,7 @@ dependencies = [
"parking_lot 0.12.3",
"pin-project",
"rand 0.9.0",
"reqwest 0.12.9",
"reqwest 0.12.15",
"ringbuf",
"rubato",
"rusty_pool",
@ -3793,7 +3808,7 @@ dependencies = [
"futures-util",
"hls_m3u8",
"patricia_tree",
"reqwest 0.12.9",
"reqwest 0.12.15",
"tokio",
"tracing",
"url",
@ -4182,11 +4197,11 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.9"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
dependencies = [
"thiserror-impl 2.0.9",
"thiserror-impl 2.0.12",
]
[[package]]
@ -4202,9 +4217,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
version = "2.0.9"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
@ -4696,7 +4711,7 @@ dependencies = [
"rustls 0.23.20",
"rustls-pki-types",
"sha1",
"thiserror 2.0.9",
"thiserror 2.0.12",
"url",
"utf-8",
]
@ -4979,20 +4994,21 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.99"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.99"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
@ -5004,9 +5020,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.49"
version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
dependencies = [
"cfg-if",
"js-sys",
@ -5017,9 +5033,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.99"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -5027,9 +5043,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.99"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
@ -5040,9 +5056,12 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.99"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-streams"
@ -5059,9 +5078,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.76"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -5154,33 +5173,38 @@ dependencies = [
]
[[package]]
name = "windows-registry"
version = "0.2.0"
name = "windows-link"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-registry"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result",
"windows-strings",
"windows-targets 0.52.6",
"windows-targets 0.53.0",
]
[[package]]
name = "windows-result"
version = "0.2.0"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-targets 0.52.6",
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
dependencies = [
"windows-result",
"windows-targets 0.52.6",
"windows-link",
]
[[package]]
@ -5234,13 +5258,29 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
@ -5253,6 +5293,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
@ -5265,6 +5311,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
@ -5277,12 +5329,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
@ -5295,6 +5359,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
@ -5307,6 +5377,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
@ -5319,6 +5395,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
@ -5331,6 +5413,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.6.20"

View File

@ -1,6 +1,6 @@
[package]
name = "fren"
version = "1.3.1"
version = "1.4.0"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -8,7 +8,7 @@ edition = "2024"
[dependencies]
config = "0.15.11"
structopt = "0.3.26"
reqwest = { version = "0.12.5", features = ["json", "multipart"] }
reqwest = { version = "0.12.15", features = ["json", "multipart"] }
serde = "1.0.195"
rand = "0.9.0"
tera = "1.19.1"
@ -30,6 +30,7 @@ emojis = "0.6.2"
poise = "0.6.1"
tracing-subscriber = "0.3.19"
log = "0.4.26"
cta-api = { version = "0.2.0", registry = "ahines"}
[dependencies.tokio]
version = "1.35.1"

View File

@ -2,6 +2,7 @@ use crate::album_manager::AlbumManager;
use crate::error::Error;
use crate::migrations::{CURRENT_DB_VERSION, do_migration};
use config::{Config, File};
use cta_api::CTAClient;
use j_db::database::Database;
use j_db::metadata::DBMetadata;
use poise::serenity_prelude::model::id::ChannelId;
@ -42,6 +43,7 @@ pub struct BotConfig {
pub toys: Vec<String>,
pub effect_role_duration: i64,
pub raas_server: String,
pub cta_key: String,
pub picox: PicOxConfig,
}
@ -75,6 +77,7 @@ pub struct GlobalData {
pub bot_state: Mutex<BotState>,
pub db: Database,
pub picox: AlbumManager,
pub cta: Mutex<CTAClient>,
pub speak_lock: Mutex<()>,
}
@ -100,6 +103,7 @@ impl GlobalData {
db,
cfg: cfg.clone(),
picox: AlbumManager::new(cfg.picox.api_base_url, &cfg.picox.token),
cta: Mutex::new(CTAClient::new(cfg.cta_key)),
speak_lock: Default::default(),
})
}

View File

@ -10,6 +10,7 @@ mod little_fren;
mod motivate;
mod role;
pub(crate) mod shop;
mod transit;
pub(crate) mod voices;
use crate::config::GlobalData;
@ -314,6 +315,7 @@ pub async fn run_bot(global_data: GlobalData) {
shop::sell_item(),
shop::shop(),
shop::use_item(),
transit::cta_bets(),
voices::list_voices(),
voices::list_words(),
voices::say(),
@ -347,7 +349,8 @@ pub async fn run_bot(global_data: GlobalData) {
let intents = serenity::GatewayIntents::non_privileged()
| serenity::GatewayIntents::DIRECT_MESSAGES
| serenity::GatewayIntents::GUILDS
| serenity::GatewayIntents::MESSAGE_CONTENT;
| serenity::GatewayIntents::MESSAGE_CONTENT
| serenity::GatewayIntents::GUILD_MESSAGE_REACTIONS;
let mut client = serenity::ClientBuilder::new(token, intents)
.framework(framework)

273
src/discord/transit.rs Normal file
View File

@ -0,0 +1,273 @@
use crate::discord::Context;
use crate::error::Error;
use crate::user::User;
use chrono::{DateTime, TimeZone, Utc};
use cta_api::models::eta::EtaRequest;
use log::debug;
use poise::serenity_prelude::{
FormattedTimestampStyle, Mentionable, MessageBuilder, ReactionType, Timestamp, UserId,
};
use std::collections::{HashMap, HashSet};
use std::time::Duration;
const CALI_STATION_ID: u32 = 30111;
#[derive(Debug, PartialOrd, PartialEq, Copy, Clone)]
pub enum CtaBetType {
OnTime,
Early,
Late,
}
impl CtaBetType {
pub fn emoji(&self) -> String {
match self {
CtaBetType::OnTime => "🟢".to_string(),
CtaBetType::Early => "🟡".to_string(),
CtaBetType::Late => "🔴".to_string(),
}
}
pub fn outcome(est_time: DateTime<Utc>, actual_time: DateTime<Utc>) -> Self {
let diff = est_time - actual_time;
if diff.num_seconds().abs() <= 1 {
CtaBetType::OnTime
} else if diff.num_seconds().is_positive() {
CtaBetType::Early
} else {
CtaBetType::Late
}
}
pub fn payout_factor(&self) -> f32 {
match self {
CtaBetType::OnTime => 10.0,
CtaBetType::Early => 2.0,
CtaBetType::Late => 1.5,
}
}
}
/// Bet on the CTA
#[poise::command(prefix_command, category = "Transit", guild_only)]
pub async fn cta_bets(ctx: Context<'_>) -> Result<(), Error> {
let mut cta_api = ctx.data().cta.lock().await;
let eta = cta_api
.fetch_eta(EtaRequest {
mapid: None,
stpid: Some(CALI_STATION_ID),
max: None,
rt: None,
})
.await?;
if eta.eta.is_empty() {
ctx.reply("No trains found, either the CTA is closed or borked. 50/50 shot really")
.await?;
return Ok(());
}
let next_train_eta = eta.eta.iter().find(|eta| eta.is_app == "0").unwrap();
let arrival_time =
chrono::NaiveDateTime::parse_from_str(&next_train_eta.arr_t, "%Y-%m-%dT%H:%M:%S").unwrap();
let arrival_time = chrono_tz::America::Chicago
.from_local_datetime(&arrival_time)
.unwrap();
let arrival_time = poise::serenity_prelude::model::Timestamp::from(arrival_time.to_utc());
let mut msg = MessageBuilder::new();
msg.push_line("# It's time to bet on public transit!");
msg.push_line("The next train to arrive to the California station on the Blue Line is:");
msg.push_line(format!("* **Train Run Number**: {}", next_train_eta.rn));
msg.push_line(format!(
"* **Is Train Delayed?**: {}",
next_train_eta.is_dly == "1"
));
msg.push_line(format!(
"* **Expected Arrival Time**: {}",
poise::serenity_prelude::utils::FormattedTimestamp::new(
arrival_time,
Some(FormattedTimestampStyle::LongTime)
)
));
msg.push_line("");
msg.push_line("Bets are 100 Fren Coins");
msg.push_bold_line("Only bet once, I'll know...");
msg.push_line("* React 🟢 if the train will be exactly on time (10x bet)");
msg.push_line("* React 🟡 if the train will be early (2x bet)");
msg.push_line("* React 🔴 if the train will be late (1.5x bet)");
let bet_msg = ctx.reply(msg.build()).await?;
let msg = bet_msg.message().await?;
msg.react(ctx, ReactionType::Unicode(CtaBetType::OnTime.emoji()))
.await?;
msg.react(ctx, ReactionType::Unicode(CtaBetType::Early.emoji()))
.await?;
msg.react(ctx, ReactionType::Unicode(CtaBetType::Late.emoji()))
.await?;
let mut arr_time = None;
// Try for 30 minutes
for _ in 0..(60 * 30) {
let train_status = cta_api
.fetch_train_schedule(next_train_eta.rn.parse().unwrap())
.await?;
let cali_eta = train_status
.eta
.iter()
.find(|schedule| {
let sta_id: u32 = schedule.stp_id.parse().unwrap();
sta_id == CALI_STATION_ID
})
.unwrap();
if cali_eta.is_app == "1" {
debug!("Train has arrived!");
arr_time = Some(Utc::now());
break;
}
tokio::time::sleep(Duration::from_secs(2)).await;
}
if arr_time.is_none() {
ctx.reply("Yeah I don't think this train is coming, oh well RIP Chicago")
.await?;
return Ok(());
}
let outcome = CtaBetType::outcome(*arrival_time, arr_time.unwrap());
let user_id = ctx.cache().current_user().id;
let msg = bet_msg.message().await?;
let reactions_on_time = msg
.reaction_users(
ctx,
ReactionType::Unicode(CtaBetType::OnTime.emoji()),
None,
None,
)
.await?;
let reactions_early = msg
.reaction_users(
ctx,
ReactionType::Unicode(CtaBetType::Early.emoji()),
None,
None,
)
.await?;
let reactions_late = msg
.reaction_users(
ctx,
ReactionType::Unicode(CtaBetType::Late.emoji()),
None,
None,
)
.await?;
let mut bets: HashMap<UserId, CtaBetType> = HashMap::new();
let mut punish_users: HashSet<UserId> = HashSet::new();
add_bets(
&user_id,
&CtaBetType::OnTime,
&reactions_on_time,
&mut bets,
&mut punish_users,
);
add_bets(
&user_id,
&CtaBetType::Late,
&reactions_late,
&mut bets,
&mut punish_users,
);
add_bets(
&user_id,
&CtaBetType::Early,
&reactions_early,
&mut bets,
&mut punish_users,
);
for user in bets.keys() {
User::take_funds(&ctx.data().db, *user, 100)?;
}
let winners: Vec<UserId> = bets
.iter()
.filter(|(_, bet)| **bet == outcome)
.filter(|(user, _)| !punish_users.contains(user))
.map(|(id, _)| *id)
.collect();
let actual_timestamp = Timestamp::from(arr_time.unwrap());
ctx.reply(format!(
"# {} Train has arrived @ {}",
outcome.emoji(),
poise::serenity_prelude::utils::FormattedTimestamp::new(
actual_timestamp,
Some(FormattedTimestampStyle::LongTime)
)
))
.await?;
if winners.is_empty() {
ctx.reply("Looks like no one won, too bad...").await?;
} else {
let payout = (100.0 * outcome.payout_factor()) as u32;
let mut winner_msg = MessageBuilder::new();
winner_msg.push_line("## Congrats to our winners:");
winner_msg.push_line(format!("They each get {} Fren Coins!", payout));
for winner in &winners {
User::give_funds(&ctx.data().db, *winner, payout)?;
winner_msg.push_line(format!("* {}", winner.mention()));
}
ctx.reply(winner_msg.build()).await?;
}
if !punish_users.is_empty() {
let mut cheater_msg = MessageBuilder::new();
cheater_msg
.push_line("## NOW FOR YOU CHEATING FUCKS, HOPE YOU ENJOY NOT WINNING ANYTHING:");
for cheater in &punish_users {
cheater_msg.push_line(format!("* {}", cheater.mention()));
}
ctx.reply(cheater_msg.build()).await?;
}
Ok(())
}
fn add_bets(
bot_user: &UserId,
bet_outcome: &CtaBetType,
reactions: &Vec<poise::serenity_prelude::User>,
bets: &mut HashMap<UserId, CtaBetType>,
punish_users: &mut HashSet<UserId>,
) {
for user in reactions {
if &user.id == bot_user {
continue;
}
if bets.contains_key(&user.id) {
debug!("Punishing user id {}", user.id);
punish_users.insert(user.id);
continue;
}
debug!("Adding User id {} to {}", user.id, bet_outcome.emoji());
bets.insert(user.id, *bet_outcome);
}
}

View File

@ -21,6 +21,7 @@ pub enum Error {
CommandError(String),
IoError(std::io::Error),
VoiceError(VoiceError),
CTAError(cta_api::Error),
}
impl StdError for Error {}
@ -79,6 +80,12 @@ impl From<VoiceError> for Error {
}
}
impl From<cta_api::Error> for Error {
fn from(value: cta_api::Error) -> Self {
Self::CTAError(value)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@ -95,6 +102,7 @@ impl Display for Error {
Error::CommandError(err_msg) => write!(f, "{}", err_msg),
Error::IoError(err) => write!(f, "IO Error: {}", err),
Error::VoiceError(err) => write!(f, "Voice error: {}", err),
Error::CTAError(err) => write!(f, "The CTA had an error, I'm shocked: {}", err),
}
}
}

View File

@ -21,6 +21,7 @@ static START: Once = Once::new();
#[tokio::main]
async fn main() {
let args: Args = Args::from_args();
tracing_subscriber::fmt::init();
let cfg = match BotConfig::new(&args.cfg_path) {
Ok(cfg) => cfg,
@ -30,8 +31,6 @@ async fn main() {
}
};
tracing_subscriber::fmt::init();
START.call_once(|| {
magick_wand_genesis();
});

View File

@ -111,8 +111,12 @@ impl Task {
}
TaskType::CheckBirthdays => {
info!("Checking Birthdays");
let time =
chrono_tz::America::Chicago.from_utc_datetime(&Utc::now().naive_utc());
let todays_birthdays =
BirthdayEntry::todays_birthdays(&data.db, chrono::Utc::now().date_naive())?;
BirthdayEntry::todays_birthdays(&data.db, time.date_naive())?;
for birth in todays_birthdays {
if let Ok(user) =

View File

@ -97,6 +97,16 @@ impl User {
Ok(())
}
pub fn take_funds(db: &Database, discord_id: UserId, amount: u32) -> Result<(), Error> {
let mut wallet = Self::get_user(db, discord_id)?;
wallet.coin_count -= amount as i64;
db.insert::<User>(wallet)?;
Ok(())
}
pub fn give_item(
db: &Database,
discord_id: UserId,