Merge pull request #660 from ZynerOrg/dev
Improvements and new cooldown feature
This commit is contained in:
commit
ec05cd75ec
15 changed files with 72 additions and 63 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "xyter",
|
"name": "xyter",
|
||||||
"version": "2.2.1",
|
"version": "2.3.0-dev.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "xyter",
|
"name": "xyter",
|
||||||
"version": "2.2.1",
|
"version": "2.3.0-dev.1",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.7.1",
|
"@prisma/client": "^4.7.1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "xyter",
|
"name": "xyter",
|
||||||
"version": "2.2.1",
|
"version": "2.3.0-dev.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "A multi purpose Discord bot written in TypeScript with Discord.js",
|
"description": "A multi purpose Discord bot written in TypeScript with Discord.js",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addDays, startOfDay } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -60,12 +61,10 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
|
|
||||||
await sendResponse(interaction, { embeds: [embed] });
|
await sendResponse(interaction, { embeds: [embed] });
|
||||||
|
|
||||||
const cooldownDuration = 24 * 60 * 60; // 24 hours in seconds
|
|
||||||
const cooldownName = await generateCooldownName(interaction);
|
|
||||||
await cooldownManager.setCooldown(
|
await cooldownManager.setCooldown(
|
||||||
cooldownName,
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
cooldownDuration
|
startOfDay(addDays(new Date(), 1))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addMonths, startOfDay } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -66,12 +67,10 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
|
|
||||||
await sendResponse(interaction, { embeds: [embed] });
|
await sendResponse(interaction, { embeds: [embed] });
|
||||||
|
|
||||||
const cooldownDuration = 4 * 7 * 24 * 60 * 60; // 1 month in seconds
|
|
||||||
const cooldownName = await generateCooldownName(interaction);
|
|
||||||
await cooldownManager.setCooldown(
|
await cooldownManager.setCooldown(
|
||||||
cooldownName,
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
cooldownDuration
|
startOfDay(addMonths(new Date(), 1))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addWeeks, startOfDay } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -62,12 +63,10 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
|
|
||||||
await sendResponse(interaction, { embeds: [embed] });
|
await sendResponse(interaction, { embeds: [embed] });
|
||||||
|
|
||||||
const cooldownDuration = 7 * 24 * 60 * 60; // 1 week in seconds
|
|
||||||
const cooldownName = await generateCooldownName(interaction);
|
|
||||||
await cooldownManager.setCooldown(
|
await cooldownManager.setCooldown(
|
||||||
cooldownName,
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
cooldownDuration
|
startOfDay(addWeeks(new Date(), 1))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Chance from "chance";
|
import Chance from "chance";
|
||||||
|
import { addHours } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -132,6 +133,6 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
await generateCooldownName(interaction),
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
86400
|
addHours(new Date(), 1)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { addSeconds } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -70,14 +71,11 @@ export const execute = async (
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const cooldownName = await generateCooldownName(interaction);
|
|
||||||
const cooldownDuration = 5;
|
|
||||||
|
|
||||||
await cooldownManager.setCooldown(
|
await cooldownManager.setCooldown(
|
||||||
cooldownName,
|
await generateCooldownName(interaction),
|
||||||
guild || null,
|
guild || null,
|
||||||
user,
|
user,
|
||||||
cooldownDuration
|
addSeconds(new Date(), 5)
|
||||||
);
|
);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if ((error as NodeJS.ErrnoException).code === "ENOTFOUND") {
|
if ((error as NodeJS.ErrnoException).code === "ENOTFOUND") {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { addSeconds } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ActionRowBuilder,
|
ActionRowBuilder,
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
|
@ -39,8 +40,6 @@ export const execute = async (
|
||||||
await deferReply(interaction, false);
|
await deferReply(interaction, false);
|
||||||
|
|
||||||
const { channel, guild, user } = interaction;
|
const { channel, guild, user } = interaction;
|
||||||
const cooldownItem = await generateCooldownName(interaction);
|
|
||||||
const cooldownDuration = 15; // 10 seconds
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content: MemeContent = await fetchRandomMeme();
|
const content: MemeContent = await fetchRandomMeme();
|
||||||
|
@ -65,10 +64,10 @@ export const execute = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
await cooldownManager.setCooldown(
|
await cooldownManager.setCooldown(
|
||||||
cooldownItem,
|
await generateCooldownName(interaction),
|
||||||
guild || null,
|
guild || null,
|
||||||
user,
|
user,
|
||||||
cooldownDuration
|
addSeconds(new Date(), 5)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addMinutes } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChannelType,
|
ChannelType,
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
|
@ -99,6 +100,6 @@ export const execute = async (
|
||||||
await generateCooldownName(interaction),
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
5 * 60
|
addMinutes(new Date(), 5)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addDays } from "date-fns";
|
||||||
import {
|
import {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
|
@ -82,6 +83,6 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
await generateCooldownName(interaction),
|
await generateCooldownName(interaction),
|
||||||
guild,
|
guild,
|
||||||
user,
|
user,
|
||||||
24 * 60 * 60
|
addDays(new Date(), 1)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,9 @@ import generateCooldownName from "../../../../helpers/generateCooldownName";
|
||||||
import handleCooldown from "./handlers/handleCooldown";
|
import handleCooldown from "./handlers/handleCooldown";
|
||||||
import handleUnavailableCommand from "./handlers/handleUnavailableCommand";
|
import handleUnavailableCommand from "./handlers/handleUnavailableCommand";
|
||||||
|
|
||||||
|
// Create a map to store locks for each identifier (guild ID + user ID + cooldown item)
|
||||||
|
const commandLocks = new Map();
|
||||||
|
|
||||||
const cooldownManager = new CooldownManager();
|
const cooldownManager = new CooldownManager();
|
||||||
|
|
||||||
export default async function handleCommandInteraction(
|
export default async function handleCommandInteraction(
|
||||||
|
@ -24,6 +27,14 @@ export default async function handleCommandInteraction(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cooldownItem = await generateCooldownName(interaction);
|
const cooldownItem = await generateCooldownName(interaction);
|
||||||
|
|
||||||
|
// Check if the identifier is already locked
|
||||||
|
if (commandLocks.has(cooldownItem)) {
|
||||||
|
throw new Error(
|
||||||
|
"You are unable to execute the same command simultaneously."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const { guildCooldown, userCooldown, guildMemberCooldown } =
|
const { guildCooldown, userCooldown, guildMemberCooldown } =
|
||||||
await cooldownManager.checkCooldowns(cooldownItem, guild, user);
|
await cooldownManager.checkCooldowns(cooldownItem, guild, user);
|
||||||
|
|
||||||
|
@ -38,10 +49,23 @@ export default async function handleCommandInteraction(
|
||||||
userCooldown,
|
userCooldown,
|
||||||
guildMemberCooldown
|
guildMemberCooldown
|
||||||
);
|
);
|
||||||
} else {
|
return;
|
||||||
await currentCommand.execute(interaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a promise that represents the current command execution
|
||||||
|
const commandExecutionPromise = currentCommand.execute(interaction);
|
||||||
|
|
||||||
|
// Acquire the lock for the identifier and store the command execution promise
|
||||||
|
commandLocks.set(cooldownItem, commandExecutionPromise);
|
||||||
|
|
||||||
|
// Wait for the current command execution to complete
|
||||||
|
await commandExecutionPromise;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await interactionErrorHandler(interaction, error);
|
await interactionErrorHandler(interaction, error);
|
||||||
|
} finally {
|
||||||
|
const cooldownItem = await generateCooldownName(interaction);
|
||||||
|
|
||||||
|
// Release the lock for the identifier
|
||||||
|
commandLocks.delete(cooldownItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { addSeconds } from "date-fns";
|
||||||
import { Channel, ChannelType, Guild, Message, User } from "discord.js";
|
import { Channel, ChannelType, Guild, Message, User } from "discord.js";
|
||||||
import CooldownManager from "../../../handlers/CooldownManager";
|
import CooldownManager from "../../../handlers/CooldownManager";
|
||||||
import CreditsManager from "../../../handlers/CreditsManager";
|
import CreditsManager from "../../../handlers/CreditsManager";
|
||||||
|
@ -93,5 +94,10 @@ async function isUserOnCooldown(guild: Guild, author: User): Promise<boolean> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setCooldown(guild: Guild, user: User) {
|
async function setCooldown(guild: Guild, user: User) {
|
||||||
await cooldownManager.setCooldown(cooldownName, guild, user, 5);
|
await cooldownManager.setCooldown(
|
||||||
|
cooldownName,
|
||||||
|
guild,
|
||||||
|
user,
|
||||||
|
addSeconds(new Date(), 5)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ class CooldownManager {
|
||||||
cooldownItem: string,
|
cooldownItem: string,
|
||||||
guild: Guild | null,
|
guild: Guild | null,
|
||||||
user: User | null,
|
user: User | null,
|
||||||
cooldownSeconds: number
|
expiresAt: Date
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const expiresAt = new Date(Date.now() + cooldownSeconds * 1000);
|
|
||||||
const data = {
|
const data = {
|
||||||
cooldownItem,
|
cooldownItem,
|
||||||
expiresAt,
|
expiresAt,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { UserReputation } from "@prisma/client";
|
||||||
import { User } from "discord.js";
|
import { User } from "discord.js";
|
||||||
import prisma from "./prisma";
|
import prisma from "./prisma";
|
||||||
|
|
||||||
|
@ -38,42 +39,30 @@ class ReputationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async repute(user: User, type: "positive" | "negative") {
|
async repute(user: User, type: "positive" | "negative") {
|
||||||
const userData = await prisma.user.upsert({
|
let userReputation: UserReputation | null = null;
|
||||||
where: { id: user.id },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
id: user.id,
|
|
||||||
userReputation: {
|
|
||||||
create: {
|
|
||||||
positive: 0,
|
|
||||||
negative: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
userReputation: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let userReputation: any = {};
|
|
||||||
|
|
||||||
if (!userData.userReputation) return null;
|
|
||||||
|
|
||||||
if (type === "positive") {
|
if (type === "positive") {
|
||||||
userReputation = await prisma.userReputation.upsert({
|
userReputation = await prisma.userReputation.upsert({
|
||||||
where: { id: userData.userReputation.id },
|
where: { id: user.id },
|
||||||
update: { positive: { increment: 1 } },
|
update: { positive: { increment: 1 } },
|
||||||
create: {
|
create: {
|
||||||
positive: 1,
|
positive: 1,
|
||||||
negative: 0,
|
negative: 0,
|
||||||
user: { connect: { id: user.id } },
|
user: {
|
||||||
|
connectOrCreate: {
|
||||||
|
where: {
|
||||||
|
id: user.id,
|
||||||
|
},
|
||||||
|
create: { id: user.id },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "negative") {
|
if (type === "negative") {
|
||||||
userReputation = await prisma.userReputation.upsert({
|
userReputation = await prisma.userReputation.upsert({
|
||||||
where: { id: userData.userReputation.id },
|
where: { id: user.id },
|
||||||
update: { negative: { increment: 1 } },
|
update: { negative: { increment: 1 } },
|
||||||
create: {
|
create: {
|
||||||
positive: 0,
|
positive: 0,
|
||||||
|
|
|
@ -25,18 +25,12 @@ export default async (
|
||||||
const errorEmbed = new EmbedBuilder()
|
const errorEmbed = new EmbedBuilder()
|
||||||
.setAuthor({ name: "⚠️ | Request Failed" })
|
.setAuthor({ name: "⚠️ | Request Failed" })
|
||||||
.setDescription(
|
.setDescription(
|
||||||
"An error occurred while processing your request. Please try again later."
|
error.message ??
|
||||||
|
"An error occurred while processing your request. Please try again later."
|
||||||
)
|
)
|
||||||
.setColor("#FFCC66")
|
.setColor("#FFCC66")
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
if (error.message !== undefined) {
|
|
||||||
errorEmbed.addFields({
|
|
||||||
name: "Error Message",
|
|
||||||
value: codeBlock(error.message),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development" && error.stack !== undefined) {
|
if (process.env.NODE_ENV === "development" && error.stack !== undefined) {
|
||||||
errorEmbed.addFields({
|
errorEmbed.addFields({
|
||||||
name: "Error Stack",
|
name: "Error Stack",
|
||||||
|
|
Loading…
Add table
Reference in a new issue