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}