// src/lavalink_handler.rs use serenity::http::Http; // Import Http for sending messages use lavalink_rs::gateway::{NodeEvent, LavalinkEventHandler as LavalinkEventHandlerRs}; use tracing::{error, info, instrument}; use async_trait::async_trait; // Needed to implement async trait methods use std::sync::Arc; // Needed for Arc // --- lavalink-rs Event Handler --- // This handler receives events directly from the connected Lavalink server. // It allows reacting to playback events like track start/end. pub struct MyLavalinkEventHandlerRs { pub http: Arc, // Hold the Http client to send messages to Discord // Add state if needed, e.g., channel IDs for announcements per guild. } #[async_trait] impl LavalinkEventHandlerRs for MyLavalinkEventHandlerRs { // The main handler function for all Lavalink NodeEvents. #[instrument(skip(self))] // Adds tracing to the handler async fn handle(&self, event: NodeEvent) { // You can uncomment this for verbose logging of all events: // info!("Received LavaLink event: {:?}", event); match event { // Handle specific event types NodeEvent::TrackStart { guild_id, track, .. } => { info!( "Track started on guild {}: {}", guild_id, track.info.title ); // Example: send a message announcing the track. // This requires knowing which channel to send it to, often // stored per guild in the BotState's announcement_channels. // Accessing BotState would require passing it here or using a global static. // let channel_id = { /* logic to get channel_id from guild_id using self.http or shared state */ }; // if let Some(channel_id) = channel_id { // if let Err(e) = ChannelId(channel_id).say(&self.http, // format!("Now playing: **{}** by **{}**", track.info.title, track.info.author) // ).await { // error!("Failed to send track start message: {}", e); // } // } } NodeEvent::TrackEnd { guild_id, track, reason, .. } => { info!( "Track ended on guild {}: {}, reason: {:?}", guild_id, track.info.title, reason ); // Logic for track end, e.g., cleaning up state if not using Lavalink queues } NodeEvent::TrackException { guild_id, track, error, .. } => { error!( "Track exception on guild {}: {}, error: {}", guild_id, track.info.title, error ); // Notify the channel about the exception } NodeEvent::TrackStuck { guild_id, track, threshold_ms, .. } => { error!( "Track stuck on guild {}: {}, threshold: {}ms", guild_id, track.info.title, threshold_ms ); // Notify the channel about the stuck track } NodeEvent::WebSocketOpen { node, .. } => { info!("Lavalink WebSocket opened: {}", node); } NodeEvent::WebSocketClosed { node, code, reason, .. } => { error!("Lavalink WebSocket closed: {}, Code: {:?}, Reason: {}", node, code, reason); } // Ignore these common events to avoid log spam NodeEvent::Ready { .. } | NodeEvent::Stats { .. } => { /* Ignore */ } NodeEvent::PlayerUpdate { .. } => { /* Ignore */ } } } }