From 44d798d1d284c2c5c65aef9d5c11ba7df5c4de75 Mon Sep 17 00:00:00 2001 From: Ladislav Hano Date: Sun, 2 Feb 2025 00:22:09 +0100 Subject: [PATCH] fix: bot stuck when forcefully disconnected without using command --- src/handlers/voice_state_handler.rs | 121 ++++++++++++++++------------ 1 file changed, 71 insertions(+), 50 deletions(-) diff --git a/src/handlers/voice_state_handler.rs b/src/handlers/voice_state_handler.rs index 9ddb690..4a0feda 100644 --- a/src/handlers/voice_state_handler.rs +++ b/src/handlers/voice_state_handler.rs @@ -31,59 +31,80 @@ async fn get_channel_info(ctx: &Context, voice_state: &VoiceState) -> Option Option<()> { + // Logic is as follows: + // User connected -> voice_state_old is None (we handle this before this function) + // Bot was moved to different vc -> we check if the new voice_state has the bot's user id + // User moved to different VC or disconnected -> we check old channel instead (the bot could be still there) + let mut voice_channel: GuildChannel; + if voice_state.user_id == ctx.cache.current_user().id { + voice_channel = get_channel_info(&ctx, &voice_state).await?; + } + // Someone disconnected or moved channels + else { + voice_channel = get_channel_info(&ctx, &voice_state_old).await?; + } + + let manager = songbird::get(&ctx) + .await + .expect("Songbird Voice client placed in at initialisation.") + .clone(); + + // bot is not connected to any channel via songbird, don't need to do anything + if manager.get(voice_channel.guild_id).is_none() { + return None; + } + + // There is a problem with this implementation + // if bot is left alone and users joins and disconnects while this counts down + // this is not a big problem since we want to disconnect anyway + sleep(Duration::from_secs(120)).await; + + if voice_state.user_id == ctx.cache.current_user().id { + voice_channel = get_channel_info(&ctx, &voice_state).await?; + } + else { + voice_channel = get_channel_info(&ctx, &voice_state_old).await?; + } + + // bot is not connected to any channel via songbird, don't need to do anything + // ? could have been removed while sleeping if the song stopped playing + if manager.get(voice_channel.guild_id).is_none() { + return None; + } + + match manager.remove(voice_channel.guild_id).await { + Ok(()) => { + let _ = voice_channel.send_message(ctx.http, + CreateMessage::new() + .content("Disconnected to save bandwidth") + ).await; + } + Err(e) => { + let _ = send_error(ctx.http, e.to_string()).await; + } + } + + None +} + pub async fn handle_voice_update(ctx: Context, voice_state_old: VoiceState, voice_state: VoiceState) -> Option<()> { - // Logic is as follows: - // User connected -> voice_state_old is None (we handle this before this function) - // Bot was moved to different vc -> we check if the new voice_state has the bot's user id - // User moved to different VC or disconnected -> we check old channel instead (the bot could be still there) - let mut voice_channel: GuildChannel; - if voice_state.user_id == ctx.cache.current_user().id { - voice_channel = get_channel_info(&ctx, &voice_state).await?; - } - // Someone disconnected or moved channels - else { - voice_channel = get_channel_info(&ctx, &voice_state_old).await?; - } - - let manager = songbird::get(&ctx) - .await - .expect("Songbird Voice client placed in at initialisation.") - .clone(); - - // bot is not connected to any channel via songbird, don't need to do anything - if manager.get(voice_channel.guild_id).is_none() { - return None; - } - - // There is a problem with this implementation - // if bot is left alone and users joins and disconnects while this counts down - // this is not a big problem since we want to disconnect anyway - sleep(Duration::from_secs(120)).await; - - if voice_state.user_id == ctx.cache.current_user().id { - voice_channel = get_channel_info(&ctx, &voice_state).await?; - } - else { - voice_channel = get_channel_info(&ctx, &voice_state_old).await?; - } - - // bot is not connected to any channel via songbird, don't need to do anything - // ? could have been removed while sleeping if the song stopped playing - if manager.get(voice_channel.guild_id).is_none() { - return None; - } - - match manager.remove(voice_channel.guild_id).await { - Ok(()) => { - let _ = voice_channel.send_message(ctx.http, - CreateMessage::new() - .content("Disconnected to save bandwidth") - ).await; - } - Err(e) => { - let _ = send_error(ctx.http, e.to_string()).await; + // if the user was disconnected remove Songbird manager so it won't get stuck + // Actually this is not really a bug since we can handle disconnect and therefore saving the song queue for example + if voice_state.channel_id.is_none() && voice_state.user_id == ctx.cache.current_user().id { + let manager = songbird::get(&ctx) + .await + .expect("Songbird Voice client placed in at initialisation.") + .clone(); + + let guild_id = voice_state_old.guild_id?; + // bot is not connected to any channel via songbird, don't need to do anything + if manager.get(guild_id).is_some() { + let _ = manager.remove(guild_id).await; + return None; } } + handle_autodisconnect(ctx, voice_state_old, voice_state).await?; None }