Hopefully fix some hang situations

main
DaXcess 2022-11-13 12:22:30 +01:00
parent 3deb9be06f
commit 71750ce584
5 changed files with 119 additions and 17 deletions

View File

@ -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 data = ctx.data.read().await;
let mut session_manager = data.get::<SessionManager>().unwrap().clone(); let mut session_manager = data.get::<SessionManager>().unwrap().clone();

View File

@ -63,10 +63,6 @@ impl Client {
.map_err(IpcError::Bincode) .map_err(IpcError::Bincode)
} }
pub fn recv(&self) -> Result<IpcPacket, IpcError> {
self.rx.lock().unwrap().recv()
}
pub fn try_recv(&self) -> Result<IpcPacket, TryRecvError> { pub fn try_recv(&self) -> Result<IpcPacket, TryRecvError> {
self.rx.lock().unwrap().try_recv() self.rx.lock().unwrap().try_recv()
} }

View File

@ -1,3 +1,6 @@
use std::time::Duration;
use ipc_channel::ipc::{IpcError, TryRecvError};
use librespot::{ use librespot::{
connect::spirc::Spirc, connect::spirc::Spirc,
core::{ core::{
@ -11,7 +14,7 @@ use librespot::{
player::{Player, PlayerEvent}, player::{Player, PlayerEvent},
}, },
}; };
use log::{debug, error, trace, warn}; use log::{debug, error, warn};
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
@ -56,8 +59,6 @@ impl SpoticordPlayer {
session.shutdown(); session.shutdown();
} }
trace!("Creating Spotify session...");
// Connect the session // Connect the session
let (session, _) = match Session::connect(session_config, credentials, None, false).await { let (session, _) = match Session::connect(session_config, credentials, None, false).await {
Ok((session, credentials)) => (session, credentials), Ok((session, credentials)) => (session, credentials),
@ -106,8 +107,6 @@ impl SpoticordPlayer {
let device_id = session.device_id().to_owned(); let device_id = session.device_id().to_owned();
let ipc = self.client.clone(); let ipc = self.client.clone();
trace!("Successfully created Spotify session");
// IPC Handler // IPC Handler
tokio::spawn(async move { tokio::spawn(async move {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -129,8 +128,6 @@ impl SpoticordPlayer {
if resp.status() == 202 { if resp.status() == 202 {
debug!("Successfully switched to device"); debug!("Successfully switched to device");
break; break;
} else {
trace!("Device switch failed with status {}", resp.status());
} }
retries -= 1; retries -= 1;
@ -219,7 +216,7 @@ impl SpoticordPlayer {
}); });
self.spirc = Some(spirc); self.spirc = Some(spirc);
session.spawn(spirc_task); tokio::spawn(spirc_task);
} }
pub fn stop(&mut self) { pub fn stop(&mut self) {
@ -242,9 +239,21 @@ pub async fn main() {
let mut player = SpoticordPlayer::create(client.clone()); let mut player = SpoticordPlayer::create(client.clone());
loop { loop {
let message = match client.recv() { let message = match client.try_recv() {
Ok(message) => message, Ok(message) => message,
Err(why) => { 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); error!("Failed to receive message: {}", why);
break; break;
} }

View File

@ -187,6 +187,7 @@ impl SpoticordSession {
continue; continue;
} else if let TryRecvError::IpcError(why) = &why { } else if let TryRecvError::IpcError(why) = &why {
if let IpcError::Disconnected = why { if let IpcError::Disconnected = why {
trace!("IPC connection closed, exiting IPC handler");
break; break;
} }
} }
@ -457,15 +458,25 @@ impl SpoticordSession {
/// Called when the player must stop, but not leave the call /// Called when the player must stop, but not leave the call
async fn player_stopped(&mut self) { async fn player_stopped(&mut self) {
if let Err(why) = self.track.pause() {
error!("Failed to pause track: {:?}", why);
}
// Disconnect from Spotify // Disconnect from Spotify
if let Err(why) = self.client.send(IpcPacket::Disconnect) { if let Err(why) = self.client.send(IpcPacket::Disconnect) {
error!("Failed to send disconnect packet: {:?}", why); 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 // Clear owner
let mut owner = self.owner.write().await; let mut owner = self.owner.write().await;
if let Some(owner_id) = owner.take() { if let Some(owner_id) = owner.take() {

View File

@ -68,6 +68,7 @@ pub async fn get_username(token: impl Into<String>) -> Result<String, String> {
} }
if response.status() != 200 { if response.status() != 200 {
error!("Failed to get username: {}", response.status());
return Err( return Err(
format!( format!(
"Failed to get track info: Invalid status code: {}", "Failed to get track info: Invalid status code: {}",