lavalink_rs/model/
events.rs

1use crate::client::LavalinkClient;
2use crate::model::*;
3
4#[derive(Debug, Clone, Default)]
5#[cfg_attr(not(feature = "python"), derive(Hash))]
6pub struct Events {
7    /// Every single event will trigger this event with the raw data received.
8    pub raw: Option<fn(LavalinkClient, session_id: String, &serde_json::Value) -> BoxFuture<()>>,
9    /// Dispatched by Lavalink upon successful connection and authorization.
10    pub ready: Option<fn(LavalinkClient, session_id: String, &Ready) -> BoxFuture<()>>,
11    /// Dispatched periodically with the current state of a player.
12    pub player_update:
13        Option<fn(LavalinkClient, session_id: String, &PlayerUpdate) -> BoxFuture<()>>,
14    /// A collection of statistics sent every minute.
15    pub stats: Option<fn(LavalinkClient, session_id: String, &Stats) -> BoxFuture<()>>,
16    /// Dispatched when a track starts playing.
17    pub track_start: Option<fn(LavalinkClient, session_id: String, &TrackStart) -> BoxFuture<()>>,
18    /// Dispatched when a track ends.
19    /// track_exception and track_stuck will also trigger this event.
20    pub track_end: Option<fn(LavalinkClient, session_id: String, &TrackEnd) -> BoxFuture<()>>,
21    /// Dispatched when a track throws an exception.
22    pub track_exception:
23        Option<fn(LavalinkClient, session_id: String, &TrackException) -> BoxFuture<()>>,
24    /// Dispatched when a track gets stuck while playing.
25    pub track_stuck: Option<fn(LavalinkClient, session_id: String, &TrackStuck) -> BoxFuture<()>>,
26    /// Dispatched when an audio WebSocket to Discord is closed.
27    pub websocket_closed:
28        Option<fn(LavalinkClient, session_id: String, &WebSocketClosed) -> BoxFuture<()>>,
29
30    #[cfg(feature = "python")]
31    pub(crate) event_handler: Option<crate::python::event::EventHandler>,
32}
33
34#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
37/// Dispatched by Lavalink upon successful connection and authorization.
38pub struct Ready {
39    pub op: String,
40    /// The lavalink session ID, used for some REST requests and resuming.
41    pub session_id: String,
42    /// Whether this session was resumed.
43    pub resumed: bool,
44}
45
46#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47#[serde(rename_all = "camelCase")]
48#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
49/// Dispatched periodically with the current state of a player.
50pub struct PlayerUpdate {
51    pub op: String,
52    #[serde(deserialize_with = "deserialize_number_from_string")]
53    pub guild_id: GuildId,
54    /// The player state.
55    pub state: player::State,
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
61/// A collection of statistics sent every minute.
62pub struct Stats {
63    #[serde(default)]
64    pub op: String,
65    /// The amount of players connected to the node.
66    pub players: u64,
67    /// The amount of players playing a track.
68    pub playing_players: u64,
69    /// The uptime of the node in milliseconds.
70    pub uptime: u64,
71    /// Memory statistics of the node.
72    pub memory: Memory,
73    /// CPU statistics of the node.
74    pub cpu: Cpu,
75    /// The frame stats of the node.
76    ///
77    /// This field is None if there's no players, or it was requested via the REST API.
78    pub frame_stats: Option<FrameStats>,
79}
80
81#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
84pub struct Cpu {
85    pub cores: u64,
86    pub system_load: f64,
87    pub lavalink_load: f64,
88}
89
90#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
91#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
92pub struct Memory {
93    pub free: u64,
94    pub used: u64,
95    pub allocated: u64,
96    pub reservable: u64,
97}
98
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
100#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
101pub struct FrameStats {
102    /// The amount of frames sent to Discord.
103    pub sent: u64,
104    /// The amount of frames that were nulled.
105    pub nulled: u64,
106    /// The difference between sent frames and the expected amount of frames.
107    ///
108    /// The expected amount of frames is 3000 (1 every 20 ms) per player.
109    /// If the deficit is negative, too many frames were sent, and if it's positive, not enough frames got sent.
110    pub deficit: i64,
111}
112
113#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
116/// Dispatched when a track starts playing.
117pub struct TrackStart {
118    pub op: String,
119    #[serde(rename = "type")]
120    pub event_type: String,
121    #[serde(deserialize_with = "deserialize_number_from_string")]
122    pub guild_id: GuildId,
123    /// The track that started playing.
124    pub track: track::TrackData,
125}
126
127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
130/// Dispatched when a track ends.
131/// track_exception and track_stuck will also trigger this event.
132pub struct TrackEnd {
133    pub op: String,
134    #[serde(rename = "type")]
135    pub event_type: String,
136    #[serde(deserialize_with = "deserialize_number_from_string")]
137    pub guild_id: GuildId,
138    /// The track that finished playing.
139    pub track: track::TrackData,
140    /// The reason the track finished.
141    pub reason: TrackEndReason,
142}
143
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all, eq, eq_int))]
147/// The reason the track finished.
148pub enum TrackEndReason {
149    Finished,
150    LoadFailed,
151    Stopped,
152    Replaced,
153    Cleanup,
154}
155
156impl From<TrackEndReason> for bool {
157    /// If the player should continue playing with the next track on the queue or not.
158    fn from(value: TrackEndReason) -> Self {
159        match value {
160            TrackEndReason::Finished => true,
161            TrackEndReason::LoadFailed => true,
162            TrackEndReason::Stopped => false,
163            TrackEndReason::Replaced => false,
164            TrackEndReason::Cleanup => false,
165        }
166    }
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
172/// Dispatched when a track throws an exception.
173pub struct TrackException {
174    pub op: String,
175    #[serde(rename = "type")]
176    pub event_type: String,
177    #[serde(deserialize_with = "deserialize_number_from_string")]
178    pub guild_id: GuildId,
179    /// The track that threw the exception
180    pub track: track::TrackData,
181    /// The exception itself.
182    pub exception: track::TrackError,
183}
184
185#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
186#[serde(rename_all = "camelCase")]
187#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
188/// Dispatched when a track gets stuck while playing.
189pub struct TrackStuck {
190    pub op: String,
191    #[serde(rename = "type")]
192    pub event_type: String,
193    #[serde(deserialize_with = "deserialize_number_from_string")]
194    pub guild_id: GuildId,
195    /// The track that got stuck.
196    pub track: track::TrackData,
197    /// The threshold in milliseconds that was exceeded.
198    pub threshold_ms: u64,
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
202#[serde(rename_all = "camelCase")]
203#[cfg_attr(feature = "python", pyo3::pyclass(get_all, set_all))]
204/// Dispatched when an audio WebSocket to Discord is closed.
205pub struct WebSocketClosed {
206    pub op: String,
207    #[serde(rename = "type")]
208    pub event_type: String,
209    #[serde(deserialize_with = "deserialize_number_from_string")]
210    pub guild_id: GuildId,
211    /// Status code returned by discord.
212    ///
213    /// See the [discord docs](https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes)
214    /// for a list of them.
215    pub code: u16,
216    /// The reason the socket was closed.
217    pub reason: String,
218    /// Whether the connection was closed by Discord or not.
219    pub by_remote: bool,
220}