From 8c6be25f02813d2567d723f58c9e76ee28af429f Mon Sep 17 00:00:00 2001 From: jude-lafitteIII Date: Mon, 18 May 2020 23:44:51 +0100 Subject: [PATCH] autodisconnect. random and popular searches --- Cargo.toml | 2 +- src/main.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 120 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 34f8efa..49e11c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" serenity = {path = "/home/jude/serenity", features = ["voice", "collector"]} sqlx = {version = "0.3", default-features = false, features = ["runtime-tokio", "macros", "mysql", "bigdecimal"]} dotenv = "0.15" -tokio = {version = "0.2.19", features = ["fs", "sync", "process"]} +tokio = {version = "0.2.19", features = ["fs", "sync", "process", "io-util"]} lazy_static = "1.4.0" diff --git a/src/main.rs b/src/main.rs index 016dfb3..006913c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,10 @@ use serenity::{ Mutex as SerenityMutex, * }, - voice::ffmpeg, + voice::{ + ffmpeg, + pcm + }, }; use sqlx::{ @@ -42,10 +45,14 @@ use dotenv::dotenv; use tokio::{ fs::File, + io::empty, process::Command, + sync::Mutex, + time, }; use std::{ + collections::HashSet, env, path::Path, sync::Arc, @@ -66,6 +73,12 @@ impl TypeMapKey for VoiceManager { type Value = Arc>; } +struct VoiceGuilds; + +impl TypeMapKey for VoiceGuilds { + type Value = Arc>>; +} + static THEME_COLOR: u32 = 0x00e0f3; lazy_static! { @@ -533,17 +546,26 @@ impl EventHandler for Handler {} async fn main() -> Result<(), Box> { dotenv()?; + let voice_guilds = Arc::new(Mutex::new(HashSet::new())); + let framework = StandardFramework::new() - .configure(|c| c.dynamic_prefix(|ctx, msg| Box::pin(async move { - let pool = ctx.data.read().await - .get::().cloned().expect("Could not get SQLPool from data"); + .configure(|c| c + .dynamic_prefix(|ctx, msg| Box::pin(async move { + let pool = ctx.data.read().await + .get::().cloned().expect("Could not get SQLPool from data"); - match GuildData::get_from_id(*msg.guild_id.unwrap().as_u64(), pool).await { - Some(guild) => Some(guild.prefix), + println!("dynamic_prefix: acquired pool and now about to query"); - None => Some(String::from("?")) - } - }))) + match GuildData::get_from_id(*msg.guild_id.unwrap().as_u64(), pool).await { + Some(guild) => Some(guild.prefix), + + None => Some(String::from("?")) + } + })) + .allow_dm(false) + .ignore_bots(true) + .ignore_webhooks(true) + ) .group(&ALLUSERS_GROUP) .group(&ROLEMANAGEDUSERS_GROUP) .group(&PERMISSIONMANAGEDUSERS_GROUP); @@ -561,13 +583,49 @@ async fn main() -> Result<(), Box> { data.insert::(pool); data.insert::(Arc::clone(&client.voice_manager)); + + data.insert::(voice_guilds.clone()); } - client.start().await?; + let cvm = Arc::clone(&client.voice_manager); + + // select on the client and client auto disconnector (when the client terminates, terminate the disconnector + tokio::select! { + _ = client.start() => {} + _ = disconnect_from_inactive(cvm, voice_guilds) => {} + }; Ok(()) } +async fn disconnect_from_inactive(voice_manager_mutex: Arc>, voice_guilds: Arc>>) { + loop { + let mut voice_guilds_acquired = voice_guilds.lock().await; + let mut voice_manager = voice_manager_mutex.lock().await; + + let mut to_remove = HashSet::new(); + + for guild in voice_guilds_acquired.iter() { + let manager_opt = voice_manager.get_mut(guild); + + if let Some(manager) = manager_opt { + let audio = manager.play_returning(pcm(false, empty())); + + if !audio.lock().await.playing { + manager.leave(); + to_remove.insert(guild.clone()); + } + } + } + + for val in to_remove.iter() { + voice_guilds_acquired.remove(val); + } + + time::delay_for(Duration::from_secs(30)).await; + } +} + #[command("play")] #[aliases("p")] async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { @@ -610,23 +668,32 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let mut voice_manager = voice_manager_lock.lock().await; + let voice_guilds_lock = ctx.data.read().await + .get::().cloned().expect("Could not get VoiceGuilds from data"); + + let mut voice_guilds = voice_guilds_lock.lock().await; + match voice_manager.get_mut(guild_id) { Some(handler) => { // play sound - handler.play(ffmpeg(fp).await?); + handler.play_only(ffmpeg(fp).await?); sound.plays += 1; sound.commit(pool).await?; + + voice_guilds.insert(guild_id); } None => { // try & join a voice channel match voice_manager.join(guild_id, user_channel) { Some(handler) => { - handler.play(ffmpeg(fp).await?); + handler.play_only(ffmpeg(fp).await?); sound.plays += 1; sound.commit(pool).await?; + + voice_guilds.insert(guild_id); } None => { @@ -1059,6 +1126,46 @@ async fn search_sounds(ctx: &Context, msg: &Message, args: Args) -> CommandResul Ok(()) } +#[command("popular")] +async fn show_popular_sounds(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { + let pool = ctx.data.read().await + .get::().cloned().expect("Could not get SQLPool from data"); + + let search_results = sqlx::query_as_unchecked!( + Sound, + " +SELECT * FROM sounds +ORDER BY plays + " + ) + .fetch_all(&pool) + .await?; + + format_search_results(search_results, msg, ctx).await?; + + Ok(()) +} + +#[command("random")] +async fn show_random_sounds(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { + let pool = ctx.data.read().await + .get::().cloned().expect("Could not get SQLPool from data"); + + let search_results = sqlx::query_as_unchecked!( + Sound, + " +SELECT * FROM sounds +ORDER BY rand() + " + ) + .fetch_all(&pool) + .await?; + + format_search_results(search_results, msg, ctx).await?; + + Ok(()) +} + #[command("greet")] async fn set_greet_sound(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let pool = ctx.data.read().await @@ -1102,10 +1209,3 @@ WHERE Ok(()) } - -/* -#[command("popular")] -async fn show_popular_sounds(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - -} -*/