Driver: Automate (re)connection logic (#81)

This PR adds several enhancements to Driver connection logic:
* Driver (re)connection attempts now have a default timeout of around 10s.
* The driver will now attempt to retry full connection attempts using a user-provided strategy: currently, this defaults to 5 attempts under an exponential backoff strategy.
* The driver will now fire `DriverDisconnect` events at the end of any session -- this unifies (re)connection failure events with session expiry as seen in #76, which should provide users with enough detail to know *which* voice channel to reconnect to. Users still need to be careful to read the session/channel IDs to ensure that they aren't overwriting another join.

This has been tested using `cargo make ready`, and by setting low timeouts to force failures in the voice receive example (with some additional error handlers).

Closes #68.
This commit is contained in:
Kyle Simpson
2021-06-23 17:11:14 +01:00
parent 8381f8c461
commit 210e3ae584
17 changed files with 672 additions and 90 deletions

View File

@@ -7,6 +7,10 @@ use crate::{
use flume::SendError;
use serde_json::Error as JsonError;
use std::{error::Error as StdError, fmt, io::Error as IoError};
#[cfg(not(feature = "tokio-02-marker"))]
use tokio::time::error::Elapsed;
#[cfg(feature = "tokio-02-marker")]
use tokio_compat::time::Elapsed;
use xsalsa20poly1305::aead::Error as CryptoError;
/// Errors encountered while connecting to a Discord voice server over the driver.
@@ -38,6 +42,8 @@ pub enum Error {
InterconnectFailure(Recipient),
/// Error communicating with gateway server over WebSocket.
Ws(WsError),
/// Connection attempt timed out.
TimedOut,
}
impl From<CryptoError> for Error {
@@ -82,6 +88,12 @@ impl From<WsError> for Error {
}
}
impl From<Elapsed> for Error {
fn from(_e: Elapsed) -> Error {
Error::TimedOut
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to connect to Discord RTP server: ")?;
@@ -99,6 +111,7 @@ impl fmt::Display for Error {
Json(e) => e.fmt(f),
InterconnectFailure(e) => write!(f, "failed to contact other task ({:?})", e),
Ws(e) => write!(f, "websocket issue ({:?}).", e),
TimedOut => write!(f, "connection attempt timed out"),
}
}
}
@@ -118,6 +131,7 @@ impl StdError for Error {
Error::Json(e) => e.source(),
Error::InterconnectFailure(_) => None,
Error::Ws(_) => None,
Error::TimedOut => None,
}
}
}