Skip to content

Commit

Permalink
Updating the bot, optimized a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
TheDogHusky committed Sep 11, 2024
1 parent b8719e4 commit 3a71cd1
Show file tree
Hide file tree
Showing 9 changed files with 628 additions and 87 deletions.
591 changes: 578 additions & 13 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"version": "0.0.1",
"description": "Official NekoNya Discord Bot",
"main": "lib/index.js",
"type": "commonjs",
"scripts": {
"test": "npx tsc",
"start": "npx tsc && node lib/index.js"
"start": "cross-env NODE_ENV=production npx tsc && node lib/index.js",
"dev": "cross-env NODE_ENV=development tsx watch src/index"
},
"repository": {
"type": "git",
Expand All @@ -26,13 +27,15 @@
"homepage": "https://github.com/NekoNyaDevs/bot#readme",
"dependencies": {
"@classycrafter/super-logger": "^2.0.0",
"axios": "^1.4.0",
"axios": "^1.7.7",
"cross-env": "^7.0.3",
"discord.js": "^14.13.0",
"dotenv": "^16.3.1",
"mongoose": "^7.4.3",
"ms": "^2.1.3",
"nekonya.js": "^1.1.7",
"pterodactyl.js": "^2.1.1"
"nekonya.js": "^1.1.8",
"pterodactyl.js": "^2.1.1",
"tsx": "^4.19.0"
},
"devDependencies": {
"@types/mongoose": "^5.11.97",
Expand Down
5 changes: 2 additions & 3 deletions src/commands/admin/restart.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Command from '../../struct/command';
import Client from '../../struct/client';
import { ChatInputCommandInteraction, Collection } from 'discord.js';
import { ChatInputCommandInteraction } from 'discord.js';
import { IGuild } from '../../struct/typings';
import { slashsync } from '../../struct/functions';

export default class RestartCommand extends Command {
constructor(client: Client) {
Expand All @@ -29,7 +28,7 @@ export default class RestartCommand extends Command {
await ctx.editReply({
content: client.makeReply('Restarted, reloading commands...', 'success')
});
await slashsync(client, { debug: client.config.debug });
await client.synchronizeCommands();
console.log(client.commands.get('hello')?.run.toString())
await ctx.editReply({
content: client.makeReply('Reloaded commands, successfully restarted!', 'success')
Expand Down
7 changes: 3 additions & 4 deletions src/commands/utils/infos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Command from '../../struct/command';
import Client from '../../struct/client';
import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js';
import { IGuild } from '../../struct/typings';
import { version, latest } from 'nekonya.js';
import { version } from 'nekonya.js';
import { getAPIStatus, formatUptime } from '../../struct/functions';

export default class InfosCommand extends Command {
Expand Down Expand Up @@ -32,13 +32,12 @@ export default class InfosCommand extends Command {
const commands = client.commands.size;
const uptime = formatUptime(client.uptime || 0);
const apiVersion = version;
const apiLatest = latest;
const apiStatus = (await getAPIStatus(apiVersion)).statusString;

const embed = new EmbedBuilder()
.setTitle(`${client.config.emotes.info}・Informations`)
.setColor(client.config.colors.main)
.setDescription(`> Get some informations about the Bot!`)
.setDescription(`> Hey there! I'm NekoNyan, a cute Discord bot made by NekoNyaDevs for the NekoNya project.\n> Here are some informations about me:`)
.setTimestamp()
.setAuthor({ name: ctx.user.tag, iconURL: ctx.user.displayAvatarURL({ size: 1024, extension: 'webp' }) })
.setFooter({ text: `Requested by ${ctx.user.tag}`, iconURL: client.user?.displayAvatarURL({ size: 1024, extension: 'webp' }) })
Expand Down Expand Up @@ -85,7 +84,7 @@ export default class InfosCommand extends Command {
},
{
name: `${client.config.emotes.api}・API`,
value: `> **Status**: \`${apiStatus}\`\n> **Version**: \`${apiVersion}\`\n> **Latest**: \`${apiLatest}\``,
value: `> **Status**: \`${apiStatus}\`\n> **Version**: \`${apiVersion}\`\n> **Latency**: \`${(await getAPIStatus(apiVersion)).latency}ms\``,
inline: true
}
]);
Expand Down
4 changes: 2 additions & 2 deletions src/events/ready.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Event from '../struct/event';
import Client from '../struct/client';
import { ActivityType } from 'discord.js';
import { slashsync, wait } from '../struct/functions';
import { wait } from '../struct/functions';

export default class ReadyEvent extends Event {
public constructor(client: Client) {
Expand All @@ -18,7 +18,7 @@ export default class ReadyEvent extends Event {

await wait('3s');

await slashsync(client, { debug: client.config.debug });
await client.synchronizeCommands();
return;
};
};
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ if (!existsSync('logs')) {
}

const client = new Client();
client.start();
client.start().catch((error) => {
client.logger.fatal(error.stack, 'Client');
});

if (process.env.NODE_ENV === 'development') {
process.on('unhandledRejection', (reason, promise) => {
Expand Down
25 changes: 25 additions & 0 deletions src/struct/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Database from './database';
import { Logger } from '@classycrafter/super-logger';
import * as conf from '../config';
import Ptero from './ptero';
import {getAPIStatus, wait} from './functions';

config();

Expand Down Expand Up @@ -37,13 +38,21 @@ export default class Bot extends Client {
};

private async _init(): Promise<void> {
const results = await getAPIStatus("v1");
if (results.status !== 200) {
this.logger.fatal(`API is down!`, 'API');
} else {
this.logger.info(`API is up!`, 'API');
}

await this.database.connect();

await this.loadCommands();
await this.loadEvents();
};

public async start(): Promise<void> {
this.logger.info(`Starting ${process.env.npm_package_name} on ${process.env.NODE_ENV} mode...`, 'Startup');
await this._init();
await this.login(process.env.TOKEN);
};
Expand Down Expand Up @@ -91,4 +100,20 @@ export default class Bot extends Client {
// @ts-ignore
return `${this.config.emotes[type]}${content}`;
}

async synchronizeCommands(): Promise<void> {
const commands = this.commands.map((command) => command.getPostableData());
const devGuild = await this.guilds.fetch(this.config.devGuildId);
if (process.env.NODE_ENV === 'development') {
await this.application?.commands.set([]);
await devGuild.commands.set(commands);
return;
} else {
await devGuild.commands.set([]);
}
await this.application?.commands.set(commands);
await wait('5s'); // wait to ensure the commands are set
this.logger.info(`Commands have been synchronized!`, 'Commands');
return;
}
};
65 changes: 6 additions & 59 deletions src/struct/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,6 @@ import { SlashSyncOptions, APIStatusAnswer } from './typings';
import ms from 'ms';
import axios from 'axios';

export async function slashsync(client: Client, options: SlashSyncOptions = {
debug: false,
guildId: undefined
}) {
const log = (message: string) => {
return options.debug && client.logger.debug(message, "SlashSync");
};

const ready = client.readyAt ? Promise.resolve() : new Promise(resolve => client.once('ready', resolve));
await ready;
const currentCommands = await client.application?.commands?.fetch({ guildId: options.guildId }) ?? new Discord.Collection();

log(`Synchronizing commands...`);
log(`${currentCommands.size} commands are actually posted.`);

const newCommands = client.commands.filter((command) => !currentCommands.some((c) => c.name === command.name));
for (let newCommand of newCommands.values()) {
const postableData = newCommand.getPostableData();
await client.application?.commands?.create(postableData, options.guildId);
}

log(`${newCommands.size} commands ${newCommands.size > 1 ? 'have' : 'has'} been created.`);

const deletedCommands = currentCommands.filter((command) => !client.commands.some((c) => c.name === command.name)).toJSON();
for (let deletedCommand of deletedCommands) {
await deletedCommand.delete().catch(err => {
log(`Unable to delete command ${deletedCommand.name}. (InternalErr)`);
});
}

log(`${deletedCommands.length} ${deletedCommands.length > 1 ? 'have' : 'has'} been deleted.`);

const updatedCommands = client.commands.filter((command) => currentCommands.some((c) => c.name === command.name));
let updatedCommandCount = 0;
for (let updatedCommand of updatedCommands.values()) {
const newCommand = updatedCommand;
const previousCommand = currentCommands.find((c) => c.name === newCommand.name);
let modified = false;
if (previousCommand?.description !== newCommand.description) modified = true;
if (!Discord.ApplicationCommand.optionsEqual(previousCommand?.options ?? [], newCommand.getPostableData().options ?? [])) modified = true;
if (modified) {
await previousCommand?.edit(newCommand);
updatedCommandCount++;
}
}

log(`${updatedCommandCount} ${updatedCommandCount > 1 ? 'have' : 'has'} been updated.`);
log(`Successfully synchronized commands!`);

return {
currentCommandCount: currentCommands.size,
newCommandCount: newCommands.size,
deletedCommandCount: deletedCommands.length,
updatedCommandCount
};
}

export function wait(time: number | string): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, typeof time === 'string' ? ms(time) : time);
Expand All @@ -75,7 +18,8 @@ export function formatUptime(ms: number): string {
return `${days}d ${hours}h ${minutes}m ${seconds}s`;
}

export async function getAPIStatus(version: string): Promise<APIStatusAnswer> {
export async function getAPIStatus(version: string = "v1"): Promise<APIStatusAnswer> {
const beforeRequest = Date.now();
const res = await axios.get(`https://nekonya.classydev.fr/api/${version}`).catch(() => {
return {
data: {
Expand All @@ -84,6 +28,8 @@ export async function getAPIStatus(version: string): Promise<APIStatusAnswer> {
}
};
});
const afterRequest = Date.now();
const latency = afterRequest - beforeRequest;
let statusString;
switch(res.data.status) {
case 200:
Expand All @@ -106,6 +52,7 @@ export async function getAPIStatus(version: string): Promise<APIStatusAnswer> {
return {
status: res.data.status,
version: res.data.version,
statusString: statusString
statusString: statusString,
latency: latency
};
}
1 change: 1 addition & 0 deletions src/struct/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ export interface APIStatusAnswer {
status: number;
version: string;
statusString: string;
latency: number;
}

0 comments on commit 3a71cd1

Please sign in to comment.