aboutsummaryrefslogtreecommitdiff
path: root/src/client/context.rs
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2017-11-03 07:13:24 -0700
committerZeyla Hellyer <[email protected]>2017-11-03 07:13:38 -0700
commitb8efeaf5e920cbfc775cdee70f23aa41ab7b9dd5 (patch)
tree17eb07c8218f1e145d5eb3fba353fd1486b3874d /src/client/context.rs
parentMake the Client return a Result (diff)
downloadserenity-b8efeaf5e920cbfc775cdee70f23aa41ab7b9dd5.tar.xz
serenity-b8efeaf5e920cbfc775cdee70f23aa41ab7b9dd5.zip
Redo client internals + gateway
This commit is a rewrite of the client module's internals and the gateway. The main benefit of this is that there is either 0 or 1 lock retrievals per event received, and the ability to utilize the ShardManager both internally and in userland code has been improved. The primary rework is in the `serenity::client` module, which now includes a few more structures, some changes to existing ones, and more functionality (such as to the `ShardManager`). The two notable additions to the client-gateway bridge are the `ShardMessenger` and `ShardManagerMonitor`. The `ShardMessenger` is a simple-to-use interface for users to use to interact with shards. The user is given one of these in the `serenity::client::Context` in dispatches to the `serenity::client::EventHandler`. This can be used for updating the presence of a shard, sending a guild chunk message, or sending a user's defined WebSocket message. The `ShardManagerMonitor` is a loop run in its own thread, potentially the main thread, that is responsible for receiving messages over an mpsc channel on what to do with shards via the `ShardManager`. For example, it will receive a message to shutdown a single shard, restart a single shard, or shutdown the entire thing. Users, in most applications, will not interact with the `ShardManagerMonitor`. Users using the `serenity::client::Client` interact with only the `ShardMessenger`. The `ShardManager` is now usable by the user and is available to them, and contains public functions for shutdowns, initializations, restarts, and complete shutdowns of shards. It contains utility functions like determining whether the `ShardManager` is responsible for a shard of a given ID and the IDs of shards currently active (having an associated `ShardRunner`). It can be found on `serenity::client::Client::shard_manager`. Speaking of the `ShardRunner`, it no longer owns a clone of an Arc to its assigned `serenity::gateway::Shard`. It now completely owns the Shard. This means that in order to open the shard, a `ShardRunner` no longer has to repeatedly retrieve a lock to it. This reduces the number of lock retrievals per event dispatching cycle from 3 or 4 depending on event type to 0 or 1 depending on whether it's a message create _and_ if the framework is in use. To interact with the Shard, one must now go through the previously mentioned `ShardMessenger`, which the `ShardRunner` will check for messages from on a loop. `serenity::client::Context` is now slightly different. Instead of the `shard` field being `Arc<Mutex<Shard>>`, it is an instance of a `ShardMessenger`. The interface is the same (minus losing some Shard-specific methods like `latency`), and `Context`'s shortcuts still exist (like `Context::online` or `Context::set_game`). It now additionally includes a `Context::shard_id` field which is a u64 containing the ID of the shard that the event was dispatched from. `serenity::client::Client` has one changed field name, one field that is now public, and a new field. `Client::shard_runners` is now `Client::shard_manager` of type `Arc<Mutex<ShardManager>>`. The `Client::token` field is now public. This can, for example, be mutated on token resets if you know what you're doing. `Client::ws_uri` is new and contains the URI for shards to use when connecting to the gateway. Otherwise, the Client's usage is unchanged. `serenity::gateway::Shard` has a couple of minor changes and many more public methods and fields. The `autoreconnect`, `check_heartbeat`, `handle_event`, `heartbeat`, `identify`, `initialize`, `reset`, `resume`, `reconnect`, and `update_presence` methods are now public. The `token` structfield is now public. There are new getters for various structfields, such as `heartbeat_instants` and `last_heartbeat_ack`. The breaking change on the `Shard` is that `Shard::handle_event` now takes an event by reference and, instead of returning `Result<Option<Event>>`, it now returns `Result<Option<ShardAction>>`. `serenity::gateway::ShardAction` is a light enum determining an action that someone _should_/_must_ perform on the shard, e.g. reconnecting or identifying. This is determined by `Shard::handle_event`. In total, there aren't too many breaking changes that most of userland use cases has to deal with -- at most, changing some usage of `Context`. Retrieving information like a Shard's latency is currently not possible anymore but work will be done to make this functionality available again.
Diffstat (limited to 'src/client/context.rs')
-rw-r--r--src/client/context.rs65
1 files changed, 33 insertions, 32 deletions
diff --git a/src/client/context.rs b/src/client/context.rs
index a60aaa0..9b89cde 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -1,7 +1,7 @@
-use Result;
+use client::bridge::gateway::{ShardClientMessage, ShardMessenger};
+use std::sync::mpsc::Sender;
use std::sync::Arc;
use typemap::ShareMap;
-use gateway::Shard;
use model::*;
use parking_lot::Mutex;
@@ -12,7 +12,7 @@ use internal::prelude::*;
#[cfg(feature = "builder")]
use builder::EditProfile;
#[cfg(feature = "builder")]
-use {http, utils};
+use {Result, http, utils};
#[cfg(feature = "builder")]
use std::collections::HashMap;
@@ -38,21 +38,23 @@ pub struct Context {
///
/// [`Client::data`]: struct.Client.html#structfield.data
pub data: Arc<Mutex<ShareMap>>,
- /// The associated shard which dispatched the event handler.
- ///
- /// Note that if you are sharding, in relevant terms, this is the shard
- /// which received the event being dispatched.
- pub shard: Arc<Mutex<Shard>>,
+ /// The messenger to communicate with the shard runner.
+ pub shard: ShardMessenger,
+ /// The ID of the shard this context is related to.
+ pub shard_id: u64,
}
impl Context {
/// Create a new Context to be passed to an event handler.
- pub(crate) fn new(shard: Arc<Mutex<Shard>>,
- data: Arc<Mutex<ShareMap>>)
- -> Context {
+ pub(crate) fn new(
+ data: Arc<Mutex<ShareMap>>,
+ runner_tx: Sender<ShardClientMessage>,
+ shard_id: u64,
+ ) -> Context {
Context {
+ shard: ShardMessenger::new(runner_tx),
+ shard_id,
data,
- shard,
}
}
@@ -110,6 +112,7 @@ impl Context {
http::edit_profile(&edited)
}
+
/// Sets the current user as being [`Online`]. This maintains the current
/// game.
///
@@ -137,9 +140,9 @@ impl Context {
/// ```
///
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
+ #[inline]
pub fn online(&self) {
- let mut shard = self.shard.lock();
- shard.set_status(OnlineStatus::Online);
+ self.shard.set_status(OnlineStatus::Online);
}
/// Sets the current user as being [`Idle`]. This maintains the current
@@ -168,9 +171,9 @@ impl Context {
/// ```
///
/// [`Idle`]: ../model/enum.OnlineStatus.html#variant.Idle
+ #[inline]
pub fn idle(&self) {
- let mut shard = self.shard.lock();
- shard.set_status(OnlineStatus::Idle);
+ self.shard.set_status(OnlineStatus::Idle);
}
/// Sets the current user as being [`DoNotDisturb`]. This maintains the
@@ -199,9 +202,9 @@ impl Context {
/// ```
///
/// [`DoNotDisturb`]: ../model/enum.OnlineStatus.html#variant.DoNotDisturb
+ #[inline]
pub fn dnd(&self) {
- let mut shard = self.shard.lock();
- shard.set_status(OnlineStatus::DoNotDisturb);
+ self.shard.set_status(OnlineStatus::DoNotDisturb);
}
/// Sets the current user as being [`Invisible`]. This maintains the current
@@ -231,9 +234,9 @@ impl Context {
///
/// [`Event::Ready`]: ../model/event/enum.Event.html#variant.Ready
/// [`Invisible`]: ../model/enum.OnlineStatus.html#variant.Invisible
+ #[inline]
pub fn invisible(&self) {
- let mut shard = self.shard.lock();
- shard.set_status(OnlineStatus::Invisible);
+ self.shard.set_status(OnlineStatus::Invisible);
}
/// "Resets" the current user's presence, by setting the game to `None` and
@@ -265,9 +268,9 @@ impl Context {
/// [`Event::Resumed`]: ../model/event/enum.Event.html#variant.Resumed
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
/// [`set_presence`]: #method.set_presence
+ #[inline]
pub fn reset_presence(&self) {
- let mut shard = self.shard.lock();
- shard.set_presence(None, OnlineStatus::Online);
+ self.shard.set_presence(None, OnlineStatus::Online);
}
/// Sets the current game, defaulting to an online status of [`Online`].
@@ -303,9 +306,9 @@ impl Context {
/// ```
///
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
+ #[inline]
pub fn set_game(&self, game: Game) {
- let mut shard = self.shard.lock();
- shard.set_presence(Some(game), OnlineStatus::Online);
+ self.shard.set_presence(Some(game), OnlineStatus::Online);
}
/// Sets the current game, passing in only its name. This will automatically
@@ -351,8 +354,7 @@ impl Context {
url: None,
};
- let mut shard = self.shard.lock();
- shard.set_presence(Some(game), OnlineStatus::Online);
+ self.shard.set_presence(Some(game), OnlineStatus::Online);
}
/// Sets the current user's presence, providing all fields to be passed.
@@ -406,9 +408,9 @@ impl Context {
///
/// [`DoNotDisturb`]: ../model/enum.OnlineStatus.html#variant.DoNotDisturb
/// [`Idle`]: ../model/enum.OnlineStatus.html#variant.Idle
+ #[inline]
pub fn set_presence(&self, game: Option<Game>, status: OnlineStatus) {
- let mut shard = self.shard.lock();
- shard.set_presence(game, status);
+ self.shard.set_presence(game, status);
}
/// Disconnects the shard from the websocket, essentially "quiting" it.
@@ -417,9 +419,8 @@ impl Context {
/// until [`Client::start`] and vice versa are called again.
///
/// [`Client::start`]: ./struct.Client.html#method.start
- pub fn quit(&self) -> Result<()> {
- let mut shard = self.shard.lock();
-
- shard.shutdown_clean()
+ #[inline]
+ pub fn quit(&self) {
+ self.shard.shutdown_clean();
}
}