Improved `start_session` performance and added checklist

main
Joey Hines 2024-09-29 12:45:05 -06:00
parent 4bddb8371c
commit c644874fef
No known key found for this signature in database
GPG Key ID: 995E531F7A569DDB
3 changed files with 99 additions and 36 deletions

View File

@ -2,11 +2,11 @@ use crate::config::BotConfig;
use crate::context::Context; use crate::context::Context;
use crate::model::session::{Session, SessionConfig}; use crate::model::session::{Session, SessionConfig};
use chrono::Utc; use chrono::Utc;
use log::{debug, info}; use log::{debug, error, info};
use poise::futures_util::{Stream, StreamExt}; use poise::futures_util::{Stream, StreamExt};
use poise::serenity_prelude::{ use poise::serenity_prelude::{
futures, AutocompleteChoice, CreateAttachment, EditScheduledEvent, MessageBuilder, futures, AutocompleteChoice, CreateAttachment, CreateEmbed, EditScheduledEvent, GatewayIntents,
ScheduledEventId, ScheduledEventStatus, MessageBuilder, ScheduledEventId, ScheduledEventStatus,
}; };
use poise::CreateReply; use poise::CreateReply;
use raas_types::raas::bot::roll::{roll_response, Roll, RollCmd}; 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 path = ctx.data().config.session_config_path.clone();
let mut session_config = ctx.data().session_config.lock().await; 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(); session_config.save_config(path).await.unwrap();
@ -131,30 +131,75 @@ async fn start_session(
#[autocomplete = "autocomplete_session"] #[autocomplete = "autocomplete_session"]
session: ScheduledEventId, session: ScheduledEventId,
) -> Result<(), Error> { ) -> 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 let session = sessions
.sessions .sessions
.iter() .iter()
.find(|s| s.event == session) .find(|s| s.event == session)
.unwrap(); .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 let event = ctx
.guild_id() .guild_id()
.unwrap() .unwrap()
.edit_scheduled_event( .edit_scheduled_event(
ctx.http(), ctx.http(),
session.event, event.id,
EditScheduledEvent::new().status(ScheduledEventStatus::Active), EditScheduledEvent::new().status(ScheduledEventStatus::Active),
) )
.await?; .await
.unwrap();
ctx.reply(format!("Started session '{}'", event.name)) info!("Started event '{}'", event.name);
.await?;
sessions.active_session = Some(event.id);
sessions.save_config(ctx.data().config.session_config_path.clone()).await?;
Ok(()) Ok(())
} }
@ -182,36 +227,29 @@ async fn stop_session(ctx: BotContext<'_>) -> Result<(), Error> {
.await?; .await?;
} }
} }
sessions.remove_session(session);
} else { } else {
ctx.reply("No sessions in progress!").await?; ctx.reply("No sessions in progress!").await?;
} }
sessions.active_session = None; sessions.active_session = None;
sessions
.save_config(ctx.data().config.session_config_path.clone())
.await
.unwrap();
Ok(()) Ok(())
} }
async fn autocomplete_session<'a>( async fn autocomplete_session<'a>(
ctx: BotContext<'a>, ctx: BotContext<'a>,
partial: &'a str, partial: &'a str,
) -> impl Stream<Item = poise::serenity_prelude::AutocompleteChoice> + 'a { ) -> impl Stream<Item = AutocompleteChoice> + 'a {
let sessions: Vec<Session> = { ctx.data().session_config.lock().await.sessions.clone() }; let sessions: Vec<Session> = { ctx.data().session_config.lock().await.sessions.clone() };
futures::stream::iter(sessions).filter_map(move |s| async move { futures::stream::iter(sessions).filter_map(move |s| async move {
let event = ctx if s.name.matches(partial).count() > 0 {
.guild_id() Some(AutocompleteChoice::new(s.name, s.event.to_string()))
.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
}
} else { } else {
None None
} }
@ -221,7 +259,7 @@ async fn autocomplete_session<'a>(
pub async fn start_bot(config: BotConfig) { pub async fn start_bot(config: BotConfig) {
info!("Starting bot!"); 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(); let token = config.bot_token.clone();

View File

@ -1,4 +1,5 @@
use config::{Config, File}; use config::{Config, File};
use poise::serenity_prelude::MessageBuilder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use structopt::StructOpt; use structopt::StructOpt;
@ -8,11 +9,29 @@ pub struct Args {
pub config_path: PathBuf, pub config_path: PathBuf,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionCheckList {
steps: Vec<String>,
}
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)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BotConfig { pub struct BotConfig {
pub bot_token: String, pub bot_token: String,
pub raas_url: String, pub raas_url: String,
pub session_config_path: PathBuf, pub session_config_path: PathBuf,
pub checklist: SessionCheckList,
} }
impl BotConfig { impl BotConfig {

View File

@ -7,6 +7,7 @@ use std::path::PathBuf;
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Session { pub struct Session {
pub name: String,
pub event: ScheduledEventId, pub event: ScheduledEventId,
pub scenes: Vec<Scene>, pub scenes: Vec<Scene>,
} }
@ -45,10 +46,15 @@ impl SessionConfig {
tokio::fs::write(path, toml::to_string(self).unwrap()).await 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 { self.sessions.push(Session {
name: name.to_string(),
event, event,
scenes: vec![], scenes: vec![],
}) });
}
pub fn remove_session(&mut self, event: ScheduledEventId) {
self.sessions.retain(|s| s.event != event);
} }
} }