removed all autodisconnect code so that it can be redone at some point hopefully.

This commit is contained in:
jellywx 2020-11-11 18:21:45 +00:00
parent 2737747f6e
commit c92c0d2207
3 changed files with 673 additions and 528 deletions

954
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
[package] [package]
name = "soundfx-rs" name = "soundfx-rs"
version = "1.0.1-rc.4" version = "1.0.1-rc.5"
authors = ["jude-lafitteIII <judewrs@gmail.com>"] authors = ["jude-lafitteIII <judewrs@gmail.com>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
serenity = { git = "https://github.com/Lakelezz/serenity", branch = "await", features = ["voice", "collector"] } serenity = { git = "https://github.com/jellywx/serenity", branch = "jellywx-member_permissions", features = ["voice", "collector"] }
sqlx = { version = "0.3.5", default-features = false, features = ["runtime-tokio", "macros", "mysql", "bigdecimal"] } sqlx = { version = "0.3.5", default-features = false, features = ["runtime-tokio", "macros", "mysql", "bigdecimal"] }
dotenv = "0.15" dotenv = "0.15"
tokio = { version = "0.2", features = ["fs", "sync", "process", "io-util"] } tokio = { version = "0.2", features = ["fs", "process", "io-util"] }
lazy_static = "1.4" lazy_static = "1.4"
reqwest = "0.10" reqwest = "0.10"

View File

@ -19,6 +19,7 @@ use serenity::{
macros::{check, command, group, hook}, macros::{check, command, group, hook},
Args, CheckResult, CommandError, CommandResult, DispatchError, Reason, StandardFramework, Args, CheckResult, CommandError, CommandResult, DispatchError, Reason, StandardFramework,
}, },
http::Http,
model::{ model::{
channel::{Channel, Message}, channel::{Channel, Message},
guild::Guild, guild::Guild,
@ -26,31 +27,20 @@ use serenity::{
voice::VoiceState, voice::VoiceState,
}, },
prelude::{Mutex as SerenityMutex, *}, prelude::{Mutex as SerenityMutex, *},
utils::shard_id,
voice::Handler as VoiceHandler, voice::Handler as VoiceHandler,
}; };
use sqlx::{ use sqlx::mysql::MySqlPool;
mysql::{MySqlConnection, MySqlPool},
Pool,
};
use dotenv::dotenv; use dotenv::dotenv;
use tokio::{sync::RwLock, time}; use std::{collections::HashMap, env, sync::Arc, time::Duration};
use serenity::http::Http; struct MySQL;
use serenity::utils::shard_id;
use std::{
collections::HashMap,
env,
sync::Arc,
time::{Duration, SystemTime, UNIX_EPOCH},
};
struct SQLPool; impl TypeMapKey for MySQL {
type Value = MySqlPool;
impl TypeMapKey for SQLPool {
type Value = Pool<MySqlConnection>;
} }
struct VoiceManager; struct VoiceManager;
@ -59,12 +49,6 @@ impl TypeMapKey for VoiceManager {
type Value = Arc<SerenityMutex<ClientVoiceManager>>; type Value = Arc<SerenityMutex<ClientVoiceManager>>;
} }
struct VoiceGuilds;
impl TypeMapKey for VoiceGuilds {
type Value = Arc<RwLock<HashMap<GuildId, u64>>>;
}
struct ReqwestClient; struct ReqwestClient;
impl TypeMapKey for ReqwestClient { impl TypeMapKey for ReqwestClient {
@ -150,7 +134,7 @@ async fn role_check(ctx: &Context, msg: &Message, _args: &mut Args) -> CheckResu
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -229,7 +213,12 @@ async fn permission_check(ctx: &Context, msg: &Message, _args: &mut Args) -> Che
async fn perform_permission_check(ctx: &Context, msg: &&Message) -> CheckResult { async fn perform_permission_check(ctx: &Context, msg: &&Message) -> CheckResult {
if let Some(guild) = msg.guild(&ctx).await { if let Some(guild) = msg.guild(&ctx).await {
if guild.member_permissions(&msg.author).await.manage_guild() { if guild
.member_permissions(&ctx, &msg.author)
.await
.unwrap()
.manage_guild()
{
CheckResult::Success CheckResult::Success
} else { } else {
CheckResult::Failure(Reason::User(String::from( CheckResult::Failure(Reason::User(String::from(
@ -307,7 +296,7 @@ impl EventHandler for Handler {
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -350,25 +339,11 @@ SELECT name, id, plays, public, server_id, uploader_id
.cloned() .cloned()
.expect("Could not get VoiceManager from data"); .expect("Could not get VoiceManager from data");
let voice_guilds = ctx
.data
.read()
.await
.get::<VoiceGuilds>()
.cloned()
.expect("Could not get VoiceGuilds from data");
let mut voice_manager = voice_manager_lock.lock().await; let mut voice_manager = voice_manager_lock.lock().await;
if let Some(handler) = voice_manager.join(guild_id, user_channel) { if let Some(handler) = voice_manager.join(guild_id, user_channel) {
let _audio = play_audio( let _audio =
&mut sound, play_audio(&mut sound, guild_data, handler, pool).await;
guild_data,
handler,
voice_guilds,
pool,
)
.await;
} }
} }
} }
@ -383,10 +358,9 @@ async fn play_audio(
sound: &mut Sound, sound: &mut Sound,
guild: GuildData, guild: GuildData,
handler: &mut VoiceHandler, handler: &mut VoiceHandler,
voice_guilds: Arc<RwLock<HashMap<GuildId, u64>>>, mysql_pool: MySqlPool,
pool: MySqlPool,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let audio = handler.play_only(sound.store_sound_source(pool.clone()).await?); let audio = handler.play_only(sound.store_sound_source(mysql_pool.clone()).await?);
{ {
let mut locked = audio.lock().await; let mut locked = audio.lock().await;
@ -395,16 +369,7 @@ async fn play_audio(
} }
sound.plays += 1; sound.plays += 1;
sound.commit(pool).await?; sound.commit(mysql_pool).await?;
{
let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
voice_guilds
.write()
.await
.insert(GuildId(guild.id), since_epoch.as_secs());
}
Ok(()) Ok(())
} }
@ -442,8 +407,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let logged_in_id = http.get_current_user().await?.id; let logged_in_id = http.get_current_user().await?.id;
let voice_guilds = Arc::new(RwLock::new(HashMap::new()));
let framework = StandardFramework::new() let framework = StandardFramework::new()
.configure(|c| { .configure(|c| {
c.dynamic_prefix(|ctx, msg| { c.dynamic_prefix(|ctx, msg| {
@ -452,7 +415,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -494,7 +457,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.on_dispatch_error(dispatch_error_hook); .on_dispatch_error(dispatch_error_hook);
let mut client = let mut client =
Client::new(&env::var("DISCORD_TOKEN").expect("Missing token from environment")) Client::builder(&env::var("DISCORD_TOKEN").expect("Missing token from environment"))
.intents( .intents(
GatewayIntents::GUILD_VOICE_STATES GatewayIntents::GUILD_VOICE_STATES
| GatewayIntents::GUILD_MESSAGES | GatewayIntents::GUILD_MESSAGES
@ -506,61 +469,25 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.expect("Error occurred creating client"); .expect("Error occurred creating client");
{ {
let pool = MySqlPool::new(&env::var("DATABASE_URL").expect("No database URL provided")) let mysql_pool =
.await MySqlPool::new(&env::var("DATABASE_URL").expect("No database URL provided"))
.unwrap(); .await
.unwrap();
let mut data = client.data.write().await; let mut data = client.data.write().await;
data.insert::<SQLPool>(pool);
data.insert::<MySQL>(mysql_pool);
data.insert::<VoiceManager>(Arc::clone(&client.voice_manager)); data.insert::<VoiceManager>(Arc::clone(&client.voice_manager));
data.insert::<VoiceGuilds>(voice_guilds.clone());
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new())); data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
} }
let cvm = Arc::clone(&client.voice_manager);
tokio::spawn(async {
let disconnect_cycle_delay = env::var("DISCONNECT_CYCLE_DELAY")
.unwrap_or("300".to_string())
.parse::<u64>()
.expect("DISCONNECT_CYCLE_DELAY invalid");
disconnect_from_inactive(cvm, voice_guilds, disconnect_cycle_delay).await
});
client.start_autosharded().await?; client.start_autosharded().await?;
Ok(()) Ok(())
} }
async fn disconnect_from_inactive(
voice_manager_mutex: Arc<SerenityMutex<ClientVoiceManager>>,
voice_guilds: Arc<RwLock<HashMap<GuildId, u64>>>,
wait_time: u64,
) {
loop {
time::delay_for(Duration::from_secs(wait_time)).await;
let voice_guilds_acquired = voice_guilds.read().await;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
for (guild, last_active) in voice_guilds_acquired.iter() {
if (now - last_active) > wait_time {
let mut voice_manager = voice_manager_mutex.lock().await;
voice_manager.leave(guild);
}
}
}
}
#[command("play")] #[command("play")]
#[aliases("p")] #[aliases("p")]
async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
@ -587,7 +514,7 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -619,15 +546,7 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let guild_data = let guild_data =
GuildData::get_from_id(guild, pool.clone()).await.unwrap(); GuildData::get_from_id(guild, pool.clone()).await.unwrap();
let voice_guilds = ctx play_audio(sound, guild_data, handler, pool).await?;
.data
.read()
.await
.get::<VoiceGuilds>()
.cloned()
.expect("Could not get VoiceGuilds from data");
play_audio(sound, guild_data, handler, voice_guilds, pool).await?;
msg.channel_id msg.channel_id
.say( .say(
@ -716,7 +635,7 @@ async fn change_volume(ctx: &Context, msg: &Message, mut args: Args) -> CommandR
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -764,7 +683,7 @@ async fn change_prefix(ctx: &Context, msg: &Message, mut args: Args) -> CommandR
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -842,7 +761,7 @@ async fn upload_new_sound(ctx: &Context, msg: &Message, args: Args) -> CommandRe
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -870,45 +789,57 @@ async fn upload_new_sound(ctx: &Context, msg: &Message, args: Args) -> CommandRe
} }
if permit_upload { if permit_upload {
msg.channel_id.say(&ctx, "Please now upload an audio file under 1MB in size (larger files will be automatically trimmed):").await?; let attachment = if let Some(attachment) = msg.attachments.get(0) {
Some(attachment.url.clone())
} else {
msg.channel_id.say(&ctx, "Please now upload an audio file under 1MB in size (larger files will be automatically trimmed):").await?;
let reply = msg let reply = msg
.channel_id .channel_id
.await_reply(&ctx) .await_reply(&ctx)
.author_id(msg.author.id) .author_id(msg.author.id)
.timeout(Duration::from_secs(30)) .timeout(Duration::from_secs(30))
.await; .await;
match reply { match reply {
Some(reply_msg) => { Some(reply_msg) => {
if reply_msg.attachments.len() == 1 { if let Some(attachment) = reply_msg.attachments.get(0) {
match Sound::create_anon( Some(attachment.url.clone())
&new_name, } else {
&reply_msg.attachments[0].url, msg.channel_id.say(&ctx, "Please upload 1 attachment following your upload command. Aborted").await?;
*msg.guild_id.unwrap().as_u64(),
*msg.author.id.as_u64(),
pool,
)
.await
{
Ok(_) => {
msg.channel_id.say(&ctx, "Sound has been uploaded").await?;
}
Err(e) => { None
println!("Error occurred during upload: {:?}", e);
msg.channel_id.say(&ctx, "Sound failed to upload.").await?;
}
} }
} else { }
msg.channel_id.say(&ctx, "Please upload 1 attachment following your upload command. Aborted").await?;
None => {
msg.channel_id
.say(&ctx, "Upload timed out. Please redo the command")
.await?;
None
} }
} }
};
None => { if let Some(url) = attachment {
msg.channel_id match Sound::create_anon(
.say(&ctx, "Upload timed out. Please redo the command") &new_name,
.await?; url.as_str(),
*msg.guild_id.unwrap().as_u64(),
*msg.author.id.as_u64(),
pool,
)
.await
{
Ok(_) => {
msg.channel_id.say(&ctx, "Sound has been uploaded").await?;
}
Err(e) => {
println!("Error occurred during upload: {:?}", e);
msg.channel_id.say(&ctx, "Sound failed to upload.").await?;
}
} }
} }
} else { } else {
@ -943,7 +874,7 @@ async fn set_allowed_roles(ctx: &Context, msg: &Message, args: Args) -> CommandR
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1023,7 +954,7 @@ async fn list_sounds(ctx: &Context, msg: &Message, args: Args) -> CommandResult
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1070,7 +1001,7 @@ async fn change_public(ctx: &Context, msg: &Message, args: Args) -> CommandResul
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
let uid = msg.author.id.as_u64(); let uid = msg.author.id.as_u64();
@ -1120,7 +1051,7 @@ async fn delete_sound(ctx: &Context, msg: &Message, args: Args) -> CommandResult
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1195,7 +1126,7 @@ async fn search_sounds(ctx: &Context, msg: &Message, args: Args) -> CommandResul
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1221,7 +1152,7 @@ async fn show_popular_sounds(ctx: &Context, msg: &Message, _args: Args) -> Comma
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1248,7 +1179,7 @@ async fn show_random_sounds(ctx: &Context, msg: &Message, _args: Args) -> Comman
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1278,7 +1209,7 @@ async fn set_greet_sound(ctx: &Context, msg: &Message, args: Args) -> CommandRes
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not get SQLPool from data"); .expect("Could not get SQLPool from data");
@ -1383,7 +1314,7 @@ async fn allow_greet_sounds(ctx: &Context, msg: &Message, _args: Args) -> Comman
.data .data
.read() .read()
.await .await
.get::<SQLPool>() .get::<MySQL>()
.cloned() .cloned()
.expect("Could not acquire SQL pool from data"); .expect("Could not acquire SQL pool from data");