aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2018-04-27 08:05:56 -0700
committerKen Swenson <[email protected]>2018-11-06 20:35:51 -0500
commit3e54f4c524ad609b31c061286eab971f0084a4c5 (patch)
tree907334e8b8a2823696f2b96456aca062f3d00a40 /src
parentMake builders mutably borrowed (diff)
downloadserenity-3e54f4c524ad609b31c061286eab971f0084a4c5.tar.xz
serenity-3e54f4c524ad609b31c061286eab971f0084a4c5.zip
Add Rich Presence parsing support
Adds support for parsing Rich Presences. This can not be used for setting activities with bots. Upgrade path: Basically change your import and usage from `serenity::model::gateway::Game` to `serenity::model::gateway::Activity`.
Diffstat (limited to 'src')
-rw-r--r--src/client/bridge/gateway/shard_messenger.rs50
-rw-r--r--src/client/bridge/gateway/shard_runner.rs16
-rw-r--r--src/client/bridge/gateway/shard_runner_message.rs12
-rw-r--r--src/client/context.rs63
-rw-r--r--src/gateway/mod.rs6
-rw-r--r--src/gateway/shard.rs18
-rw-r--r--src/gateway/ws_client_ext.rs4
-rw-r--r--src/internal/ws_impl.rs20
-rw-r--r--src/model/gateway.rs319
9 files changed, 278 insertions, 230 deletions
diff --git a/src/client/bridge/gateway/shard_messenger.rs b/src/client/bridge/gateway/shard_messenger.rs
index 11e75ce..21e586a 100644
--- a/src/client/bridge/gateway/shard_messenger.rs
+++ b/src/client/bridge/gateway/shard_messenger.rs
@@ -7,11 +7,11 @@ use websocket::message::OwnedMessage;
/// A lightweight wrapper around an mpsc sender.
///
/// This is used to cleanly communicate with a shard's respective
-/// [`ShardRunner`]. This can be used for actions such as setting the game via
-/// [`set_game`] or shutting down via [`shutdown`].
+/// [`ShardRunner`]. This can be used for actions such as setting the activity
+/// via [`set_activity`] or shutting down via [`shutdown`].
///
/// [`ShardRunner`]: struct.ShardRunner.html
-/// [`set_game`]: #method.set_game
+/// [`set_activity`]: #method.set_activity
/// [`shutdown`]: #method.shutdown
#[derive(Clone, Debug)]
pub struct ShardMessenger {
@@ -124,13 +124,13 @@ impl ShardMessenger {
});
}
- /// Sets the user's current game, if any.
+ /// Sets the user's current activity, if any.
///
/// Other presence settings are maintained.
///
/// # Examples
///
- /// Setting the current game to playing `"Heroes of the Storm"`:
+ /// Setting the current activity to playing `"Heroes of the Storm"`:
///
/// ```rust,no_run
/// # extern crate parking_lot;
@@ -146,19 +146,9 @@ impl ShardMessenger {
/// #
/// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
- /// # #[cfg(feature = "model")]
- /// use serenity::model::gateway::Game;
- /// # #[cfg(not(feature = "model"))]
- /// use serenity::model::gateway::{Game, GameType};
- ///
- /// # #[cfg(feature = "model")]
- /// shard.set_game(Some(Game::playing("Heroes of the Storm")));
- /// # #[cfg(not(feature = "model"))]
- /// shard.set_game(Some(Game {
- /// kind: GameType::Playing,
- /// name: "Heroes of the Storm".to_owned(),
- /// url: None,
- /// }));
+ /// use serenity::model::gateway::Activity;
+ ///
+ /// shard.set_activity(Some(Activity::playing("Heroes of the Storm")));
/// # Ok(())
/// # }
/// #
@@ -166,12 +156,8 @@ impl ShardMessenger {
/// # try_main().unwrap();
/// # }
/// ```
- pub fn set_game<T: Into<Game>>(&self, game: Option<T>) {
- self._set_game(game.map(Into::into))
- }
-
- fn _set_game(&self, game: Option<Game>) {
- let _ = self.send(ShardRunnerMessage::SetGame(game));
+ pub fn set_activity(&self, activity: Option<Activity>) {
+ let _ = self.send(ShardRunnerMessage::SetActivity(activity));
}
/// Sets the user's full presence information.
@@ -198,9 +184,9 @@ impl ShardMessenger {
/// #
/// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
- /// use serenity::model::{Game, OnlineStatus};
+ /// use serenity::model::{Activity, OnlineStatus};
///
- /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online);
+ /// shard.set_presence(Some(Activity::playing("Heroes of the Storm")), OnlineStatus::Online);
/// # Ok(())
/// # }
/// #
@@ -208,20 +194,12 @@ impl ShardMessenger {
/// # try_main().unwrap();
/// # }
/// ```
- pub fn set_presence<T: Into<Game>>(
- &self,
- game: Option<T>,
- status: OnlineStatus,
- ) {
- self._set_presence(game.map(Into::into), status)
- }
-
- fn _set_presence(&self, game: Option<Game>, mut status: OnlineStatus) {
+ pub fn set_presence(&self, activity: Option<Activity>, mut status: OnlineStatus) {
if status == OnlineStatus::Offline {
status = OnlineStatus::Invisible;
}
- let _ = self.send(ShardRunnerMessage::SetPresence(status, game));
+ let _ = self.send(ShardRunnerMessage::SetPresence(status, activity));
}
/// Sets the user's current online status.
diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs
index ea1fad6..0f244bd 100644
--- a/src/client/bridge/gateway/shard_runner.rs
+++ b/src/client/bridge/gateway/shard_runner.rs
@@ -258,26 +258,26 @@ impl<H: EventHandler + Send + Sync + 'static> ShardRunner<H> {
ShardRunnerMessage::Message(msg) => {
self.shard.client.send_message(&msg).is_ok()
},
- ShardRunnerMessage::SetGame(game) => {
- // To avoid a clone of `game`, we do a little bit of
+ ShardRunnerMessage::SetActivity(activity) => {
+ // To avoid a clone of `activity`, we do a little bit of
// trickery here:
//
// First, we obtain a reference to the current presence of
// the shard, and create a new presence tuple of the new
- // game we received over the channel as well as the online
- // status that the shard already had.
+ // activity we received over the channel as well as the
+ // online status that the shard already had.
//
// We then (attempt to) send the websocket message with the
// status update, expressively returning:
//
// - whether the message successfully sent
- // - the original game we received over the channel
- self.shard.set_game(game);
+ // - the original activity we received over the channel
+ self.shard.set_activity(activity);
self.shard.update_presence().is_ok()
},
- ShardRunnerMessage::SetPresence(status, game) => {
- self.shard.set_presence(status, game);
+ ShardRunnerMessage::SetPresence(status, activity) => {
+ self.shard.set_presence(status, activity);
self.shard.update_presence().is_ok()
},
diff --git a/src/client/bridge/gateway/shard_runner_message.rs b/src/client/bridge/gateway/shard_runner_message.rs
index edb9b8a..0fac329 100644
--- a/src/client/bridge/gateway/shard_runner_message.rs
+++ b/src/client/bridge/gateway/shard_runner_message.rs
@@ -1,7 +1,7 @@
use model::{
- gateway::Game,
+ gateway::Activity,
+ id::GuildId,
user::OnlineStatus,
- id::GuildId
};
use websocket::message::OwnedMessage;
@@ -38,11 +38,11 @@ pub enum ShardRunnerMessage {
Close(u16, Option<String>),
/// Indicates that the client is to send a custom WebSocket message.
Message(OwnedMessage),
- /// Indicates that the client is to update the shard's presence's game.
- SetGame(Option<Game>),
+ /// Indicates that the client is to update the shard's presence's activity.
+ SetActivity(Option<Activity>),
/// Indicates that the client is to update the shard's presence in its
- /// entirety.
- SetPresence(OnlineStatus, Option<Game>),
+ /// entirity.
+ SetPresence(OnlineStatus, Option<Activity>),
/// Indicates that the client is to update the shard's presence's status.
SetStatus(OnlineStatus),
}
diff --git a/src/client/context.rs b/src/client/context.rs
index f6ffbef..ff5a788 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -25,7 +25,7 @@ use utils::{self, VecMap};
/// [`Shard`] which received the event, or the low-level [`http`] module.
///
/// The context contains "shortcuts", like for interacting with the shard.
-/// Methods like [`set_game`] will unlock the shard and perform an update for
+/// Methods like [`set_activity`] will unlock the shard and perform an update for
/// you to save a bit of work.
///
/// A context will only live for the event it was dispatched for. After the
@@ -33,7 +33,7 @@ use utils::{self, VecMap};
///
/// [`Shard`]: ../gateway/struct.Shard.html
/// [`http`]: ../http/index.html
-/// [`set_game`]: #method.set_game
+/// [`set_activity`]: #method.set_activity
#[derive(Clone)]
pub struct Context {
/// A clone of [`Client::data`]. Refer to its documentation for more
@@ -122,7 +122,7 @@ impl Context {
/// Sets the current user as being [`Online`]. This maintains the current
- /// game.
+ /// activity.
///
/// # Examples
///
@@ -154,7 +154,7 @@ impl Context {
}
/// Sets the current user as being [`Idle`]. This maintains the current
- /// game.
+ /// activity.
///
/// # Examples
///
@@ -185,7 +185,7 @@ impl Context {
}
/// Sets the current user as being [`DoNotDisturb`]. This maintains the
- /// current game.
+ /// current activity.
///
/// # Examples
///
@@ -216,7 +216,7 @@ impl Context {
}
/// Sets the current user as being [`Invisible`]. This maintains the current
- /// game.
+ /// activity.
///
/// # Examples
///
@@ -247,8 +247,8 @@ impl Context {
self.shard.set_status(OnlineStatus::Invisible);
}
- /// "Resets" the current user's presence, by setting the game to `None` and
- /// the online status to [`Online`].
+ /// "Resets" the current user's presence, by setting the activity to `None`
+ /// and the online status to [`Online`].
///
/// Use [`set_presence`] for fine-grained control over individual details.
///
@@ -281,7 +281,7 @@ impl Context {
self.shard.set_presence(None::<Game>, OnlineStatus::Online);
}
- /// Sets the current game, defaulting to an online status of [`Online`].
+ /// Sets the current activity, defaulting to an online status of [`Online`].
///
/// # Examples
///
@@ -294,7 +294,7 @@ impl Context {
/// # use serenity::prelude::*;
/// # use serenity::model::channel::Message;
/// #
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
///
/// struct Handler;
///
@@ -306,7 +306,7 @@ impl Context {
/// return;
/// }
///
- /// ctx.set_game(Game::playing(*unsafe { args.get_unchecked(1) }));
+ /// ctx.set_activity(Activity::playing(*unsafe { args.get_unchecked(1) }));
/// }
/// }
///
@@ -321,26 +321,22 @@ impl Context {
///
/// [`Online`]: ../model/user/enum.OnlineStatus.html#variant.Online
#[inline]
- pub fn set_game<T: Into<Game>>(&self, game: T) {
- self._set_game(game.into())
+ pub fn set_activity(&self, activity: Activity) {
+ self.shard.set_presence(Some(activity), OnlineStatus::Online);
}
- fn _set_game(&self, game: Game) {
- self.shard.set_presence(Some(game), OnlineStatus::Online);
- }
-
- /// Sets the current game, passing in only its name. This will automatically
- /// set the current user's [`OnlineStatus`] to [`Online`], and its
- /// [`GameType`] as [`Playing`].
+ /// Sets the current activity, passing in only its name. This will
+ /// automatically set the current user's [`OnlineStatus`] to [`Online`], and
+ /// its [`ActivityType`] as [`Playing`].
///
- /// Use [`reset_presence`] to clear the current game, or [`set_presence`]
- /// for more fine-grained control.
+ /// Use [`reset_presence`] to clear the current activity, or
+ /// [`set_presence`] for more fine-grained control.
///
/// **Note**: Maximum length is 128.
///
/// # Examples
///
- /// When an [`Event::Ready`] is received, set the game name to `"test"`:
+ /// When an [`Event::Ready`] is received, set the activity name to `"test"`:
///
/// ```rust,no_run
/// # use serenity::prelude::*;
@@ -359,23 +355,24 @@ impl Context {
/// ```
///
/// [`Event::Ready`]: ../model/event/enum.Event.html#variant.Ready
- /// [`GameType`]: ../model/gateway/enum.GameType.html
+ /// [`ActivityType`]: ../model/gateway/enum.ActivityType.html
/// [`Online`]: ../model/user/enum.OnlineStatus.html#variant.Online
/// [`OnlineStatus`]: ../model/user/enum.OnlineStatus.html
- /// [`Playing`]: ../model/gateway/enum.GameType.html#variant.Playing
+ /// [`Playing`]: ../model/gateway/enum.ActivityType.html#variant.Playing
/// [`reset_presence`]: #method.reset_presence
/// [`set_presence`]: #method.set_presence
#[deprecated(since = "0.5.5", note = "Use Context::set_game")]
#[inline]
- pub fn set_game_name<T: Into<String>>(&self, game_name: T) {
- self.set_game(game_name.into())
+ pub fn set_game_name(&self, game_name: &str) {
+ let activity = Activity::playing(game_name);
+ self.shard.set_presence(Some(activity), OnlineStatus::Online);
}
/// Sets the current user's presence, providing all fields to be passed.
///
/// # Examples
///
- /// Setting the current user as having no game and being [`Idle`]:
+ /// Setting the current user as having no activity and being [`Idle`]:
///
/// ```rust,no_run
/// # use serenity::prelude::*;
@@ -406,13 +403,13 @@ impl Context {
///
/// impl EventHandler for Handler {
/// fn ready(&self, context: Context, _: Ready) {
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
/// use serenity::model::user::OnlineStatus;
///
- /// let game = Game::playing("Heroes of the Storm");
+ /// let activity = Activity::playing("Heroes of the Storm");
/// let status = OnlineStatus::DoNotDisturb;
///
- /// context.set_presence(Some(game), status);
+ /// context.set_presence(Some(activity), status);
/// }
/// }
///
@@ -424,8 +421,8 @@ impl Context {
/// [`DoNotDisturb`]: ../model/user/enum.OnlineStatus.html#variant.DoNotDisturb
/// [`Idle`]: ../model/user/enum.OnlineStatus.html#variant.Idle
#[inline]
- pub fn set_presence(&self, game: Option<Game>, status: OnlineStatus) {
- self.shard.set_presence(game, status);
+ pub fn set_presence(&self, activity: Option<Activity>, status: OnlineStatus) {
+ self.shard.set_presence(activity, status);
}
/// Disconnects the shard from the websocket, essentially "quiting" it.
diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs
index 07d882c..a5f3a5e 100644
--- a/src/gateway/mod.rs
+++ b/src/gateway/mod.rs
@@ -57,8 +57,8 @@ pub use self::{
};
use model::{
- gateway::Game,
- user::OnlineStatus
+ gateway::Activity,
+ user::OnlineStatus,
};
use serde_json::Value;
use std::fmt::{Display, Formatter, Result as FmtResult};
@@ -70,7 +70,7 @@ use websocket::sync::{
#[cfg(feature = "client")]
use client::bridge::gateway::ShardClientMessage;
-pub type CurrentPresence = (Option<Game>, OnlineStatus);
+pub type CurrentPresence = (Option<Activity>, OnlineStatus);
pub type WsClient = Client<TlsStream<TcpStream>>;
/// Indicates the current connection stage of a [`Shard`].
diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs
index 09a3b69..b629361 100644
--- a/src/gateway/shard.rs
+++ b/src/gateway/shard.rs
@@ -2,7 +2,7 @@ use constants::{self, close_codes};
use internal::prelude::*;
use model::{
event::{Event, GatewayEvent},
- gateway::Game,
+ gateway::Activity,
id::GuildId,
user::OnlineStatus
};
@@ -29,8 +29,8 @@ use websocket::{
/// A Shard is a higher-level handler for a websocket connection to Discord's
/// gateway. The shard allows for sending and receiving messages over the
-/// websocket, such as setting the active game, reconnecting, syncing guilds,
-/// and more.
+/// websocket, such as setting the active activity, reconnecting, syncing
+/// guilds, and more.
///
/// Refer to the [module-level documentation][module docs] for information on
/// effectively using multiple shards, if you need to.
@@ -272,22 +272,22 @@ impl Shard {
/// #
/// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
///
- /// shard.set_game(Some(Game::playing("Heroes of the Storm")));
+ /// shard.set_activity(Some(Activity::playing("Heroes of the Storm")));
/// # }
/// #
/// # #[cfg(not(feature = "model"))]
/// # fn main() { }
/// ```
#[inline]
- pub fn set_game(&mut self, game: Option<Game>) {
- self.current_presence.0 = game;
+ pub fn set_activity(&mut self, activity: Option<Activity>) {
+ self.current_presence.0 = activity;
}
#[inline]
- pub fn set_presence(&mut self, status: OnlineStatus, game: Option<Game>) {
- self.set_game(game);
+ pub fn set_presence(&mut self, status: OnlineStatus, activity: Option<Activity>) {
+ self.set_activity(activity);
self.set_status(status);
}
diff --git a/src/gateway/ws_client_ext.rs b/src/gateway/ws_client_ext.rs
index 934383c..27f11ee 100644
--- a/src/gateway/ws_client_ext.rs
+++ b/src/gateway/ws_client_ext.rs
@@ -92,7 +92,7 @@ impl WebSocketGatewayClientExt for WsClient {
shard_info: &[u64; 2],
current_presence: &CurrentPresence,
) -> Result<()> {
- let &(ref game, ref status) = current_presence;
+ let &(ref activity, ref status) = current_presence;
let now = Utc::now().timestamp() as u64;
debug!("[Shard {:?}] Sending presence update", shard_info);
@@ -103,7 +103,7 @@ impl WebSocketGatewayClientExt for WsClient {
"afk": false,
"since": now,
"status": status.name(),
- "game": game.as_ref().map(|x| json!({
+ "game": activity.as_ref().map(|x| json!({
"name": x.name,
"type": x.kind,
"url": x.url,
diff --git a/src/internal/ws_impl.rs b/src/internal/ws_impl.rs
index 5d8969b..fbf6ae4 100644
--- a/src/internal/ws_impl.rs
+++ b/src/internal/ws_impl.rs
@@ -20,25 +20,13 @@ impl ReceiverExt for WsClient<TlsStream<TcpStream>> {
fn recv_json(&mut self) -> Result<Option<Value>> {
Ok(match self.recv_message()? {
OwnedMessage::Binary(bytes) => {
- serde_json::from_reader(ZlibDecoder::new(&bytes[..]))
- .map(Some)
- .map_err(|why| {
- warn!("Err deserializing bytes: {:?}; bytes: {:?}", why, bytes);
-
- why
- })?
+ println!("{:?}", bytes);
+ serde_json::from_reader(ZlibDecoder::new(&bytes[..])).map(Some)?
},
OwnedMessage::Close(data) => return Err(Error::Gateway(GatewayError::Closed(data))),
OwnedMessage::Text(payload) => {
- serde_json::from_str(&payload).map(Some).map_err(|why| {
- warn!(
- "Err deserializing text: {:?}; text: {}",
- why,
- payload,
- );
-
- why
- })?
+ println!("{}", payload);
+ serde_json::from_str(&payload).map(Some)?
},
OwnedMessage::Ping(x) => {
self.send_message(&OwnedMessage::Pong(x))
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index 68668cf..bbff7e4 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -1,5 +1,6 @@
//! Models pertaining to the gateway.
+use chrono::{DateTime, Utc};
use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
@@ -26,82 +27,116 @@ pub struct BotGateway {
pub url: String,
}
-/// Representation of a game that a [`User`] is playing -- or streaming in the
-/// case that a stream URL is provided.
-///
-/// [`User`]: ../user/struct.User.html
+/// Representation of an activity that a [`User`] is performing.
#[derive(Clone, Debug, Serialize)]
-pub struct Game {
- /// The type of game status.
- #[serde(default, rename = "type")]
- pub kind: GameType,
- /// The name of the game being played.
+pub struct Activity {
+ /// The ID of the application for the activity.
+ pub application_id: Option<ApplicationId>,
+ /// Images for the presence and their texts.
+ pub assets: Option<ActivityAssets>,
+ /// What the user is doing.
+ pub details: Option<String>,
+ /// Activity flags describing what the payload includes.
+ pub flags: Option<ActivityFlags>,
+ /// Whether or not the activity is an instanced game session.
+ pub instance: Option<bool>,
+ /// The type of activity being performed
+ #[serde(default = "ActivityType::default", rename = "type")]
+ pub kind: ActivityType,
+ /// The name of the activity.
pub name: String,
- /// The Stream URL if [`kind`] is [`GameType::Streaming`].
+ /// Information about the user's current party.
+ pub party: Option<ActivityParty>,
+ /// Secrets for Rich Presence joining and spectating.
+ pub secrets: Option<ActivitySecrets>,
+ /// The user's current party status.
+ pub state: Option<String>,
+ /// Unix timestamps for the start and/or end times of the activity.
+ pub timestamps: Option<ActivityTimestamps>,
+ /// The Stream URL if [`kind`] is [`ActivityType::Streaming`].
///
- /// [`GameType::Streaming`]: enum.GameType.html#variant.Streaming
+ /// [`ActivityType::Streaming`]: enum.ActivityType.html#variant.Streaming
/// [`kind`]: #structfield.kind
pub url: Option<String>,
}
#[cfg(feature = "model")]
-impl Game {
+impl Activity {
/// Creates a `Game` struct that appears as a `Playing <name>` status.
///
/// **Note**: Maximum `name` length is 128.
///
/// # Examples
///
- /// Create a command that sets the current game being played:
+ /// Create a command that sets the current activity:
///
/// ```rust,no_run
/// # #[macro_use] extern crate serenity;
/// #
/// use serenity::framework::standard::Args;
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
///
- /// command!(game(ctx, _msg, args) {
+ /// command!(activity(ctx, _msg, args) {
/// let name = args.full();
- /// ctx.set_game(Game::playing(&name));
+ /// ctx.set_activity(Activity::playing(&name));
/// });
/// #
/// # fn main() {}
/// ```
- pub fn playing(name: &str) -> Game {
- Game {
- kind: GameType::Playing,
+ pub fn playing(name: &str) -> Activity {
+ Activity {
+ application_id: None,
+ assets: None,
+ details: None,
+ flags: None,
+ instance: None,
+ kind: ActivityType::Playing,
name: name.to_string(),
+ party: None,
+ secrets: None,
+ state: None,
+ timestamps: None,
url: None,
}
}
- /// Creates a `Game` struct that appears as a `Streaming <name>` status.
+ /// Creates an `Activity` struct that appears as a `Streaming <name>`
+ /// status.
///
/// **Note**: Maximum `name` length is 128.
///
/// # Examples
///
- /// Create a command that sets the current game and stream:
+ /// Create a command that sets the current streaming status:
///
/// ```rust,no_run
/// # #[macro_use] extern crate serenity;
/// #
/// use serenity::framework::standard::Args;
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
///
/// // Assumes command has min_args set to 2.
/// command!(stream(ctx, _msg, args) {
/// # let stream_url = String::from("");
/// let name = args.full();
- /// ctx.set_game(Game::streaming(&name, &stream_url));
+ /// ctx.set_activity(Activity::streaming(&name, &stream_url));
/// });
/// #
/// # fn main() {}
/// ```
- pub fn streaming(name: &str, url: &str) -> Game {
- Game {
- kind: GameType::Streaming,
+ pub fn streaming(name: &str, url: &str) -> Activity {
+ Activity {
+ application_id: None,
+ assets: None,
+ details: None,
+ flags: None,
+ instance: None,
+ kind: ActivityType::Streaming,
name: name.to_string(),
+ party: None,
+ secrets: None,
+ state: None,
+ timestamps: None,
url: Some(url.to_string()),
}
}
@@ -112,115 +147,159 @@ impl Game {
///
/// # Examples
///
- /// Create a command that sets the current game being played:
+ /// Create a command that sets the current listening status:
///
/// ```rust,no_run
/// # #[macro_use] extern crate serenity;
/// #
/// use serenity::framework::standard::Args;
- /// use serenity::model::gateway::Game;
+ /// use serenity::model::gateway::Activity;
///
/// command!(listen(ctx, _msg, args) {
/// let name = args.full();
- /// ctx.set_game(Game::listening(&name));
+ /// ctx.set_activity(Activity::listening(&name));
/// });
/// #
/// # fn main() {}
/// ```
- pub fn listening(name: &str) -> Game {
- Game {
- kind: GameType::Listening,
+ pub fn listening(name: &str) -> Activity {
+ Activity {
+ application_id: None,
+ assets: None,
+ details: None,
+ flags: None,
+ instance: None,
+ kind: ActivityType::Listening,
name: name.to_string(),
+ party: None,
+ secrets: None,
+ state: None,
+ timestamps: None,
url: None,
}
}
}
-impl<'a> From<&'a str> for Game {
- fn from(name: &'a str) -> Self {
- Game {
- kind: GameType::Playing,
- name: name.to_owned(),
- url: None,
- }
- }
-}
-
-impl From<String> for Game {
- fn from(name: String) -> Self {
- Game {
- kind: GameType::Playing,
- url: None,
- name,
- }
- }
-}
-
-impl<'a> From<(String, GameType)> for Game {
- fn from((name, kind): (String, GameType)) -> Self {
- Self {
- url: None,
- kind,
- name,
- }
- }
-}
-
-impl<'a> From<(&'a str, &'a str)> for Game {
- fn from((name, url): (&'a str, &'a str)) -> Self {
- Self {
- kind: GameType::Streaming,
- name: name.to_owned(),
- url: Some(url.to_owned()),
- }
- }
-}
-
-impl From<(String, String)> for Game {
- fn from((name, url): (String, String)) -> Self {
- Self {
- kind: GameType::Streaming,
- url: Some(url),
- name,
- }
- }
-}
-
-impl From<(String, GameType, String)> for Game {
- fn from((name, kind, url): (String, GameType, String)) -> Self {
- Self {
- url: Some(url),
- kind,
- name,
- }
- }
-}
-
-impl<'de> Deserialize<'de> for Game {
+impl<'de> Deserialize<'de> for Activity {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;
+ let application_id = match map.remove("application_id") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let assets = match map.remove("assets") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let details = match map.remove("details") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let flags = match map.remove("flags") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let instance = match map.remove("instance") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
let kind = map.remove("type")
- .and_then(|v| GameType::deserialize(v).ok())
- .unwrap_or(GameType::Playing);
+ .and_then(|v| ActivityType::deserialize(v).ok())
+ .unwrap_or(ActivityType::Playing);
let name = map.remove("name")
.and_then(|v| String::deserialize(v).ok())
.unwrap_or_else(String::new);
+ let party = match map.remove("party") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let secrets = match map.remove("secrets") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let state = match map.remove("state") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
+ let timestamps = match map.remove("timestamps") {
+ Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
+ None => None,
+ };
let url = map.remove("url")
.and_then(|v| serde_json::from_value::<String>(v).ok());
- Ok(Game {
+ Ok(Activity {
+ application_id,
+ assets,
+ details,
+ flags,
+ instance,
kind,
name,
+ party,
+ secrets,
+ state,
+ timestamps,
url,
})
}
}
+/// The assets for an activity.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ActivityAssets {
+ /// The ID for a large asset of the activity, usually a snowflake.
+ pub large_image: Option<String>,
+ /// Text displayed when hovering over the large image of the activity.
+ pub large_text: Option<String>,
+ /// The ID for a small asset of the activity, usually a snowflake.
+ pub small_image: Option<String>,
+ /// Text displayed when hovering over the small image of the activity.
+ pub small_text: Option<String>,
+}
+
+bitflags! {
+ /// A set of flags defining what is in an activity's payload.
+ #[derive(Deserialize, Serialize)]
+ pub struct ActivityFlags: u64 {
+ /// Whether the activity is an instance activity.
+ const INSTANCE = 0b001;
+ /// Whether the activity is joinable.
+ const JOIN = 0b010;
+ /// Whether the activity can be spectated.
+ const SPECTATE = 0b011;
+ /// Whether a request can be sent to join the user's party.
+ const JOIN_REQUEST = 0b100;
+ /// Whether the activity can be synced.
+ const SYNC = 0b101;
+ /// Whether the activity can be played.
+ const PLAY = 0b110;
+ }
+}
+
+/// Information about an activity's party.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ActivityParty {
+ /// The ID of the party.
+ pub id: Option<String>,
+ /// Used to show the party's current and maximum size.
+ pub size: [u64; 2],
+}
+/// Secrets for an activity.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ActivitySecrets {
+ /// The secret for joining a party.
+ pub join: Option<String>,
+ /// The secret for a specific instanced match.
+ #[serde(rename = "match")]
+ pub match_: Option<String>,
+ /// The secret for spectating an activity.
+ pub spectate: Option<String>,
+}
-/// The type of activity that is being performed when playing a game.
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
-pub enum GameType {
+#[derive(Clone, Copy, Debug)]
+pub enum ActivityType {
/// An indicator that the user is playing a game.
Playing = 0,
/// An indicator that the user is streaming to a service.
@@ -230,16 +309,16 @@ pub enum GameType {
}
enum_number!(
- GameType {
+ ActivityType {
Playing,
Streaming,
Listening,
}
);
-impl GameType {
+impl ActivityType {
pub fn num(&self) -> u64 {
- use self::GameType::*;
+ use self::ActivityType::*;
match *self {
Playing => 0,
@@ -249,8 +328,8 @@ impl GameType {
}
}
-impl Default for GameType {
- fn default() -> Self { GameType::Playing }
+impl Default for ActivityType {
+ fn default() -> Self { ActivityType::Playing }
}
/// A representation of the data retrieved from the gateway endpoint.
@@ -269,10 +348,10 @@ pub struct Gateway {
/// [`User`]: ../user/struct.User.html
#[derive(Clone, Debug)]
pub struct Presence {
- /// The game that a [`User`] is current playing.
+ /// The activity that a [`User`] is performing.
///
- /// [`User`]: ../user/struct.User.html
- pub game: Option<Game>,
+ /// [`User`]: struct.User.html
+ pub activity: Option<Activity>,
/// The date of the last presence update.
pub last_modified: Option<u64>,
/// The nickname of the member, if applicable.
@@ -309,8 +388,8 @@ impl<'de> Deserialize<'de> for Presence {
(user_id, None)
};
- let game = match map.remove("game") {
- Some(v) => serde_json::from_value::<Option<Game>>(v)
+ let activity = match map.remove("game") {
+ Some(v) => serde_json::from_value::<Option<Activity>>(v)
.map_err(DeError::custom)?,
None => None,
};
@@ -329,12 +408,12 @@ impl<'de> Deserialize<'de> for Presence {
.map_err(DeError::custom)?;
Ok(Presence {
- game,
- last_modified,
- nick,
- status,
- user,
- user_id,
+ activity: activity,
+ last_modified: last_modified,
+ nick: nick,
+ status: status,
+ user: user,
+ user_id: user_id,
})
}
}
@@ -348,7 +427,7 @@ impl Serialize for Presence {
}
let mut state = serializer.serialize_struct("Presence", 5)?;
- state.serialize_field("game", &self.game)?;
+ state.serialize_field("game", &self.activity)?;
state.serialize_field("last_modified", &self.last_modified)?;
state.serialize_field("nick", &self.nick)?;
state.serialize_field("status", &self.status)?;
@@ -393,4 +472,10 @@ pub struct SessionStartLimit {
pub reset_after: u64,
/// The total number of session starts within the ratelimit period allowed.
pub total: u64,
-} \ No newline at end of file
+}
+/// Timestamps of when a user started and/or is ending their activity.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ActivityTimestamps {
+ pub end: Option<DateTime<Utc>>,
+ pub start: Option<DateTime<Utc>>,
+}