spectacles_model/
presence.rs

1//! Structures related to a user's presence on Discord.
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4use serde_json::Error as JsonError;
5use serde_repr::{Deserialize_repr, Serialize_repr};
6
7use crate::gateway::{Opcodes, SendablePacket, SendPacket};
8use crate::Snowflake;
9
10/// Data about an activity that the user is participating in.
11#[derive(Deserialize, Serialize, Debug, Clone, Default)]
12pub struct Activity {
13    /// The name of the activity.
14    pub name: String,
15    /// The type of activity.
16    #[serde(rename = "type")]
17    pub kind: ActivityType,
18    /// If type is 1, the stream URL.
19    #[serde(default)]
20    pub url: String,
21    /// Timestamps for this activity.
22    #[serde(default)]
23    pub timestamps: Option<ActivityTimestamps>,
24    /// The application ID for the game, if any.
25    pub application_id: Option<Snowflake>,
26    /// What the player is currently doing.
27    pub details: Option<String>,
28    /// The user's current party status.
29    pub state: Option<String>,
30    /// The player's current party.
31    #[serde(default)]
32    pub party: Option<ActivityParty>,
33    /// The Rich Presence assets.
34    #[serde(default)]
35    pub assets: Option<ActivityAssets>,
36    /// The Rich Presence secrets.
37    #[serde(default)]
38    pub secrets: Option<ActivitySecrets>,
39    /// Whether or not the activity is in a current game session.
40    #[serde(default)]
41    pub instance: Option<bool>,
42    /// Activity flags.
43    #[serde(default)]
44    pub flags: Option<i32>
45}
46
47/// Represents the activity of the current client.
48#[derive(Deserialize, Serialize, Debug, Clone, Default)]
49pub struct ClientActivity {
50    /// The name of the current activity.
51    pub name: String,
52    /// The activity type.
53    #[serde(rename = "type")]
54    pub kind: ActivityType,
55    /// The stream URL, if streaming.
56    pub url: Option<String>,
57}
58
59impl ClientActivity {
60    /// Create an activity with the PLAYING prefix.
61    pub fn game(name: &str) -> Self {
62        Self {
63            name: name.to_string(),
64            kind: ActivityType::Game,
65            url: None
66        }
67    }
68
69    /// Create an activity with the STREAMING prefix.
70    pub fn streaming(name: &str, url: &str) -> Self {
71        Self {
72            name: name.to_string(),
73            kind: ActivityType::Streaming,
74            url: Some(url.to_string())
75        }
76    }
77
78    /// Create an activity with the LISTENING prefix.
79    pub fn listening(name: &str) -> Self {
80        Self {
81            name: name.to_string(),
82            kind: ActivityType::Listening,
83            url: None
84        }
85    }
86}
87
88/// Represents a user's presence in a Discord guild.
89#[derive(Deserialize, Serialize, Debug, Clone)]
90pub struct Presence {
91    /// The user that this presence belongs to.
92    pub user: PresenceUser,
93    /// The roles that this user has.
94    #[serde(default)]
95    pub roles: Option<Vec<Snowflake>>,
96    /// The user's current activity, if any.
97    #[serde(default)]
98    pub game: Option<Activity>,
99    /// The ID of the guild.
100    #[serde(default)]
101    pub guild_id: Option<Snowflake>,
102    /// The status of this user.
103    #[serde(default)]
104    pub status: Option<Status>,
105    #[serde(default)]
106    /// The user's current activities.
107    pub activities: Option<Vec<Activity>>,
108    /// The user's client status.
109    #[serde(default)]
110    pub client_status: Option<ClientStatus>
111
112}
113
114/// Represents a user sent in a presence update event.
115#[derive(Deserialize, Serialize, Debug, Clone, Default)]
116pub struct PresenceUser {
117    /// The ID of this user.
118    pub id: Snowflake
119}
120
121/// The current presence of the connected Client.
122#[derive(Deserialize, Serialize, Debug, Clone, Default)]
123pub struct ClientPresence {
124    /// Milliseconds that the client went idle.
125    pub since: Option<i32>,
126    /// The user's current activity if any.
127    pub game: Option<ClientActivity>,
128    /// The status of the user.
129    pub status: String,
130    /// Whether or not the client is AFK.
131    pub afk: bool
132}
133
134/// Represents the platform dependent status of a user.
135#[derive(Deserialize, Serialize, Debug, Clone, Default)]
136pub struct ClientStatus {
137    /// The user's status on a desktop.
138    #[serde(default)]
139    pub desktop: Option<String>,
140    /// The user's status on mobile.
141    #[serde(default)]
142    pub mobile: Option<String>,
143    /// The user's status in the web browser client.
144    #[serde(default)]
145    pub web: Option<String>
146}
147
148/// Represents an Activity's timestamps.
149#[derive(Deserialize, Serialize, Debug, Clone, Default)]
150pub struct ActivityTimestamps {
151    /// When the activity started, in milliseconds.
152    #[serde(default)]
153    pub start: Option<u64>,
154    /// When the activity ends, in milliseconds.
155    #[serde(default)]
156    pub end: Option<u64>
157}
158
159/// Information about the player's current party.
160#[derive(Deserialize, Serialize, Debug, Clone, Default)]
161pub struct ActivityParty {
162    /// The ID for this party.
163    #[serde(default)]
164    pub id: String,
165    /// The party's current and maximum size.
166    #[serde(default)]
167    pub size: [i32; 2]
168}
169
170/// Rich Presence image and text assets.
171#[derive(Deserialize, Serialize, Debug, Clone, Default)]
172pub struct ActivityAssets {
173    /// The ID of the large image of this activity.
174    #[serde(default)]
175    pub large_image: String,
176    /// The large image hover text.
177    #[serde(default)]
178    pub large_text: String,
179    /// The ID of the small image of this activity.
180    #[serde(default)]
181    pub small_image: String,
182    /// The small image hover text.
183    #[serde(default)]
184    pub small_text: String
185}
186
187/// Rich Presence secrets, used for joining and spectating.
188#[derive(Deserialize, Serialize, Debug, Clone, Default)]
189pub struct ActivitySecrets {
190    /// The secret for joining a party.
191    #[serde(default)]
192    pub join: String,
193    /// The secret for spectating a game.
194    #[serde(default)]
195    pub spectate: String,
196    /// The secret for an instanced match.
197    #[serde(rename = "match", default)]
198    pub match_type: String
199}
200
201
202impl SendablePacket for ClientPresence {
203    fn to_json(self) -> Result<String, JsonError> {
204        serde_json::to_string(&SendPacket {
205            op: Opcodes::StatusUpdate,
206            d: self
207        })
208    }
209
210    fn bytes(self) -> Result<Vec<u8>, JsonError> {
211        let json = self.to_json()?;
212
213        Ok(json.as_bytes().to_vec())
214    }
215}
216/// A list of possible activity types.
217#[derive(Deserialize_repr, Serialize_repr, Debug, Clone)]
218#[repr(u8)]
219pub enum ActivityType {
220    Game,
221    Streaming,
222    Listening,
223    Watching
224}
225
226impl Default for ActivityType {
227    fn default() -> Self {
228        ActivityType::Game
229    }
230}
231/// A list of possible statuses.
232#[derive(Deserialize, Serialize, Debug, Clone)]
233pub enum Status {
234    #[serde(rename = "online")]
235    Online,
236    #[serde(rename = "dnd")]
237    DnD,
238    #[serde(rename = "idle")]
239    Idle,
240    #[serde(rename = "invisible")]
241    Invisible,
242    #[serde(rename = "offline")]
243    Offline
244}
245
246impl Default for Status {
247    fn default() -> Self {
248        Status::Online
249    }
250}
251
252
253impl Display for Status {
254    fn fmt(&self, f: &mut Formatter) -> FmtResult {
255        match self {
256            Status::Online => write!(f, "online"),
257            Status::DnD => write!(f, "dnd"),
258            Status::Idle => write!(f, "idle"),
259            Status::Invisible => write!(f, "invisible"),
260            Status::Offline => write!(f, "offline")
261        }
262    }
263}