twilight_lavalink/model/
incoming.rs

1//! Events that Lavalink sends to clients.
2
3/// The type of event that is coming in from a Lavalink message.
4#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
5#[non_exhaustive]
6#[serde(rename_all = "camelCase")]
7pub enum Opcode {
8    /// Meta information about a track starting or ending.
9    Event,
10    /// An update about a player's current track.
11    PlayerUpdate,
12    /// Lavalink is connected and ready.
13    Ready,
14    /// Updated statistics about a node.
15    Stats,
16}
17
18use serde::{Deserialize, Serialize};
19use twilight_model::id::{Id, marker::GuildMarker};
20
21/// The levels of severity that an exception can have.
22#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
23#[non_exhaustive]
24#[serde(rename_all = "camelCase")]
25pub enum Severity {
26    /// The cause is known and expected, indicates that there is nothing wrong
27    /// with the library itself.
28    Common,
29    /// The probable cause is an issue with the library or there is no way to
30    /// tell what the cause might be. This is the default level and other
31    /// levels are used in cases where the thrower has more in-depth knowledge
32    /// about the error.
33    Fault,
34    /// The cause might not be exactly known, but is possibly caused by outside
35    /// factors. For example when an outside service responds in a format that
36    /// we do not expect.
37    Suspicious,
38}
39
40/// The exception with the details attached on what happened when making a query
41/// to Lavalink.
42#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
43#[non_exhaustive]
44#[serde(rename_all = "camelCase")]
45pub struct Exception {
46    /// The cause of the exception.
47    pub cause: String,
48    /// The message of the exception.
49    pub message: Option<String>,
50    /// The severity of the exception.
51    pub severity: Severity,
52    /// The full stack trace of the cause.
53    pub cause_stack_trace: String,
54}
55
56/// An incoming event from a Lavalink node.
57#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
58#[non_exhaustive]
59#[serde(tag = "op", rename_all = "camelCase")]
60#[allow(clippy::large_enum_variant)]
61pub enum IncomingEvent {
62    /// Dispatched when player or voice events occur.
63    Event(Event),
64    /// Dispatched when you successfully connect to the Lavalink node.
65    Ready(Ready),
66    /// New statistics about a node and its host.
67    Stats(Stats),
68    /// An update about the information of a player.
69    PlayerUpdate(PlayerUpdate),
70}
71
72impl From<Ready> for IncomingEvent {
73    fn from(event: Ready) -> IncomingEvent {
74        Self::Ready(event)
75    }
76}
77
78impl From<Event> for IncomingEvent {
79    fn from(event: Event) -> IncomingEvent {
80        Self::Event(event)
81    }
82}
83
84impl From<PlayerUpdate> for IncomingEvent {
85    fn from(event: PlayerUpdate) -> IncomingEvent {
86        Self::PlayerUpdate(event)
87    }
88}
89
90impl From<Stats> for IncomingEvent {
91    fn from(event: Stats) -> IncomingEvent {
92        Self::Stats(event)
93    }
94}
95
96/// The Discord voice information that Lavalink uses for connection and sending
97/// information.
98#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
99#[non_exhaustive]
100#[serde(rename_all = "camelCase")]
101pub struct VoiceState {
102    /// The Discord voice endpoint to connect to.
103    pub endpoint: String,
104    /// The Discord voice session id to authenticate with. Note this is separate
105    /// from the lavalink session id.
106    pub session_id: String,
107    /// The Discord voice token to authenticate with.
108    pub token: String,
109}
110
111/// An update of a player's status and state.
112#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
113#[non_exhaustive]
114#[serde(rename_all = "camelCase")]
115pub struct PlayerUpdate {
116    /// The guild ID of the player.
117    pub guild_id: Id<GuildMarker>,
118    /// The new state of the player.
119    pub state: PlayerUpdateState,
120}
121
122impl PlayerUpdate {
123    /// The operation type of the `PlayerUpate` event.
124    pub const OPCODE: Opcode = Opcode::PlayerUpdate;
125}
126
127/// New statistics about a node and its host.
128#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
129#[non_exhaustive]
130#[serde(rename_all = "camelCase")]
131pub struct PlayerUpdateState {
132    /// True when the player is connected to the voice gateway.
133    pub connected: bool,
134    /// The ping of the node to the Discord voice server in milliseconds (-1 if not connected).
135    pub ping: i64,
136    /// Track position in milliseconds. None if not playing anything.
137    pub position: i64,
138    /// Unix timestamp of the player in milliseconds.
139    pub time: i64,
140}
141
142/// Dispatched by Lavalink upon successful connection and authorization.
143#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
144#[non_exhaustive]
145#[serde(rename_all = "camelCase")]
146pub struct Ready {
147    /// Whether this session was resumed.
148    pub resumed: bool,
149    /// The Lavalink session id of this connection. Not to be confused with a
150    /// Discord voice session id.
151    pub session_id: String,
152}
153
154/// Statistics about a node and its host.
155#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
156#[non_exhaustive]
157#[serde(rename_all = "camelCase")]
158pub struct Stats {
159    /// CPU information about the node's host.
160    pub cpu: StatsCpu,
161    /// The frame stats of the node. `null` if the node has no players or when
162    /// retrieved via /v4/stats.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub frame_stats: Option<StatsFrame>,
165    /// Memory information about the node's host.
166    pub memory: StatsMemory,
167    /// The current number of total players (active and not active) within
168    /// the node.
169    pub players: u64,
170    /// The current number of active players within the node.
171    pub playing_players: u64,
172    /// The uptime of the Lavalink server in seconds.
173    pub uptime: u64,
174}
175
176/// CPU information about a node and its host.
177#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
178#[non_exhaustive]
179#[serde(rename_all = "camelCase")]
180pub struct StatsCpu {
181    /// The number of CPU cores.
182    pub cores: usize,
183    /// The load of the Lavalink server.
184    pub lavalink_load: f64,
185    /// The load of the system as a whole.
186    pub system_load: f64,
187}
188
189/// CPU information about a node and its host.
190#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
191#[non_exhaustive]
192#[serde(rename_all = "camelCase")]
193pub struct StatsFrame {
194    /// The load of the system as a whole.
195    pub deficit: i64,
196    /// The load of the Lavalink server.
197    pub nulled: i64,
198    /// The number of CPU cores.
199    pub sent: i64,
200}
201
202/// Memory information about a node and its host.
203#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
204#[non_exhaustive]
205#[serde(rename_all = "camelCase")]
206pub struct StatsMemory {
207    /// The number of bytes allocated.
208    pub allocated: u64,
209    /// The number of bytes free.
210    pub free: u64,
211    /// The number of bytes reservable.
212    pub reservable: u64,
213    /// The number of bytes used.
214    pub used: u64,
215}
216
217/// Information about the track returned or playing on Lavalink.
218#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
219#[non_exhaustive]
220#[serde(rename_all = "camelCase")]
221pub struct TrackInfo {
222    /// The track artwork url.
223    pub artwork_url: Option<String>,
224    /// The track author.
225    pub author: String,
226    /// The track [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code).
227    pub isrc: Option<String>,
228    /// The track identifier.
229    pub identifier: String,
230    /// Whether the track is seekable.
231    pub is_seekable: bool,
232    /// Whether the track is a stream.
233    pub is_stream: bool,
234    /// The track length in milliseconds.
235    pub length: u64,
236    /// The track position in milliseconds.
237    pub position: u64,
238    /// The track source name.
239    pub source_name: String,
240    /// The track title.
241    pub title: String,
242    /// The track uri.
243    pub uri: Option<String>,
244}
245
246/// A track object for lavalink to consume and read.
247#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
248#[non_exhaustive]
249#[serde(rename_all = "camelCase")]
250pub struct Track {
251    /// The base64 encoded track to play
252    pub encoded: String,
253    /// Info about the track
254    pub info: TrackInfo,
255}
256
257/// Server dispatched an event. See the Event Types section for more information.
258#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
259#[non_exhaustive]
260#[serde(rename_all = "camelCase")]
261pub struct Event {
262    /// The data of the event type.
263    #[serde(flatten)]
264    pub data: EventData,
265    /// The guild id that this was received from.
266    pub guild_id: String,
267    /// The type of event.
268    pub r#type: EventType,
269}
270
271/// The type of event being dispatched as a message from the server as the event
272/// triggers.
273#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
274#[non_exhaustive]
275pub enum EventType {
276    /// Dispatched when a track starts playing.
277    TrackStartEvent,
278    /// Dispatched when a track ends.
279    TrackEndEvent,
280    /// Dispatched when a track throws an exception.
281    TrackExceptionEvent,
282    /// Dispatched when a track gets stuck while playing.
283    TrackStuckEvent,
284    /// Dispatched when the websocket connection to Discord voice servers is closed.
285    WebSocketClosedEvent,
286}
287
288/// The data of the server event that was dispatched when event triggers.
289#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
290#[non_exhaustive]
291#[serde(untagged)]
292pub enum EventData {
293    /// Dispatched when a track ends.
294    TrackEndEvent(TrackEnd),
295    /// Dispatched when a track throws an exception.
296    TrackExceptionEvent(TrackException),
297    /// Dispatched when a track gets stuck while playing.
298    TrackStuckEvent(TrackStuck),
299    /// Dispatched when a track starts playing.
300    TrackStartEvent(TrackStart),
301    /// Dispatched when the websocket connection to Discord voice servers is closed.
302    WebSocketClosedEvent(WebSocketClosed),
303}
304
305/// The reason for the track ending.
306#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
307#[non_exhaustive]
308#[serde(rename_all = "camelCase")]
309pub enum TrackEndReason {
310    /// The track was cleaned up.
311    Cleanup,
312    /// The track finished playing.
313    Finished,
314    /// The track failed to load.
315    LoadFailed,
316    /// The track was replaced
317    Replaced,
318    /// The track was stopped.
319    Stopped,
320}
321
322/// A track ended event from lavalink.
323#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
324#[non_exhaustive]
325#[serde(rename_all = "camelCase")]
326pub struct TrackEnd {
327    /// The reason that the track ended.
328    pub reason: TrackEndReason,
329    /// The track that ended playing.
330    pub track: Track,
331}
332
333/// A track started.
334#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
335#[non_exhaustive]
336#[serde(rename_all = "camelCase")]
337pub struct TrackStart {
338    /// The track that started playing.
339    pub track: Track,
340}
341
342/// Dispatched when a track throws an exception.
343#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
344#[non_exhaustive]
345#[serde(rename_all = "camelCase")]
346pub struct TrackException {
347    /// The occurred exception.
348    pub exception: Exception,
349    /// The track that threw the exception.
350    pub track: Track,
351}
352
353/// Dispatched when a track gets stuck while playing.
354#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
355#[non_exhaustive]
356#[serde(rename_all = "camelCase")]
357pub struct TrackStuck {
358    /// The threshold in milliseconds that was exceeded.
359    pub threshold_ms: u64,
360    /// The track that got stuck.
361    pub track: Track,
362}
363
364/// The voice websocket connection to Discord has been closed.
365#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
366#[non_exhaustive]
367#[serde(rename_all = "camelCase")]
368pub struct WebSocketClosed {
369    /// True if Discord closed the connection, false if Lavalink closed it.
370    pub by_remote: bool,
371    /// [Discord websocket opcode](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes)
372    /// that closed the connection.
373    pub code: u64,
374    /// Reason the connection was closed.
375    pub reason: String,
376}