updated serenity and songbird versions to latest

This commit is contained in:
jellywx 2021-08-13 14:20:45 +01:00
parent 9db0265f5e
commit 7354646c89
9 changed files with 406 additions and 601 deletions

750
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
[package] [package]
name = "soundfx-rs" name = "soundfx-rs"
version = "1.3.1" version = "1.4.0"
authors = ["jellywx <judesouthworth@pm.me>"] authors = ["jellywx <judesouthworth@pm.me>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
songbird = { path = "/home/jude/songbird" } songbird = { git = "https://github.com/serenity-rs/songbird", branch = "next" }
serenity = { path = "/home/jude/serenity", features = ["voice", "collector", "unstable_discord_api"] } serenity = { git = "https://github.com/serenity-rs/serenity", branch = "next", features = ["voice", "collector", "unstable_discord_api"] }
sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] } sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] }
dotenv = "0.15" dotenv = "0.15"
tokio = { version = "1", features = ["fs", "process", "io-util"] } tokio = { version = "1", features = ["fs", "process", "io-util"] }

View File

@ -296,7 +296,9 @@ impl ApplicationCommandOptionType {
impl ToTokens for ApplicationCommandOptionType { impl ToTokens for ApplicationCommandOptionType {
fn to_tokens(&self, stream: &mut TokenStream2) { fn to_tokens(&self, stream: &mut TokenStream2) {
let path = quote!(serenity::model::interactions::ApplicationCommandOptionType); let path = quote!(
serenity::model::interactions::application_command::ApplicationCommandOptionType
);
let variant = match self { let variant = match self {
ApplicationCommandOptionType::SubCommand => quote!(SubCommand), ApplicationCommandOptionType::SubCommand => quote!(SubCommand),
ApplicationCommandOptionType::SubCommandGroup => quote!(SubCommandGroup), ApplicationCommandOptionType::SubCommandGroup => quote!(SubCommandGroup),

View File

@ -192,7 +192,7 @@ async fn info(
invoke: &(dyn CommandInvoke + Sync + Send), invoke: &(dyn CommandInvoke + Sync + Send),
_args: Args, _args: Args,
) -> CommandResult { ) -> CommandResult {
let current_user = ctx.cache.current_user().await; let current_user = ctx.cache.current_user();
invoke.respond(ctx.http.clone(), CreateGenericResponse::new() invoke.respond(ctx.http.clone(), CreateGenericResponse::new()
.embed(|e| e .embed(|e| e

View File

@ -225,7 +225,7 @@ pub async fn delete_sound(
} else { } else {
let has_perms = { let has_perms = {
if let Ok(member) = invoke.member(&ctx).await { if let Ok(member) = invoke.member(&ctx).await {
if let Ok(perms) = member.permissions(&ctx).await { if let Ok(perms) = member.permissions(&ctx) {
perms.manage_guild() perms.manage_guild()
} else { } else {
false false

View File

@ -4,7 +4,7 @@ use serenity::{
builder::CreateActionRow, builder::CreateActionRow,
client::Context, client::Context,
framework::standard::CommandResult, framework::standard::CommandResult,
model::interactions::{ButtonStyle, InteractionResponseType}, model::interactions::{message_component::ButtonStyle, InteractionResponseType},
}; };
use songbird::{ use songbird::{
@ -42,7 +42,7 @@ pub async fn play(
invoke: &(dyn CommandInvoke + Sync + Send), invoke: &(dyn CommandInvoke + Sync + Send),
args: Args, args: Args,
) -> CommandResult { ) -> CommandResult {
let guild = invoke.guild(ctx.cache.clone()).await.unwrap(); let guild = invoke.guild(ctx.cache.clone()).unwrap();
invoke invoke
.respond( .respond(
@ -72,7 +72,7 @@ pub async fn loop_play(
invoke: &(dyn CommandInvoke + Sync + Send), invoke: &(dyn CommandInvoke + Sync + Send),
args: Args, args: Args,
) -> CommandResult { ) -> CommandResult {
let guild = invoke.guild(ctx.cache.clone()).await.unwrap(); let guild = invoke.guild(ctx.cache.clone()).unwrap();
invoke invoke
.respond( .respond(
@ -101,7 +101,7 @@ pub async fn play_ambience(
invoke: &(dyn CommandInvoke + Sync + Send), invoke: &(dyn CommandInvoke + Sync + Send),
args: Args, args: Args,
) -> CommandResult { ) -> CommandResult {
let guild = invoke.guild(ctx.cache.clone()).await.unwrap(); let guild = invoke.guild(ctx.cache.clone()).unwrap();
let channel_to_join = guild let channel_to_join = guild
.voice_states .voice_states

View File

@ -14,7 +14,7 @@ use serenity::{
gateway::{Activity, Ready}, gateway::{Activity, Ready},
guild::Guild, guild::Guild,
id::GuildId, id::GuildId,
interactions::Interaction, interactions::{Interaction, InteractionResponseType},
voice::VoiceState, voice::VoiceState,
}, },
utils::shard_id, utils::shard_id,
@ -22,9 +22,8 @@ use serenity::{
use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler}; use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler};
use crate::framework::{Args, CommandInvoke}; use crate::framework::Args;
use serenity::model::interactions::{InteractionData, InteractionType};
use serenity::model::prelude::InteractionResponseType;
use std::{collections::HashMap, env}; use std::{collections::HashMap, env};
pub struct RestartTrack; pub struct RestartTrack;
@ -63,13 +62,12 @@ impl EventHandler for Handler {
async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) { async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) {
if is_new { if is_new {
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") { if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
let shard_count = ctx.cache.shard_count().await; let shard_count = ctx.cache.shard_count();
let current_shard_id = shard_id(guild.id.as_u64().to_owned(), shard_count); let current_shard_id = shard_id(guild.id.as_u64().to_owned(), shard_count);
let guild_count = ctx let guild_count = ctx
.cache .cache
.guilds() .guilds()
.await
.iter() .iter()
.filter(|g| shard_id(g.as_u64().to_owned(), shard_count) == current_shard_id) .filter(|g| shard_id(g.as_u64().to_owned(), shard_count) == current_shard_id)
.count() as u64; .count() as u64;
@ -91,7 +89,7 @@ impl EventHandler for Handler {
.post( .post(
format!( format!(
"https://top.gg/api/bots/{}/stats", "https://top.gg/api/bots/{}/stats",
ctx.cache.current_user_id().await.as_u64() ctx.cache.current_user_id().as_u64()
) )
.as_str(), .as_str(),
) )
@ -117,8 +115,7 @@ impl EventHandler for Handler {
if let Some(past_state) = old { if let Some(past_state) = old {
if let (Some(guild_id), None) = (guild_id_opt, new.channel_id) { if let (Some(guild_id), None) = (guild_id_opt, new.channel_id) {
if let Some(channel_id) = past_state.channel_id { if let Some(channel_id) = past_state.channel_id {
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx).await if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
{
if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 { if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 {
let songbird = songbird::get(&ctx).await.unwrap(); let songbird = songbird::get(&ctx).await.unwrap();
@ -128,7 +125,7 @@ impl EventHandler for Handler {
} }
} }
} else if let (Some(guild_id), Some(user_channel)) = (guild_id_opt, new.channel_id) { } else if let (Some(guild_id), Some(user_channel)) = (guild_id_opt, new.channel_id) {
if let Some(guild) = ctx.cache.guild(guild_id).await { if let Some(guild) = ctx.cache.guild(guild_id) {
let pool = ctx let pool = ctx
.data .data
.read() .read()
@ -183,12 +180,12 @@ SELECT name, id, plays, public, server_id, uploader_id
} }
async fn interaction_create(&self, ctx: Context, interaction: Interaction) { async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
if interaction.guild_id.is_none() { match interaction {
return; Interaction::ApplicationCommand(application_command) => {
} if application_command.guild_id.is_none() {
return;
}
match interaction.kind {
InteractionType::ApplicationCommand => {
let framework = ctx let framework = ctx
.data .data
.read() .read()
@ -197,33 +194,34 @@ SELECT name, id, plays, public, server_id, uploader_id
.cloned() .cloned()
.expect("RegexFramework not found in context"); .expect("RegexFramework not found in context");
framework.execute(ctx, interaction).await; framework.execute(ctx, application_command).await;
} }
InteractionType::MessageComponent => { Interaction::MessageComponent(component) => {
if let (Some(InteractionData::MessageComponent(data)), Some(member)) = if component.guild_id.is_none() {
(interaction.clone().data, interaction.clone().member) return;
{
let mut args = Args {
args: Default::default(),
};
args.args.insert("query".to_string(), data.custom_id);
play_from_query(
&ctx,
interaction.guild(ctx.cache.clone()).await.unwrap(),
member.user.id,
args,
false,
)
.await;
interaction
.create_interaction_response(ctx, |r| {
r.kind(InteractionResponseType::DeferredUpdateMessage)
})
.await
.unwrap();
} }
let mut args = Args {
args: Default::default(),
};
args.args
.insert("query".to_string(), component.data.custom_id.clone());
play_from_query(
&ctx,
component.guild_id.unwrap().to_guild_cached(&ctx).unwrap(),
component.user.id,
args,
false,
)
.await;
component
.create_interaction_response(ctx, |r| {
r.kind(InteractionResponseType::DeferredUpdateMessage)
})
.await
.unwrap();
} }
_ => {} _ => {}
} }

View File

@ -10,8 +10,12 @@ use serenity::{
channel::{Channel, GuildChannel, Message}, channel::{Channel, GuildChannel, Message},
guild::{Guild, Member}, guild::{Guild, Member},
id::{ChannelId, GuildId, UserId}, id::{ChannelId, GuildId, UserId},
interactions::{ApplicationCommand, Interaction, InteractionData}, interactions::{
prelude::{ApplicationCommandOptionType, InteractionResponseType}, application_command::{
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
},
InteractionResponseType,
},
}, },
prelude::TypeMapKey, prelude::TypeMapKey,
Result as SerenityResult, Result as SerenityResult,
@ -126,11 +130,11 @@ impl CreateGenericResponse {
pub trait CommandInvoke { pub trait CommandInvoke {
fn channel_id(&self) -> ChannelId; fn channel_id(&self) -> ChannelId;
fn guild_id(&self) -> Option<GuildId>; fn guild_id(&self) -> Option<GuildId>;
async fn guild(&self, cache: Arc<Cache>) -> Option<Guild>; fn guild(&self, cache: Arc<Cache>) -> Option<Guild>;
fn author_id(&self) -> UserId; fn author_id(&self) -> UserId;
async fn member(&self, context: &Context) -> SerenityResult<Member>; async fn member(&self, context: &Context) -> SerenityResult<Member>;
fn msg(&self) -> Option<Message>; fn msg(&self) -> Option<Message>;
fn interaction(&self) -> Option<Interaction>; fn interaction(&self) -> Option<ApplicationCommandInteraction>;
async fn respond( async fn respond(
&self, &self,
http: Arc<Http>, http: Arc<Http>,
@ -153,8 +157,8 @@ impl CommandInvoke for Message {
self.guild_id self.guild_id
} }
async fn guild(&self, cache: Arc<Cache>) -> Option<Guild> { fn guild(&self, cache: Arc<Cache>) -> Option<Guild> {
self.guild(cache).await self.guild(cache)
} }
fn author_id(&self) -> UserId { fn author_id(&self) -> UserId {
@ -169,7 +173,7 @@ impl CommandInvoke for Message {
Some(self.clone()) Some(self.clone())
} }
fn interaction(&self) -> Option<Interaction> { fn interaction(&self) -> Option<ApplicationCommandInteraction> {
None None
} }
@ -187,7 +191,10 @@ impl CommandInvoke for Message {
} }
if let Some(components) = generic_response.components { if let Some(components) = generic_response.components {
m.set_components(components.clone()); m.components(|c| {
*c = components;
c
});
} }
m m
@ -210,7 +217,10 @@ impl CommandInvoke for Message {
} }
if let Some(components) = generic_response.components { if let Some(components) = generic_response.components {
m.set_components(components.clone()); m.components(|c| {
*c = components;
c
});
} }
m m
@ -221,18 +231,18 @@ impl CommandInvoke for Message {
} }
#[async_trait] #[async_trait]
impl CommandInvoke for Interaction { impl CommandInvoke for ApplicationCommandInteraction {
fn channel_id(&self) -> ChannelId { fn channel_id(&self) -> ChannelId {
self.channel_id.unwrap() self.channel_id
} }
fn guild_id(&self) -> Option<GuildId> { fn guild_id(&self) -> Option<GuildId> {
self.guild_id self.guild_id
} }
async fn guild(&self, cache: Arc<Cache>) -> Option<Guild> { fn guild(&self, cache: Arc<Cache>) -> Option<Guild> {
if let Some(guild_id) = self.guild_id { if let Some(guild_id) = self.guild_id {
guild_id.to_guild_cached(cache).await guild_id.to_guild_cached(cache)
} else { } else {
None None
} }
@ -250,7 +260,7 @@ impl CommandInvoke for Interaction {
None None
} }
fn interaction(&self) -> Option<Interaction> { fn interaction(&self) -> Option<ApplicationCommandInteraction> {
Some(self.clone()) Some(self.clone())
} }
@ -269,7 +279,10 @@ impl CommandInvoke for Interaction {
} }
if let Some(components) = generic_response.components { if let Some(components) = generic_response.components {
d.set_components(components.clone()); d.components(|c| {
*c = components;
c
});
} }
d d
@ -292,7 +305,10 @@ impl CommandInvoke for Interaction {
} }
if let Some(components) = generic_response.components { if let Some(components) = generic_response.components {
d.set_components(components.clone()); d.components(|c| {
*c = components;
c
});
} }
d d
@ -652,63 +668,64 @@ impl RegexFramework {
info!("{} slash commands built! Ready to go", count); info!("{} slash commands built! Ready to go", count);
} }
pub async fn execute(&self, ctx: Context, interaction: Interaction) { pub async fn execute(&self, ctx: Context, interaction: ApplicationCommandInteraction) {
if let Some(InteractionData::ApplicationCommand(data)) = interaction.data.clone() { let command = {
let command = { self.commands.get(&interaction.data.name).expect(&format!(
let name = data.name; "Received invalid command: {}",
interaction.data.name
))
};
self.commands if command
.get(&name) .check_permissions(
.expect(&format!("Received invalid command: {}", name)) &ctx,
}; &interaction.guild(ctx.cache.clone()).unwrap(),
&interaction.clone().member.unwrap(),
)
.await
{
let mut args = HashMap::new();
if command for arg in interaction
.check_permissions( .data
&ctx, .options
&interaction.guild(ctx.cache.clone()).await.unwrap(), .iter()
&interaction.member(&ctx).await.unwrap(), .filter(|o| o.value.is_some())
)
.await
{ {
let mut args = HashMap::new(); args.insert(
arg.name.clone(),
for arg in data.options.iter().filter(|o| o.value.is_some()) { match arg.value.clone().unwrap() {
args.insert( Value::Bool(b) => {
arg.name.clone(), if b {
match arg.value.clone().unwrap() { arg.name.clone()
Value::Bool(b) => { } else {
if b { String::new()
arg.name.clone()
} else {
String::new()
}
} }
Value::Number(n) => n.to_string(), }
Value::String(s) => s, Value::Number(n) => n.to_string(),
_ => String::new(), Value::String(s) => s,
}, _ => String::new(),
); },
} );
}
(command.fun)(&ctx, &interaction, Args { args }) (command.fun)(&ctx, &interaction, Args { args })
.await .await
.unwrap(); .unwrap();
} else if command.required_permissions == PermissionLevel::Managed { } else if command.required_permissions == PermissionLevel::Managed {
let _ = interaction let _ = interaction
.respond( .respond(
ctx.http.clone(), ctx.http.clone(),
CreateGenericResponse::new().content("You must either be an Admin or have a role specified in `?roles` to do this command") CreateGenericResponse::new().content("You must either be an Admin or have a role specified in `?roles` to do this command")
) )
.await; .await;
} else if command.required_permissions == PermissionLevel::Restricted { } else if command.required_permissions == PermissionLevel::Restricted {
let _ = interaction let _ = interaction
.respond( .respond(
ctx.http.clone(), ctx.http.clone(),
CreateGenericResponse::new() CreateGenericResponse::new().content("You must be an Admin to do this command"),
.content("You must be an Admin to do this command"), )
) .await;
.await;
}
} }
} }
} }
@ -725,9 +742,9 @@ impl Framework for RegexFramework {
ctx: &Context, ctx: &Context,
channel: &GuildChannel, channel: &GuildChannel,
) -> SerenityResult<PermissionCheck> { ) -> SerenityResult<PermissionCheck> {
let user_id = ctx.cache.current_user_id().await; let user_id = ctx.cache.current_user_id();
let channel_perms = channel.permissions_for_user(ctx, user_id).await?; let channel_perms = channel.permissions_for_user(ctx, user_id)?;
Ok( Ok(
if channel_perms.send_messages() && channel_perms.embed_links() { if channel_perms.send_messages() && channel_perms.embed_links() {
@ -754,8 +771,8 @@ impl Framework for RegexFramework {
if msg.author.bot || msg.content.is_empty() { if msg.author.bot || msg.content.is_empty() {
} }
// Guild Command // Guild Command
else if let (Some(guild), Some(Channel::Guild(channel))) = else if let (Some(guild), Ok(Channel::Guild(channel))) =
(msg.guild(&ctx).await, msg.channel(&ctx).await) (msg.guild(&ctx), msg.channel(&ctx).await)
{ {
if let Some(full_match) = self.command_matcher.captures(&msg.content) { if let Some(full_match) = self.command_matcher.captures(&msg.content) {
if check_prefix(&ctx, &guild, full_match.name("prefix")).await { if check_prefix(&ctx, &guild, full_match.name("prefix")).await {

View File

@ -110,7 +110,7 @@ async fn join_channel(
channel_id: ChannelId, channel_id: ChannelId,
) -> (Arc<Mutex<Call>>, JoinResult<()>) { ) -> (Arc<Mutex<Call>>, JoinResult<()>) {
let songbird = songbird::get(ctx).await.unwrap(); let songbird = songbird::get(ctx).await.unwrap();
let current_user = ctx.cache.current_user_id().await; let current_user = ctx.cache.current_user_id();
let current_voice_state = guild let current_voice_state = guild
.voice_states .voice_states
@ -138,9 +138,9 @@ async fn join_channel(
let _ = call.lock().await.deafen(true).await; let _ = call.lock().await.deafen(true).await;
} }
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx).await { if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
channel channel
.edit_voice_state(&ctx, ctx.cache.current_user().await, |v| v.suppress(false)) .edit_voice_state(&ctx, ctx.cache.current_user(), |v| v.suppress(false))
.await; .await;
} }