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

@@ -15,7 +15,7 @@ mod decode_mode;
pub(crate) mod tasks;
pub use config::Config;
use connection::error::Result;
use connection::error::{Error, Result};
pub use crypto::*;
pub use decode_mode::DecodeMode;
@@ -30,7 +30,12 @@ use crate::{
EventHandler,
};
use audiopus::Bitrate;
use flume::{Receiver, SendError, Sender};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use flume::{r#async::RecvFut, SendError, Sender};
use tasks::message::CoreMessage;
use tracing::instrument;
@@ -80,13 +85,18 @@ impl Driver {
}
/// Connects to a voice channel using the specified server.
///
/// This method instantly contacts the driver tasks, and its
/// does not need to be `await`ed to start the actual connection.
#[instrument(skip(self))]
pub fn connect(&mut self, info: ConnectionInfo) -> Receiver<Result<()>> {
pub fn connect(&mut self, info: ConnectionInfo) -> Connect {
let (tx, rx) = flume::bounded(1);
self.raw_connect(info, tx);
rx
Connect {
inner: rx.into_recv_async(),
}
}
/// Connects to a voice channel using the specified server.
@@ -285,3 +295,24 @@ impl Drop for Driver {
let _ = self.sender.send(CoreMessage::Poison);
}
}
/// Future for a call to [`Driver::connect`].
///
/// This future awaits the *result* of a connection; the driver
/// is messaged at the time of the call.
///
/// [`Driver::connect`]: Driver::connect
pub struct Connect {
inner: RecvFut<'static, Result<()>>,
}
impl Future for Connect {
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.inner).poll(cx) {
Poll::Ready(r) => Poll::Ready(r.map_err(|_| Error::AttemptDiscarded).and_then(|x| x)),
Poll::Pending => Poll::Pending,
}
}
}