feat: graceful shutdown, try making join and leave work (but some bug fixes are still needed)

This commit is contained in:
2026-04-08 22:18:32 -04:00
parent 288a784870
commit d2511f7a55
6 changed files with 272 additions and 97 deletions

View File

@@ -1,12 +1,23 @@
use std::sync::LazyLock;
use twilight_model::application::{
command::{Command, CommandType},
interaction::Interaction,
};
use twilight_util::builder::command::CommandBuilder;
use crate::VCs;
use crate::command::State;
use snafu::{OptionExt, Snafu};
use std::sync::LazyLock;
use twilight_model::channel::message::{Embed, MessageFlags};
use twilight_model::http::interaction::{InteractionResponse, InteractionResponseType};
use twilight_model::id::marker::UserMarker;
use twilight_model::{
application::{
command::{Command, CommandType},
interaction::Interaction,
},
id::{
Id,
marker::{ChannelMarker, GuildMarker},
},
};
use twilight_util::builder::InteractionResponseDataBuilder;
use twilight_util::builder::command::CommandBuilder;
use twilight_util::builder::embed::EmbedBuilder;
const NAME: &str = "leave";
const DESCRIPTION: &str = "The bot will leave the VC it's in (so it won't record anyone anymore)";
@@ -18,7 +29,96 @@ pub static COMMAND: LazyLock<Command> = LazyLock::new(|| {
.build()
});
#[derive(Debug, Snafu)]
pub enum GetGuildAndVoiceChannelIdError {
/// this command was not used inside a guild (Discord server)
NotInGuild,
/// there are no voice chats in this guild
NoVCsInGuild,
/// the bot is not in a voice chat in this guild
BotNotInVC,
}
#[tracing::instrument]
pub fn get_guild_and_voice_channel_id(
bot_user_id: Id<UserMarker>,
interaction: &Interaction,
vcs: &VCs,
) -> Result<(Id<GuildMarker>, Id<ChannelMarker>), GetGuildAndVoiceChannelIdError> {
let guild_id = interaction.guild_id.context(NotInGuildSnafu)?;
let guild_vcs = vcs.get(&guild_id).context(NoVCsInGuildSnafu)?;
let &voice_channel_id = guild_vcs
.get_left_for(&bot_user_id)
.context(BotNotInVCSnafu)?;
Ok((guild_id, voice_channel_id))
}
fn get_guild_and_vc_error_to_embed(error: GetGuildAndVoiceChannelIdError) -> Embed {
match error {
GetGuildAndVoiceChannelIdError::NotInGuild => {
EmbedBuilder::new().title("Use this in a server").description("This bot can't tell which VC to leave if the command is used outside of a server (you might've used it in a DM?).").validate().unwrap().build()
}
GetGuildAndVoiceChannelIdError::NoVCsInGuild => {
EmbedBuilder::new().title("No VCs in this server").description("This bot can't leave VC because there aren't any in this server right now (therefore the bot must not be in any).").validate().unwrap().build()
},
GetGuildAndVoiceChannelIdError::BotNotInVC => {
EmbedBuilder::new().title("Not in a VC").description("This bot can't leave VC if it isn't in one in this server.").validate().unwrap().build()
},
}
}
#[tracing::instrument]
pub async fn handle(state: State, interaction: Interaction) {
todo!();
let (guild_id, voice_channel_id) =
match get_guild_and_voice_channel_id(state.discord_user_id, &interaction, &state.vcs) {
Ok((guild_id, voice_channel_id)) => (guild_id, voice_channel_id),
Err(error) => {
state
.discord_client
.interaction(state.discord_application_id)
.create_response(
interaction.id,
&interaction.token,
&InteractionResponse {
kind: InteractionResponseType::ChannelMessageWithSource,
data: Some(
InteractionResponseDataBuilder::new()
.embeds([get_guild_and_vc_error_to_embed(error)])
.flags(MessageFlags::EPHEMERAL)
.build(),
),
},
)
.await
.expect("TODO");
return;
}
};
state.songbird.leave(guild_id).await.expect("TODO");
tracing::error!("TODO: successfully left the call");
let channel_mention = format!("<#{voice_channel_id}>");
state
.discord_client
.interaction(state.discord_application_id)
.update_response(&interaction.token)
.embeds(Some(&[EmbedBuilder::new()
.title("Left VC")
.description(format!(
"This bot left {channel_mention} (and is thereby unable to record anymore)."
))
.validate()
.unwrap()
.build()]))
.await
.expect("TODO");
}