arg macro to define arguments on commands

This commit is contained in:
2021-06-11 10:10:48 +01:00
parent d5d2ac2bee
commit 1286f5f50e
7 changed files with 338 additions and 412 deletions

View File

@ -1,4 +1,5 @@
use crate::{
framework::RegexFramework,
guild_data::CtxGuildData,
join_channel, play_audio,
sound::{JoinSoundCtx, Sound},
@ -8,7 +9,9 @@ use crate::{
use serenity::{
async_trait,
client::{Context, EventHandler},
model::{channel::Channel, guild::Guild, id::GuildId, voice::VoiceState},
model::{
channel::Channel, guild::Guild, id::GuildId, interactions::Interaction, voice::VoiceState,
},
utils::shard_id,
};
@ -33,6 +36,18 @@ pub struct Handler;
#[serenity::async_trait]
impl EventHandler for Handler {
async fn cache_ready(&self, ctx: Context, _: Vec<GuildId>) {
let framework = ctx
.data
.read()
.await
.get::<RegexFramework>()
.cloned()
.expect("RegexFramework not found in context");
framework.build_slash(ctx).await;
}
async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) {
if is_new {
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
@ -154,4 +169,8 @@ SELECT name, id, plays, public, server_id, uploader_id
}
}
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
//
}
}

View File

@ -1,7 +1,8 @@
use serenity::{
async_trait,
builder::CreateEmbed,
cache::Cache,
client::Context,
constants::MESSAGE_CODE_LIMIT,
framework::{
standard::{Args, CommandResult, Delimiter},
Framework,
@ -13,7 +14,9 @@ use serenity::{
guild::{Guild, Member},
id::{ChannelId, GuildId, UserId},
interactions::Interaction,
prelude::{ApplicationCommandOptionType, InteractionResponseType},
},
prelude::TypeMapKey,
Result as SerenityResult,
};
@ -24,9 +27,6 @@ use regex::{Match, Regex, RegexBuilder};
use std::{collections::HashMap, fmt};
use crate::{guild_data::CtxGuildData, MySQL};
use serenity::builder::CreateEmbed;
use serenity::cache::Cache;
use serenity::model::prelude::InteractionResponseType;
use std::sync::Arc;
type CommandFn = for<'fut> fn(
@ -190,6 +190,15 @@ pub enum PermissionLevel {
Restricted,
}
#[derive(Debug)]
pub struct Arg {
pub name: &'static str,
pub description: &'static str,
pub kind: ApplicationCommandOptionType,
pub required: bool,
pub default: bool,
}
pub struct Command {
pub fun: CommandFn,
pub names: &'static [&'static str],
@ -198,6 +207,7 @@ pub struct Command {
pub examples: &'static [&'static str],
pub required_permissions: PermissionLevel,
pub allow_slash: bool,
pub args: &'static [&'static Arg],
}
impl Command {
@ -267,53 +277,11 @@ impl fmt::Debug for Command {
f.debug_struct("Command")
.field("name", &self.names[0])
.field("required_permissions", &self.required_permissions)
.field("args", &self.args)
.finish()
}
}
#[async_trait]
pub trait SendIterator {
async fn say_lines(
self,
http: impl AsRef<Http> + Send + Sync + 'async_trait,
content: impl Iterator<Item = String> + Send + 'async_trait,
) -> SerenityResult<()>;
}
#[async_trait]
impl SendIterator for ChannelId {
async fn say_lines(
self,
http: impl AsRef<Http> + Send + Sync + 'async_trait,
content: impl Iterator<Item = String> + Send + 'async_trait,
) -> SerenityResult<()> {
let mut current_content = String::new();
for line in content {
if current_content.len() + line.len() > MESSAGE_CODE_LIMIT as usize {
self.send_message(&http, |m| {
m.allowed_mentions(|am| am.empty_parse())
.content(&current_content)
})
.await?;
current_content = line;
} else {
current_content = format!("{}\n{}", current_content, line);
}
}
if !current_content.is_empty() {
self.send_message(&http, |m| {
m.allowed_mentions(|am| am.empty_parse())
.content(&current_content)
})
.await?;
}
Ok(())
}
}
pub struct RegexFramework {
commands: HashMap<String, &'static Command>,
command_matcher: Regex,
@ -323,6 +291,10 @@ pub struct RegexFramework {
case_insensitive: bool,
}
impl TypeMapKey for RegexFramework {
type Value = Arc<RegexFramework>;
}
impl RegexFramework {
pub fn new<T: Into<u64>>(client_id: T) -> Self {
Self {
@ -354,6 +326,8 @@ impl RegexFramework {
}
pub fn add_command(mut self, command: &'static Command) -> Self {
info!("{:?}", command);
for name in command.names {
self.commands.insert(name.to_string(), command);
}
@ -388,6 +362,10 @@ impl RegexFramework {
self
}
pub async fn build_slash(&self, http: impl AsRef<Http>) {
//
}
}
enum PermissionCheck {

View File

@ -215,6 +215,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
framework = framework.build();
let framework_arc = Arc::new(framework);
let mut client =
Client::builder(&env::var("DISCORD_TOKEN").expect("Missing token from environment"))
.intents(
@ -222,7 +224,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
| GatewayIntents::GUILD_MESSAGES
| GatewayIntents::GUILDS,
)
.framework(framework)
.framework_arc(framework_arc.clone())
.application_id(application_id.0)
.event_handler(Handler)
.register_songbird()
@ -242,7 +244,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
data.insert::<GuildDataCache>(guild_data_cache);
data.insert::<JoinSoundCache>(join_sound_cache);
data.insert::<MySQL>(mysql_pool);
data.insert::<RegexFramework>(framework_arc.clone());
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
if let Some(audio_index) = audio_index {
@ -425,6 +427,20 @@ Please select a category from the following:
#[command]
#[aliases("p")]
#[required_permissions(Managed)]
#[arg(
name = "query",
description = "Play sound with the specified name or ID",
kind = "String",
required = true,
default = true
)]
#[arg(
name = "loop",
description = "Whether to loop the sound or not (default: no)",
kind = "Boolean",
required = false,
default = false
)]
async fn play(
ctx: &Context,
invoke: &(dyn CommandInvoke + Sync + Send),
@ -443,8 +459,14 @@ async fn play(
Ok(())
}
#[command]
#[command("loop")]
#[required_permissions(Managed)]
#[arg(
name = "query",
description = "Play sound with the specified name or ID",
kind = "String",
required = true
)]
async fn loop_play(
ctx: &Context,
invoke: &(dyn CommandInvoke + Sync + Send),
@ -524,6 +546,12 @@ async fn play_cmd(ctx: &Context, guild: Guild, user_id: UserId, args: Args, loop
#[command("ambience")]
#[required_permissions(Managed)]
#[arg(
name = "name",
description = "Play sound with the specified name",
kind = "String",
required = false
)]
async fn play_ambience(
ctx: &Context,
invoke: &(dyn CommandInvoke + Sync + Send),
@ -687,6 +715,7 @@ There is a maximum sound limit per user. This can be removed by subscribing at *
}
#[command("volume")]
#[aliases("vol")]
#[required_permissions(Managed)]
async fn change_volume(
ctx: &Context,
@ -753,6 +782,7 @@ async fn change_volume(
#[command("prefix")]
#[required_permissions(Restricted)]
#[allow_slash(false)]
async fn change_prefix(
ctx: &Context,
invoke: &(dyn CommandInvoke + Sync + Send),
@ -1057,6 +1087,12 @@ INSERT INTO roles (guild_id, role)
}
#[command("list")]
#[arg(
name = "me",
description = "Whether to list your sounds or server sounds (default: server)",
kind = "Boolean",
required = false
)]
async fn list_sounds(
ctx: &Context,
invoke: &(dyn CommandInvoke + Sync + Send),