Driver, Tracks: Cleanup of leaky types (#20)
Main goal: a lot of nested future/result folding. This mainly modifies error handling for Tracks and TrackHandles to be more consistent, and hides the underlying channel result passing in get_info. Errors returned should be far clearer, and are domain specific rather than falling back to a very opaque use of the underlying channel error. It should be clearer to users why their handle commands failed, or why they can't make a ytdl track loop or similar. Also fixed/cleaned up Songbird::join(_gateway) to return in a single await, sparing the user from the underlying channel details and repeated Errs. I was trying for some time to extend the same graces to `Call`, but could not figure out a sane way to get a 'static version of the first future in the chain (i.e., the gateway send) so that the whole thing could happen after dropping the lock around the Call. I really wanted to fix this to happen as a single folded await too, but I think this might need some crazy hack or redesign.
This commit is contained in:
@@ -9,7 +9,7 @@ use crate::{
|
||||
info::{ConnectionInfo, ConnectionProgress},
|
||||
shards::Shard,
|
||||
};
|
||||
use flume::{Receiver, Sender};
|
||||
use flume::{r#async::RecvFut, Sender};
|
||||
use serde_json::json;
|
||||
use tracing::instrument;
|
||||
|
||||
@@ -173,11 +173,21 @@ impl Call {
|
||||
|
||||
#[cfg(feature = "driver")]
|
||||
/// Connect or switch to the given voice channel by its Id.
|
||||
///
|
||||
/// This function acts as a future in two stages:
|
||||
/// * The first `await` sends the request over the gateway.
|
||||
/// * The second `await`s a the driver's connection attempt.
|
||||
/// To prevent deadlock, any mutexes around this Call
|
||||
/// *must* be released before this result is queried.
|
||||
///
|
||||
/// When using [`Songbird::join`], this pattern is correctly handled for you.
|
||||
///
|
||||
/// [`Songbird::join`]: crate::Songbird::join
|
||||
#[instrument(skip(self))]
|
||||
pub async fn join(
|
||||
&mut self,
|
||||
channel_id: ChannelId,
|
||||
) -> JoinResult<Receiver<ConnectionResult<()>>> {
|
||||
) -> JoinResult<RecvFut<'static, ConnectionResult<()>>> {
|
||||
let (tx, rx) = flume::unbounded();
|
||||
|
||||
self.connection = Some((
|
||||
@@ -186,7 +196,7 @@ impl Call {
|
||||
Return::Conn(tx),
|
||||
));
|
||||
|
||||
self.update().await.map(|_| rx)
|
||||
self.update().await.map(|_| rx.into_recv_async())
|
||||
}
|
||||
|
||||
/// Join the selected voice channel, *without* running/starting an RTP
|
||||
@@ -194,11 +204,21 @@ impl Call {
|
||||
///
|
||||
/// Use this if you require connection info for lavalink,
|
||||
/// some other voice implementation, or don't want to use the driver for a given call.
|
||||
///
|
||||
/// This function acts as a future in two stages:
|
||||
/// * The first `await` sends the request over the gateway.
|
||||
/// * The second `await`s voice session data from Discord.
|
||||
/// To prevent deadlock, any mutexes around this Call
|
||||
/// *must* be released before this result is queried.
|
||||
///
|
||||
/// When using [`Songbird::join_gateway`], this pattern is correctly handled for you.
|
||||
///
|
||||
/// [`Songbird::join_gateway`]: crate::Songbird::join_gateway
|
||||
#[instrument(skip(self))]
|
||||
pub async fn join_gateway(
|
||||
&mut self,
|
||||
channel_id: ChannelId,
|
||||
) -> JoinResult<Receiver<ConnectionInfo>> {
|
||||
) -> JoinResult<RecvFut<'static, ConnectionInfo>> {
|
||||
let (tx, rx) = flume::unbounded();
|
||||
|
||||
self.connection = Some((
|
||||
@@ -207,7 +227,7 @@ impl Call {
|
||||
Return::Info(tx),
|
||||
));
|
||||
|
||||
self.update().await.map(|_| rx)
|
||||
self.update().await.map(|_| rx.into_recv_async())
|
||||
}
|
||||
|
||||
/// Leaves the current voice channel, disconnecting from it.
|
||||
|
||||
Reference in New Issue
Block a user