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

View File

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

View File

@ -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;
}

View File

@ -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() {

View File

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