From a0b29231c898fc8e8eed76c51fbb68ade22335ee Mon Sep 17 00:00:00 2001 From: maamokun/MikanDev Date: Thu, 12 Dec 2024 22:15:42 +0900 Subject: [PATCH] feat: fully handled command and message ratelimiting, with premium --- src/commands/ping.ts | 2 +- src/handlers/command.ts | 9 +++++++++ src/handlers/ratelimit.ts | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/commands/ping.ts b/src/commands/ping.ts index 3bacd80..676c088 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -3,7 +3,7 @@ import type { CommandInteraction } from "discord.js"; export default { name: "ping", description: "Replies with Pong!", - cooldown: 0, + cooldown: 5, isPremium: false, botPermissions: [], userPermissions: [], diff --git a/src/handlers/command.ts b/src/handlers/command.ts index c6ddfd5..d49e9b7 100644 --- a/src/handlers/command.ts +++ b/src/handlers/command.ts @@ -4,6 +4,7 @@ import { type CommandInteraction, } from "discord.js"; import crypto from "node:crypto"; +import { setCommandRatelimit, checkCommandRatelimit } from "./ratelimit.ts"; import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); @@ -48,6 +49,8 @@ export async function handleCommand(interaction: CommandInteraction) { `../commands/${interaction.commandName}.ts` ); const command = commandModule.default; + const limited = await checkCommandRatelimit("cmd", interaction, command.name); + if (limited) return interaction.reply({ content: "You are being ratelimited! Please wait a bit before using this command again.", ephemeral: true }); if (!command.slashCommand.enabled) return interaction.reply("This command is not enabled!"); if (command.isPremium && !premium) @@ -55,6 +58,12 @@ export async function handleCommand(interaction: CommandInteraction) { "This command is only available for premium users!", ); if (command.slashCommand.enabled) command.interactionRun(interaction); + if (premium) { + setCommandRatelimit("cmd", interaction, command.PremiumCooldown || command.cooldown, command.name); + } + if (!premium) { + setCommandRatelimit("cmd", interaction, command.cooldown, command.name); + } } catch (error) { const logId = await sendLog(error.message); console.error(`Error while executing command: ${logId}`); diff --git a/src/handlers/ratelimit.ts b/src/handlers/ratelimit.ts index 4d63f87..2c6306d 100644 --- a/src/handlers/ratelimit.ts +++ b/src/handlers/ratelimit.ts @@ -5,6 +5,8 @@ const redis = createClient({ url: process.env.REDIS_URL, }); +await redis.connect(); + export function setMessageRatelimit(type: string, message: Message) { if (type == "msg") { redis.set( @@ -27,3 +29,26 @@ export async function checkMessageRatelimit(type: string, message: Message) { } } } + +export function setCommandRatelimit(type: string, interaction: CommandInteraction, time: number, name: string) { + if (type == "cmd") { + redis.set( + `command:${interaction.guildId}:${interaction.user.id}:${name}`, + `${interaction.guildId}`, + { EX: time }, + ); + } +} + +export async function checkCommandRatelimit(type: string, interaction: CommandInteraction, name: string) { + if (type == "cmd") { + const isLimited = await redis.get( + `command:${interaction.guildId}:${interaction.user.id}:${name}`, + ); + if (isLimited == `${interaction.guildId}`) { + return true; + } else { + return false; + } + } +}