chore: remove /join and /leave to prevent confusion
This commit is contained in:
@@ -1,170 +0,0 @@
|
|||||||
use crate::{VCs, call::join_and_record, command::State};
|
|
||||||
use snafu::{OptionExt as _, Snafu};
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
use twilight_model::{
|
|
||||||
application::{
|
|
||||||
command::{Command, CommandType},
|
|
||||||
interaction::Interaction,
|
|
||||||
},
|
|
||||||
channel::message::{Embed, MessageFlags},
|
|
||||||
http::interaction::{InteractionResponse, InteractionResponseType},
|
|
||||||
id::{
|
|
||||||
Id,
|
|
||||||
marker::{ChannelMarker, GuildMarker},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use twilight_util::builder::{
|
|
||||||
InteractionResponseDataBuilder, command::CommandBuilder, embed::EmbedBuilder,
|
|
||||||
};
|
|
||||||
|
|
||||||
const NAME: &str = "join";
|
|
||||||
const DESCRIPTION: &str = "The bot will join the same VC as you (with intention to record)";
|
|
||||||
|
|
||||||
pub static COMMAND: LazyLock<Command> = LazyLock::new(|| {
|
|
||||||
CommandBuilder::new(NAME, DESCRIPTION, CommandType::ChatInput)
|
|
||||||
.validate()
|
|
||||||
.expect("command wasn't correct")
|
|
||||||
.build()
|
|
||||||
});
|
|
||||||
|
|
||||||
#[derive(Debug, Snafu)]
|
|
||||||
enum GetGuildAndVoiceChannelIdError {
|
|
||||||
/// this command was not used inside a guild (Discord server)
|
|
||||||
NotInGuild,
|
|
||||||
|
|
||||||
/// there is no user who invoked this command
|
|
||||||
NoUser,
|
|
||||||
|
|
||||||
/// the user is not in a voice chat in this guild
|
|
||||||
UserNotInVC,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
fn get_guild_and_voice_channel_id(
|
|
||||||
interaction: &Interaction,
|
|
||||||
vcs: &VCs,
|
|
||||||
) -> Result<(Id<GuildMarker>, Id<ChannelMarker>), GetGuildAndVoiceChannelIdError> {
|
|
||||||
let guild_id = interaction.guild_id.context(NotInGuildSnafu)?;
|
|
||||||
|
|
||||||
let user_id = interaction
|
|
||||||
.member
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|member| member.user.as_ref().map(|user| user.id))
|
|
||||||
.context(NoUserSnafu)?;
|
|
||||||
|
|
||||||
let &voice_channel_id = vcs
|
|
||||||
.get(&guild_id)
|
|
||||||
.context(UserNotInVCSnafu)?
|
|
||||||
.get_left_for(&user_id)
|
|
||||||
.context(UserNotInVCSnafu)?;
|
|
||||||
|
|
||||||
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 find a VC to join if the command is used outside of a server (you might've used it in a DM?).").validate().unwrap().build()
|
|
||||||
},
|
|
||||||
GetGuildAndVoiceChannelIdError::NoUser => {
|
|
||||||
EmbedBuilder::new().title("Not invoked by a user").description("This command works by joining the same VC as the user, but this bot didn't receive any user data. So did no user invoke it?! (This error should be impossible!)").validate().unwrap().build()
|
|
||||||
},
|
|
||||||
GetGuildAndVoiceChannelIdError::UserNotInVC => {
|
|
||||||
EmbedBuilder::new().title("You're not in a VC").description("This bot can't follow you into VC if you aren't in one in this server.").validate().unwrap().build()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(state))]
|
|
||||||
pub async fn handle(state: State, interaction: Interaction) {
|
|
||||||
let guild_and_voice_channel_id_res =
|
|
||||||
{ get_guild_and_voice_channel_id(&interaction, &state.vcs_sender.borrow()) };
|
|
||||||
let (guild_id, voice_channel_id) = match guild_and_voice_channel_id_res {
|
|
||||||
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
|
|
||||||
.discord_client
|
|
||||||
.interaction(state.discord_application_id)
|
|
||||||
.create_response(
|
|
||||||
interaction.id,
|
|
||||||
&interaction.token,
|
|
||||||
&InteractionResponse {
|
|
||||||
kind: InteractionResponseType::DeferredChannelMessageWithSource,
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("TODO");
|
|
||||||
|
|
||||||
match join_and_record()
|
|
||||||
.audio_channels(state.audio_channels.into())
|
|
||||||
.audio_sample_rate(state.audio_sample_rate.into())
|
|
||||||
.guild_id(guild_id)
|
|
||||||
.recording_manager(state.recording_manager)
|
|
||||||
.songbird(&state.songbird)
|
|
||||||
.user_manager(state.user_manager)
|
|
||||||
.voice_channel_id(voice_channel_id)
|
|
||||||
.call()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(()) => {
|
|
||||||
let channel_mention = format!("<#{voice_channel_id}>");
|
|
||||||
|
|
||||||
let info_mention = format!(
|
|
||||||
"</{}:{}>",
|
|
||||||
state.discord_info_command_name, state.discord_info_command_id
|
|
||||||
);
|
|
||||||
let opt_in_mention = format!(
|
|
||||||
"</{}:{}>",
|
|
||||||
state.discord_opt_in_command_name, state.discord_opt_in_command_id
|
|
||||||
);
|
|
||||||
let opt_out_mention = format!(
|
|
||||||
"</{}:{}>",
|
|
||||||
state.discord_opt_out_command_name, state.discord_opt_out_command_id
|
|
||||||
);
|
|
||||||
|
|
||||||
state
|
|
||||||
.discord_client
|
|
||||||
.interaction(state.discord_application_id)
|
|
||||||
.update_response(
|
|
||||||
&interaction.token,
|
|
||||||
).embeds(Some(&[
|
|
||||||
EmbedBuilder::new()
|
|
||||||
.title("Joined VC to record")
|
|
||||||
.description(format!("This bot joined {channel_mention} and intends to record. You can opt out with {opt_out_mention} or explicitly opt in with {opt_in_mention} (I'd appreciate this one). Please use {info_mention} for more information about this bot."))
|
|
||||||
.validate()
|
|
||||||
.unwrap()
|
|
||||||
.build()
|
|
||||||
]))
|
|
||||||
.await
|
|
||||||
.expect("TODO");
|
|
||||||
}
|
|
||||||
Err(join_error) => {
|
|
||||||
tracing::error!(?join_error);
|
|
||||||
let _ = state.songbird.remove(guild_id).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
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)";
|
|
||||||
|
|
||||||
pub static COMMAND: LazyLock<Command> = LazyLock::new(|| {
|
|
||||||
CommandBuilder::new(NAME, DESCRIPTION, CommandType::ChatInput)
|
|
||||||
.validate()
|
|
||||||
.expect("command wasn't correct")
|
|
||||||
.build()
|
|
||||||
});
|
|
||||||
|
|
||||||
#[derive(Debug, Snafu)]
|
|
||||||
pub enum GetGuildAndVoiceChannelIdError {
|
|
||||||
/// this command was not used inside a guild (Discord server)
|
|
||||||
NotInGuild,
|
|
||||||
|
|
||||||
/// there is no user who invoked this command
|
|
||||||
NoUser,
|
|
||||||
|
|
||||||
/// the bot is not in a voice chat in this guild
|
|
||||||
BotNotInVC,
|
|
||||||
|
|
||||||
/// the user is not in a voice chat with the bot in this guild
|
|
||||||
UserNotInVCWithBot,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub fn get_user_and_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 user_id = interaction
|
|
||||||
.member
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|member| member.user.as_ref().map(|user| user.id))
|
|
||||||
.context(NoUserSnafu)?;
|
|
||||||
|
|
||||||
let &bot_voice_channel_id = vcs
|
|
||||||
.get(&guild_id)
|
|
||||||
.context(BotNotInVCSnafu)?
|
|
||||||
.get_left_for(&bot_user_id)
|
|
||||||
.context(BotNotInVCSnafu)?;
|
|
||||||
|
|
||||||
let &user_voice_channel_id = vcs
|
|
||||||
.get(&guild_id)
|
|
||||||
.context(UserNotInVCWithBotSnafu)?
|
|
||||||
.get_left_for(&user_id)
|
|
||||||
.context(UserNotInVCWithBotSnafu)?;
|
|
||||||
|
|
||||||
if user_voice_channel_id != bot_voice_channel_id {
|
|
||||||
return Err(GetGuildAndVoiceChannelIdError::UserNotInVCWithBot);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((guild_id, bot_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::NoUser => {
|
|
||||||
EmbedBuilder::new().title("Not invoked by a user").description("This command works by joining the same VC as the user, but this bot didn't receive any user data. So did no user invoke it?! (This error should be impossible!)").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()
|
|
||||||
},
|
|
||||||
GetGuildAndVoiceChannelIdError::UserNotInVCWithBot => {
|
|
||||||
EmbedBuilder::new().title("Not in a VC with the Bot").description("You have to be in the VC with the bot to make it leave (to prevent griefing and abuse).").validate().unwrap().build()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub async fn handle(state: State, interaction: Interaction) {
|
|
||||||
let guild_and_voice_channel_id_result = {
|
|
||||||
get_user_and_guild_and_voice_channel_id(
|
|
||||||
state.discord_user_id,
|
|
||||||
&interaction,
|
|
||||||
&state.vcs_sender.borrow(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let (guild_id, voice_channel_id) = match guild_and_voice_channel_id_result {
|
|
||||||
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)
|
|
||||||
.create_response(interaction.id, &interaction.token,
|
|
||||||
&InteractionResponse {
|
|
||||||
kind: InteractionResponseType::ChannelMessageWithSource,
|
|
||||||
data: Some(
|
|
||||||
InteractionResponseDataBuilder::new()
|
|
||||||
.embeds([
|
|
||||||
EmbedBuilder::new()
|
|
||||||
.title("Left VC")
|
|
||||||
.description(format!(
|
|
||||||
"This bot left {channel_mention} (and is thereby unable to record anymore)."
|
|
||||||
))
|
|
||||||
.validate()
|
|
||||||
.unwrap()
|
|
||||||
.build()
|
|
||||||
])
|
|
||||||
.flags(MessageFlags::EPHEMERAL)
|
|
||||||
.build(),
|
|
||||||
),
|
|
||||||
},)
|
|
||||||
.await
|
|
||||||
.expect("TODO");
|
|
||||||
}
|
|
||||||
@@ -21,8 +21,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub mod info;
|
pub mod info;
|
||||||
pub mod join;
|
|
||||||
pub mod leave;
|
|
||||||
pub mod opt_in;
|
pub mod opt_in;
|
||||||
pub mod opt_out;
|
pub mod opt_out;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
@@ -65,8 +63,6 @@ where
|
|||||||
pub fn all() -> Vec<(&'static Command, BoxedHandler)> {
|
pub fn all() -> Vec<(&'static Command, BoxedHandler)> {
|
||||||
vec![
|
vec![
|
||||||
(&info::COMMAND, box_handler(info::handle)),
|
(&info::COMMAND, box_handler(info::handle)),
|
||||||
(&join::COMMAND, box_handler(join::handle)),
|
|
||||||
(&leave::COMMAND, box_handler(leave::handle)),
|
|
||||||
(&opt_in::COMMAND, box_handler(opt_in::handle)),
|
(&opt_in::COMMAND, box_handler(opt_in::handle)),
|
||||||
(&opt_out::COMMAND, box_handler(opt_out::handle)),
|
(&opt_out::COMMAND, box_handler(opt_out::handle)),
|
||||||
(&render::COMMAND, box_handler(render::handle)),
|
(&render::COMMAND, box_handler(render::handle)),
|
||||||
|
|||||||
Reference in New Issue
Block a user