From 71750ce5841f059c2725874601afc4aa2d59e382 Mon Sep 17 00:00:00 2001 From: DaXcess Date: Sun, 13 Nov 2022 12:22:30 +0100 Subject: [PATCH] Hopefully fix some hang situations --- src/bot/commands/music/join.rs | 85 ++++++++++++++++++++++++++++++++++ src/ipc/mod.rs | 4 -- src/player.rs | 27 +++++++---- src/session/mod.rs | 19 ++++++-- src/utils/spotify.rs | 1 + 5 files changed, 119 insertions(+), 17 deletions(-) diff --git a/src/bot/commands/music/join.rs b/src/bot/commands/music/join.rs index e5205df..de3c675 100644 --- a/src/bot/commands/music/join.rs +++ b/src/bot/commands/music/join.rs @@ -41,6 +41,91 @@ pub fn run(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutpu } }; + // Check for Voice Channel permissions + { + let channel = match ctx.cache.guild_channel(channel_id) { + Some(channel) => channel, + None => { + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("Cannot join voice channel") + .description("The voice channel you are in is not available") + .status(Status::Error) + .build(), + true, + ) + .await; + + return; + } + }; + + if let Ok(permissions) = + channel.permissions_for_user(&ctx.cache, &ctx.cache.current_user_id()) + { + if !permissions.view_channel() || !permissions.connect() || !permissions.speak() { + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("Cannot join voice channel") + .description("I do not have the permissions to connect to that voice channel") + .status(Status::Error) + .build(), + true, + ) + .await; + + return; + } + } + } + + // Check for Text Channel permissions + { + let channel = match ctx.cache.guild_channel(&command.channel_id) { + Some(channel) => channel, + None => { + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("Cannot join voice channel") + .description("The text channel you are in is not available") + .status(Status::Error) + .build(), + true, + ) + .await; + + return; + } + }; + + if let Ok(permissions) = + channel.permissions_for_user(&ctx.cache, &ctx.cache.current_user_id()) + { + if !permissions.view_channel() || !permissions.send_messages() || !permissions.embed_links() + { + respond_message( + &ctx, + &command, + EmbedBuilder::new() + .title("Cannot join voice channel") + .description("I do not have the permissions to speak in this text channel") + .status(Status::Error) + .build(), + true, + ) + .await; + + return; + } + } + } + let data = ctx.data.read().await; let mut session_manager = data.get::().unwrap().clone(); diff --git a/src/ipc/mod.rs b/src/ipc/mod.rs index 6b231b9..0c9dff6 100644 --- a/src/ipc/mod.rs +++ b/src/ipc/mod.rs @@ -63,10 +63,6 @@ impl Client { .map_err(IpcError::Bincode) } - pub fn recv(&self) -> Result { - self.rx.lock().unwrap().recv() - } - pub fn try_recv(&self) -> Result { self.rx.lock().unwrap().try_recv() } diff --git a/src/player.rs b/src/player.rs index 693828c..ab80fc3 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,3 +1,6 @@ +use std::time::Duration; + +use ipc_channel::ipc::{IpcError, TryRecvError}; use librespot::{ connect::spirc::Spirc, core::{ @@ -11,7 +14,7 @@ use librespot::{ player::{Player, PlayerEvent}, }, }; -use log::{debug, error, trace, warn}; +use log::{debug, error, warn}; use serde_json::json; use crate::{ @@ -56,8 +59,6 @@ impl SpoticordPlayer { session.shutdown(); } - trace!("Creating Spotify session..."); - // Connect the session let (session, _) = match Session::connect(session_config, credentials, None, false).await { Ok((session, credentials)) => (session, credentials), @@ -106,8 +107,6 @@ impl SpoticordPlayer { let device_id = session.device_id().to_owned(); let ipc = self.client.clone(); - trace!("Successfully created Spotify session"); - // IPC Handler tokio::spawn(async move { let client = reqwest::Client::new(); @@ -129,8 +128,6 @@ impl SpoticordPlayer { if resp.status() == 202 { debug!("Successfully switched to device"); break; - } else { - trace!("Device switch failed with status {}", resp.status()); } retries -= 1; @@ -219,7 +216,7 @@ impl SpoticordPlayer { }); self.spirc = Some(spirc); - session.spawn(spirc_task); + tokio::spawn(spirc_task); } pub fn stop(&mut self) { @@ -242,9 +239,21 @@ pub async fn main() { let mut player = SpoticordPlayer::create(client.clone()); loop { - let message = match client.recv() { + let message = match client.try_recv() { Ok(message) => message, Err(why) => { + if let TryRecvError::Empty = why { + // No message, wait a bit and try again + tokio::time::sleep(Duration::from_millis(25)).await; + + continue; + } else if let TryRecvError::IpcError(why) = &why { + if let IpcError::Disconnected = why { + debug!("IPC connection closed, goodbye"); + break; + } + } + error!("Failed to receive message: {}", why); break; } diff --git a/src/session/mod.rs b/src/session/mod.rs index 7905940..17fa28d 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -187,6 +187,7 @@ impl SpoticordSession { continue; } else if let TryRecvError::IpcError(why) = &why { if let IpcError::Disconnected = why { + trace!("IPC connection closed, exiting IPC handler"); break; } } @@ -457,15 +458,25 @@ impl SpoticordSession { /// Called when the player must stop, but not leave the call async fn player_stopped(&mut self) { - if let Err(why) = self.track.pause() { - error!("Failed to pause track: {:?}", why); - } - // Disconnect from Spotify if let Err(why) = self.client.send(IpcPacket::Disconnect) { error!("Failed to send disconnect packet: {:?}", why); } + /* So this is really annoying, but necessary. + * If we pause songbird too quickly, the player would still have + * some audio to write to stdout. Because songbird is paused, + * the audio is never read, and the player process will hang. + * + * So yeah we just blatanly wait a second, and hope that's enough. + * Most likely causes issues when the system is a bit slow. + */ + tokio::time::sleep(Duration::from_millis(1000)).await; + + if let Err(why) = self.track.pause() { + error!("Failed to pause track: {:?}", why); + } + // Clear owner let mut owner = self.owner.write().await; if let Some(owner_id) = owner.take() { diff --git a/src/utils/spotify.rs b/src/utils/spotify.rs index 7414b8a..2707d08 100644 --- a/src/utils/spotify.rs +++ b/src/utils/spotify.rs @@ -68,6 +68,7 @@ pub async fn get_username(token: impl Into) -> Result { } if response.status() != 200 { + error!("Failed to get username: {}", response.status()); return Err( format!( "Failed to get track info: Invalid status code: {}",