'Map items gets replaced every time node.js
I'm trying to implement cooldown to my command handler in my Discord bot, but I'm stuck.
The cooldown itself works, but when I try to use a command that is different from the one that I executed before, that cooldown gets replaced with the last one. Here's the code:
const cooldowns = new Map();
try {
const cooldown = cooldowns.get(interaction.user.id);
if (cooldown && cooldowns.get("command") == command.data.name) {
const remaining = ms(cooldown - Date.now(), {till: "second"});
return interaction.reply({ content: `Please wait until cooldown expires! Remaining: ${codeLine(remaining)}`});
}
await command.execute(client, interaction, Discord, profileData);
let startTime = Date.now() + command.cooldown;
cooldowns.set(interaction.user.id, startTime);
cooldowns.set("command", command.data.name);
setTimeout(async () => cooldowns.delete(interaction.user.id, "command"), command.cooldown);
}
catch (error) {
console.log(`The interaction error is ${error}`);
await interaction.reply({ content: "There was an error trying to execute this command. 🍐", ephemeral: true});
}
}
So for example when I use the command /hello, with a cooldown of 30 seconds, the 1st time it gets executed, and if I try to execute it again the bot responds with the cooldown saying that I can't use the command until the cooldown expires, which is correct, but if I use another command, for example /world with 0 cooldown, the command gets executed correctly, but the cooldown for the /hello command gets canceled, and it can be used again.
I'm assuming that the interaction.user.id and the "command" items get replaced with new ones, and I can't find a method to create new ones.
Solution 1:[1]
UPDATED
According to your requirement, I created a data structure like below
{
"userA": {
"/hello": startTime
"/world": startTime
},
"userB": {
"/hello": startTime
"/world": startTime
}
}
userA is for user id
/hello and /world are commands
startTime is the cooldown for each command
You can check this implementation with some comments
const cooldowns = {}; //similar to Map but simpler
try {
//cannot find any user in cooldowns map
if (!cooldowns[interaction.user.id]) {
cooldowns[interaction.user.id] = {} //create map to keep commands
}
//check if the cooldown exists in the commands
const cooldown = cooldowns[interaction.user.id][command.data.name];
if (cooldown) {
const remaining = ms(cooldown - Date.now(), {
till: "second"
});
if (remaining > 0) {
return interaction.reply({
content: `Please wait until cooldown expires! Remaining: ${codeLine(remaining)}`
});
}
}
await command.execute(client, interaction, Discord, profileData);
let startTime = Date.now() + command.cooldown;
cooldowns[interaction.user.id][command.data.name] = startTime
setTimeout(async () => delete cooldowns[interaction.user.id][command.data.name], command.cooldown);
} catch (error) {
console.log(`The interaction error is ${error}`);
await interaction.reply({
content: "There was an error trying to execute this command. ?",
ephemeral: true
});
}
OLD ANSWER
if (cooldown && cooldowns.get("command") == command.data.name) {
const remaining = ms(cooldown - Date.now(), {till: "second"});
return interaction.reply({ content: `Please wait until cooldown expires! Remaining: ${codeLine(remaining)}`});
}
I think this part is causing the problem cooldowns.get("command") == command.data.name. If your new command matches with the previous command, you check the cooldown.
BUT whenever your new command does not match with the previous one, you bypass that condition which is the system won't check the remaining time.
The possible fix should be
if (cooldown) {
const remaining = ms(cooldown - Date.now(), {till: "second"});
return interaction.reply({ content: `Please wait until cooldown expires! Remaining: ${codeLine(remaining)}`});
}
You only need to check the cooldown from the user id, and don't need to check command matching.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
