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:
@@ -11,7 +11,11 @@ use xsalsa20poly1305::aead::Error as CryptoError;
|
||||
|
||||
/// Errors encountered while connecting to a Discord voice server over the driver.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// The driver hung up an internal signaller, either due to another connection attempt
|
||||
/// or a crash.
|
||||
AttemptDiscarded,
|
||||
/// An error occurred during [en/de]cryption of voice packets or key generation.
|
||||
Crypto(CryptoError),
|
||||
/// Server did not return the expected crypto mode during negotiation.
|
||||
@@ -83,6 +87,7 @@ impl fmt::Display for Error {
|
||||
write!(f, "Failed to connect to Discord RTP server: ")?;
|
||||
use Error::*;
|
||||
match self {
|
||||
AttemptDiscarded => write!(f, "connection attempt was aborted/discarded."),
|
||||
Crypto(c) => write!(f, "cryptography error {}.", c),
|
||||
CryptoModeInvalid => write!(f, "server changed negotiated encryption mode."),
|
||||
CryptoModeUnavailable => write!(f, "server did not offer chosen encryption mode."),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ impl Mixer {
|
||||
if temp_len > 0 || opus_len.is_some() {
|
||||
track.step_frame();
|
||||
} else if track.do_loop() {
|
||||
if let Some(time) = track.seek_time(Default::default()) {
|
||||
if let Ok(time) = track.seek_time(Default::default()) {
|
||||
// have to reproduce self.fire_event here
|
||||
// to circumvent the borrow checker's lack of knowledge.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user