From c644874fefbab7bf32bf4c8840fc5110c910b9c1 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 29 Sep 2024 12:45:05 -0600 Subject: [PATCH] Improved `start_session` performance and added checklist --- src/bot.rs | 106 +++++++++++++++++++++++++++++-------------- src/config.rs | 19 ++++++++ src/model/session.rs | 10 +++- 3 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 8e849c3..9155861 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -2,11 +2,11 @@ use crate::config::BotConfig; use crate::context::Context; use crate::model::session::{Session, SessionConfig}; use chrono::Utc; -use log::{debug, info}; +use log::{debug, error, info}; use poise::futures_util::{Stream, StreamExt}; use poise::serenity_prelude::{ - futures, AutocompleteChoice, CreateAttachment, EditScheduledEvent, MessageBuilder, - ScheduledEventId, ScheduledEventStatus, + futures, AutocompleteChoice, CreateAttachment, CreateEmbed, EditScheduledEvent, GatewayIntents, + MessageBuilder, ScheduledEventId, ScheduledEventStatus, }; use poise::CreateReply; use raas_types::raas::bot::roll::{roll_response, Roll, RollCmd}; @@ -113,7 +113,7 @@ async fn create_session( let path = ctx.data().config.session_config_path.clone(); let mut session_config = ctx.data().session_config.lock().await; - session_config.create_session(event.id).await; + session_config.create_session(event.id, &event.name); session_config.save_config(path).await.unwrap(); @@ -131,30 +131,75 @@ async fn start_session( #[autocomplete = "autocomplete_session"] session: ScheduledEventId, ) -> Result<(), Error> { - let sessions = &mut ctx.data().session_config.lock().await; + let event = { + let sessions = &mut ctx.data().session_config.lock().await; - let session = sessions - .sessions - .iter() - .find(|s| s.event == session) - .unwrap(); + let session = sessions + .sessions + .iter() + .find(|s| s.event == session) + .cloned() + .unwrap(); + let event = match ctx + .guild_id() + .unwrap() + .scheduled_event(ctx.http(), session.event, false) + .await + { + Ok(e) => e, + Err(err) => { + error!("Event '{}', no longer available", session.event); + + sessions.remove_session(session.event); + + sessions + .save_config(ctx.data().config.session_config_path.clone()) + .await?; + + return Err(err.into()); + } + }; + + sessions.active_session = Some(event.id); + + sessions + .save_config(ctx.data().config.session_config_path.clone()) + .await + .unwrap(); + + event + }; + + ctx.reply(format!("Started session '{}'", event.name)) + .await?; + + ctx.send( + CreateReply::default().reply(true).embed( + CreateEmbed::new() + .title(format!("{} started", event.name)) + .field( + "Checklist", + ctx.data().config.checklist.format_as_markdown(), + false, + ), + ), + ) + .await?; + + // Note: This needs to be done last to get around timeouts caused by editing the event during event processing let event = ctx .guild_id() .unwrap() .edit_scheduled_event( ctx.http(), - session.event, + event.id, EditScheduledEvent::new().status(ScheduledEventStatus::Active), ) - .await?; + .await + .unwrap(); - ctx.reply(format!("Started session '{}'", event.name)) - .await?; - - sessions.active_session = Some(event.id); - - sessions.save_config(ctx.data().config.session_config_path.clone()).await?; + info!("Started event '{}'", event.name); Ok(()) } @@ -182,36 +227,29 @@ async fn stop_session(ctx: BotContext<'_>) -> Result<(), Error> { .await?; } } + sessions.remove_session(session); } else { ctx.reply("No sessions in progress!").await?; } sessions.active_session = None; + sessions + .save_config(ctx.data().config.session_config_path.clone()) + .await + .unwrap(); Ok(()) } async fn autocomplete_session<'a>( ctx: BotContext<'a>, partial: &'a str, -) -> impl Stream + 'a { +) -> impl Stream + 'a { let sessions: Vec = { ctx.data().session_config.lock().await.sessions.clone() }; futures::stream::iter(sessions).filter_map(move |s| async move { - let event = ctx - .guild_id() - .unwrap() - .scheduled_event(ctx.http(), s.event, false) - .await; - - if let Ok(event) = event { - if event.status == ScheduledEventStatus::Scheduled - && event.name.matches(partial).count() > 0 - { - Some(AutocompleteChoice::new(event.name, event.id.to_string())) - } else { - None - } + if s.name.matches(partial).count() > 0 { + Some(AutocompleteChoice::new(s.name, s.event.to_string())) } else { None } @@ -221,7 +259,7 @@ async fn autocomplete_session<'a>( pub async fn start_bot(config: BotConfig) { info!("Starting bot!"); - let intents = poise::serenity_prelude::GatewayIntents::non_privileged(); + let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::GUILD_SCHEDULED_EVENTS; let token = config.bot_token.clone(); diff --git a/src/config.rs b/src/config.rs index d68a5f2..55f5cab 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,5 @@ use config::{Config, File}; +use poise::serenity_prelude::MessageBuilder; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; use structopt::StructOpt; @@ -8,11 +9,29 @@ pub struct Args { pub config_path: PathBuf, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SessionCheckList { + steps: Vec, +} + +impl SessionCheckList { + pub fn format_as_markdown(&self) -> String { + let mut msg = MessageBuilder::new(); + + for step in &self.steps { + msg.push_line(format!("* {}", step)); + } + + msg.build() + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BotConfig { pub bot_token: String, pub raas_url: String, pub session_config_path: PathBuf, + pub checklist: SessionCheckList, } impl BotConfig { diff --git a/src/model/session.rs b/src/model/session.rs index be06d23..05216fb 100644 --- a/src/model/session.rs +++ b/src/model/session.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Session { + pub name: String, pub event: ScheduledEventId, pub scenes: Vec, } @@ -45,10 +46,15 @@ impl SessionConfig { tokio::fs::write(path, toml::to_string(self).unwrap()).await } - pub async fn create_session(&mut self, event: ScheduledEventId) { + pub fn create_session(&mut self, event: ScheduledEventId, name: &str) { self.sessions.push(Session { + name: name.to_string(), event, scenes: vec![], - }) + }); + } + + pub fn remove_session(&mut self, event: ScheduledEventId) { + self.sessions.retain(|s| s.event != event); } }