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:
Kyle Simpson
2020-12-04 15:13:43 +00:00
committed by GitHub
parent 9fdbcd77be
commit f222ce9969
14 changed files with 276 additions and 134 deletions

View File

@@ -1,5 +1,5 @@
#[cfg(feature = "driver")]
use crate::{driver::Config, error::ConnectionResult};
use crate::driver::Config;
use crate::{
error::{JoinError, JoinResult},
id::{ChannelId, GuildId, UserId},
@@ -9,7 +9,6 @@ use crate::{
};
#[cfg(feature = "serenity")]
use async_trait::async_trait;
use flume::Receiver;
#[cfg(feature = "serenity")]
use futures::channel::mpsc::UnboundedSender as Sender;
use parking_lot::RwLock as PRwLock;
@@ -114,7 +113,7 @@ impl Songbird {
client_data.initialised = true;
}
/// Retreives a [`Call`] for the given guild, if one already exists.
/// Retrieves a [`Call`] for the given guild, if one already exists.
///
/// [`Call`]: Call
pub fn get<G: Into<GuildId>>(&self, guild_id: G) -> Option<Arc<Mutex<Call>>> {
@@ -122,7 +121,7 @@ impl Songbird {
map_read.get(&guild_id.into()).cloned()
}
/// Retreives a [`Call`] for the given guild, creating a new one if
/// Retrieves a [`Call`] for the given guild, creating a new one if
/// none is found.
///
/// This will not join any calls, or cause connection state to change.
@@ -186,11 +185,7 @@ impl Songbird {
/// [`Call`]: Call
/// [`get`]: Songbird::get
#[inline]
pub async fn join<C, G>(
&self,
guild_id: G,
channel_id: C,
) -> (Arc<Mutex<Call>>, JoinResult<Receiver<ConnectionResult<()>>>)
pub async fn join<C, G>(&self, guild_id: G, channel_id: C) -> (Arc<Mutex<Call>>, JoinResult<()>)
where
C: Into<ChannelId>,
G: Into<GuildId>,
@@ -203,14 +198,22 @@ impl Songbird {
&self,
guild_id: GuildId,
channel_id: ChannelId,
) -> (Arc<Mutex<Call>>, JoinResult<Receiver<ConnectionResult<()>>>) {
) -> (Arc<Mutex<Call>>, JoinResult<()>) {
let call = self.get_or_insert(guild_id);
let result = {
let stage_1 = {
let mut handler = call.lock().await;
handler.join(channel_id).await
};
let result = match stage_1 {
Ok(chan) => chan
.await
.map_err(|_| JoinError::Dropped)
.and_then(|x| x.map_err(JoinError::from)),
Err(e) => Err(e),
};
(call, result)
}
@@ -226,7 +229,7 @@ impl Songbird {
&self,
guild_id: G,
channel_id: C,
) -> (Arc<Mutex<Call>>, JoinResult<Receiver<ConnectionInfo>>)
) -> (Arc<Mutex<Call>>, JoinResult<ConnectionInfo>)
where
C: Into<ChannelId>,
G: Into<GuildId>,
@@ -238,14 +241,19 @@ impl Songbird {
&self,
guild_id: GuildId,
channel_id: ChannelId,
) -> (Arc<Mutex<Call>>, JoinResult<Receiver<ConnectionInfo>>) {
) -> (Arc<Mutex<Call>>, JoinResult<ConnectionInfo>) {
let call = self.get_or_insert(guild_id);
let result = {
let stage_1 = {
let mut handler = call.lock().await;
handler.join_gateway(channel_id).await
};
let result = match stage_1 {
Ok(chan) => chan.await.map_err(|_| JoinError::Dropped),
Err(e) => Err(e),
};
(call, result)
}