Gateway: Add connection timeout, add Config to gateway. (#51)

This change fixes tasks hanging due to rare cases of messages being lost between full Discord reconnections by placing a configurable timeout on the `ConnectionInfo` responses. This is a companion fix to [serenity#1255](https://github.com/serenity-rs/serenity/pull/1255). To make this doable, `Config`s are now used by all versions of `Songbird`/`Call`, and relevant functions are  added to simplify setup with configuration. These are now non-exhaustive, correcting an earlier oversight. For future extensibility, this PR moves the return type of `join`/`join_gateway` into a custom future (no longer leaking flume's `RecvFut` type).

Additionally, this fixes the Makefile's feature sets for driver/gateway-only compilation.

This is a breaking change in:
* the return types of `join`/`join_gateway`
* moving `crate::driver::Config` -> `crate::Config`,
* `Config` and `JoinError` becoming `#[non_breaking]`.

This was tested via `cargo make ready`, and by testing `examples/serenity/voice_receive` with various timeout settings.
This commit is contained in:
Kyle Simpson
2021-03-29 19:51:13 +01:00
parent f449d4f679
commit 1fc3dc2259
18 changed files with 426 additions and 119 deletions

View File

@@ -1,10 +1,9 @@
#[cfg(feature = "driver-core")]
use crate::driver::Config;
use crate::{
error::{JoinError, JoinResult},
id::{ChannelId, GuildId, UserId},
shards::Sharder,
Call,
Config,
ConnectionInfo,
};
#[cfg(feature = "serenity")]
@@ -50,9 +49,7 @@ pub struct Songbird {
client_data: PRwLock<ClientData>,
calls: DashMap<GuildId, Arc<Mutex<Call>>>,
sharder: Sharder,
#[cfg(feature = "driver-core")]
driver_config: PRwLock<Option<Config>>,
config: PRwLock<Option<Config>>,
}
impl Songbird {
@@ -63,13 +60,21 @@ impl Songbird {
///
/// [registered]: crate::serenity::register_with
pub fn serenity() -> Arc<Self> {
Self::serenity_from_config(Default::default())
}
#[cfg(feature = "serenity")]
/// Create a new Songbird instance for serenity, using the given configuration.
///
/// This must be [registered] after creation.
///
/// [registered]: crate::serenity::register_with
pub fn serenity_from_config(config: Config) -> Arc<Self> {
Arc::new(Self {
client_data: Default::default(),
calls: Default::default(),
sharder: Sharder::Serenity(Default::default()),
#[cfg(feature = "driver-core")]
driver_config: Default::default(),
config: Some(config).into(),
})
}
@@ -82,6 +87,26 @@ impl Songbird {
///
/// [`process`]: Songbird::process
pub fn twilight<U>(cluster: Cluster, shard_count: u64, user_id: U) -> Arc<Self>
where
U: Into<UserId>,
{
Self::twilight_from_config(cluster, shard_count, user_id, Default::default())
}
#[cfg(feature = "twilight")]
/// Create a new Songbird instance for twilight.
///
/// Twilight handlers do not need to be registered, but
/// users are responsible for passing in any events using
/// [`process`].
///
/// [`process`]: Songbird::process
pub fn twilight_from_config<U>(
cluster: Cluster,
shard_count: u64,
user_id: U,
config: Config,
) -> Arc<Self>
where
U: Into<UserId>,
{
@@ -93,9 +118,7 @@ impl Songbird {
}),
calls: Default::default(),
sharder: Sharder::Twilight(cluster),
#[cfg(feature = "driver-core")]
driver_config: Default::default(),
config: Some(config).into(),
})
}
@@ -144,23 +167,30 @@ impl Songbird {
.get_shard(shard)
.expect("Failed to get shard handle: shard_count incorrect?");
#[cfg(feature = "driver-core")]
let call = Call::from_driver_config(
let call = Call::from_config(
guild_id,
shard_handle,
info.user_id,
self.driver_config.read().clone().unwrap_or_default(),
self.config.read().clone().unwrap_or_default(),
);
#[cfg(not(feature = "driver-core"))]
let call = Call::new(guild_id, shard_handle, info.user_id);
Arc::new(Mutex::new(call))
})
.clone()
})
}
/// Sets a shared configuration for all drivers created from this
/// manager.
///
/// Changes made here will apply to new Call and Driver instances only.
///
/// Requires the `"driver"` feature.
pub fn set_config(&self, new_config: Config) {
let mut config = self.config.write();
*config = Some(new_config);
}
fn manager_info(&self) -> ClientData {
let client_data = self.client_data.write();
@@ -213,10 +243,7 @@ impl Songbird {
};
let result = match stage_1 {
Ok(chan) => chan
.await
.map_err(|_| JoinError::Dropped)
.and_then(|x| x.map_err(JoinError::from)),
Ok(chan) => chan.await,
Err(e) => Err(e),
};
@@ -401,20 +428,6 @@ impl VoiceGatewayManager for Songbird {
}
}
#[cfg(feature = "driver-core")]
impl Songbird {
/// Sets a shared configuration for all drivers created from this
/// manager.
///
/// Changes made here will apply to new Call and Driver instances only.
///
/// Requires the `"driver"` feature.
pub fn set_config(&self, new_config: Config) {
let mut config = self.driver_config.write();
*config = Some(new_config);
}
}
#[inline]
fn shard_id(guild_id: u64, shard_count: u64) -> u64 {
(guild_id >> 22) % shard_count