spiffbot/src/commands.rs
2025-03-23 13:53:22 -03:00

211 lines
5.7 KiB
Rust

use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::LazyLock;
use std::sync::RwLock;
use std::time::Duration;
use serenity::all::Context;
use serenity::all::GuildId;
use serenity::all::Message;
use serenity::all::Permissions;
use crate::arguments::ArgumentStorage;
use crate::constants::CAT_HID;
pub static COMMANDS: LazyLock<RwLock<HashMap<String, BotCommand>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
#[derive(Debug)]
pub enum CommandFnKind {
Lua(()),
Rust(fn(Context, Message, Option<GuildId>)),
}
#[derive(Debug)]
pub struct BotCommand {
pub run_dm_command: Option<CommandFnKind>,
pub run_guild_command: Option<CommandFnKind>,
pub aliases: Vec<String>,
pub pretty_name: Option<String>,
pub name: String,
pub command_category: Option<String>,
pub help: Option<String>,
// pub usage: String, // will be calculated from arguments automatically
pub timeout: Option<Duration>, // TODO make this dynamic?
pub hidden: bool,
pub arguments: ArgumentStorage,
pub required_caller_discord_permissions: serenity::all::Permissions,
#[cfg(feature = "nsfw_features")]
pub is_nsfw: bool,
#[cfg(feature = "premium_features")]
pub premium_kind: usize,
}
impl BotCommand {
pub fn new(name: String) -> Self {
Self {
run_dm_command: None,
run_guild_command: None,
aliases: vec![],
pretty_name: None,
name,
hidden: false,
command_category: None,
help: None,
timeout: None,
arguments: ArgumentStorage::new(),
required_caller_discord_permissions: Permissions::empty(),
#[cfg(feature = "nsfw_features")]
is_nsfw: false,
#[cfg(feature = "premium_features")]
premium_kind: 0,
}
}
pub fn dm_command(mut self, dm_command: CommandFnKind) -> Self {
self.run_dm_command = Some(dm_command);
self
}
pub fn guild_command(mut self, guild_command: CommandFnKind) -> Self {
self.run_guild_command = Some(guild_command);
self
}
pub fn pretty_name(mut self, pretty_name: String) -> Self {
self.pretty_name = Some(pretty_name);
self
}
// pub fn name(mut self, name: String) -> Self {
// self.name = name;
// self
// }
pub fn alias(mut self, alias: String) -> Self {
self.aliases.push(alias);
self
}
pub fn aliases(mut self, aliases: &mut Vec<String>) -> Self {
self.aliases.append(aliases);
self
}
pub fn category(mut self, category: String) -> Self {
self.command_category = Some(category);
self
}
pub fn help(mut self, help: String) -> Self {
self.help = Some(help);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
// pub fn argument(mut self, argument: Argument) -> Self {
// self.arguments.add(argument);
// self
// }
pub fn hidden(mut self, hidden: bool) -> Self {
self.hidden = hidden;
self
}
}
unsafe impl Sync for BotCommand {}
unsafe impl Send for BotCommand {}
//impl Debug for BotCommand {
// fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// let mut binding = f.debug_struct("Command");
// binding
// .field(
// "run_dm_command",
// &::std::any::type_name_of_val(&self.run_dm_command),
// )
// .field(
// "run_guild_command",
// &::std::any::type_name_of_val(&self.run_guild_command),
// )
// .field("aliases", &self.aliases)
// .field("name", &self.name)
// .field("pretty_name", &self.pretty_name)
// .field("command_type", &self.command_category)
// .field("help", &self.help)
// .field("hidden", &self.hidden)
// // .field("usage", &self.usage)
// .field("timeout", &self.timeout)
// .field("arguments", &self.arguments)
// .field("permissions", &self.required_caller_discord_permissions);
// #[cfg(feature = "nsfw_features")]
// binding.field("is_nsfw", &self.is_nsfw);
// #[cfg(feature = "premium_features")]
// binding.field("premium_kind", &self.premium_kind);
// binding.finish()
// }
//}
// impl Default for Command {
// fn default() -> Self {
// }
// }
/// The last set of commands, these are used by the hoster of the engine.
pub fn insert_lua(_lua: &mlua::Lua) {
// commands.insert(
// "stop".to_owned(),
// Command::new("stop".to_owned())
// .alias("svs".to_owned())
// .category(CAT_HID.to_owned())
// .hidden(true)
// .dm_command(CommandFnKind::Rust(stop_command))
// .guild_command(CommandFnKind::Rust(stop_command))
// .pretty_name("Stop the bot".to_owned())
// .help("Stops the bot. Does nothing unless you are a developer.".to_owned()),
// );
}
/// Cannot use any command names of stock commands, but gets to pick before lua commands are loaded.
pub fn insert_rust() {
// COMMANDS.blocking_write().insert(
// "stop2".to_owned(),
// BotCommand::new("stop".to_owned())
// .alias("svs".to_owned())
// .category(CAT_HID.to_owned())
// .hidden(true)
// .dm_command(CommandFnKind::Rust(stop_command))
// .guild_command(CommandFnKind::Rust(stop_command))
// .pretty_name("Stop the bot".to_owned())
// .help("Stops the bot. Does nothing unless you are a developer.".to_owned()),
// );
}
/// Will never fail, gets first pick of command names and properties. It is up to the maintainer to make damn sure this works.
pub fn insert_stock() {
let shutdown_command = |_, msg: Message, _| {
// hardcode my id for now
if crate::databases::get_db().is_dev(msg.author.id) {
return;
}
crate::shutdown_handler();
};
// TODO fix this unwrap
COMMANDS.write().unwrap().insert(
"stop".to_owned(),
BotCommand::new("stop".to_owned())
.alias("svs".to_owned())
.category(CAT_HID.to_owned())
.hidden(true)
.dm_command(CommandFnKind::Rust(shutdown_command))
.guild_command(CommandFnKind::Rust(shutdown_command))
.pretty_name("Stop the bot".to_owned())
.help("Stops the bot. Does nothing unless you are a developer.".to_owned()),
);
}