mirror of
https://github.com/discordeno/discordeno.git
synced 2026-05-21 02:40:08 +00:00
I prefer semicolors, they also help avoiding certain pitfalls in JavaScript/TypeScript, such as the following code sample: ```js const xyz = "test" (something.else as string) = "another" ``` This results in a TypeError: "test" is not a function, this is because js thinks we are trying to call the string "test" as a function. To fix this it requires a `;` somewhere before the `(`, such as `;(something ... ` which in my opinion is ugly and less clean overall.
124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
import { join as joinPath } from 'node:path';
|
|
import type { DiscordGatewayPayload, GatewayDispatchEventNames } from '@discordeno/bot';
|
|
import { connect as connectAmqp } from 'amqplib';
|
|
import {
|
|
EVENT_HANDLER_HOST,
|
|
EVENT_HANDLER_PORT,
|
|
MESSAGEQUEUE_ENABLE,
|
|
MESSAGEQUEUE_PASSWORD,
|
|
MESSAGEQUEUE_URL,
|
|
MESSAGEQUEUE_USERNAME,
|
|
} from '../config.js';
|
|
import { getDirnameFromFileUrl } from '../util.js';
|
|
import { bot } from './bot.js';
|
|
import { buildFastifyApp } from './fastify.js';
|
|
import importDirectory from './utils/loader.js';
|
|
|
|
// The importDirectory function uses 'readdir' that requires either a relative path compared to the process CWD or an absolute one, so to get one relative we need to use import.meta.url
|
|
const currentDirectory = getDirnameFromFileUrl(import.meta.url);
|
|
|
|
await importDirectory(joinPath(currentDirectory, './commands'));
|
|
await importDirectory(joinPath(currentDirectory, './events'));
|
|
|
|
if (MESSAGEQUEUE_ENABLE) {
|
|
await connectToRabbitMQ();
|
|
}
|
|
|
|
const app = buildFastifyApp();
|
|
|
|
app.get('/timecheck', async (_req, res) => {
|
|
res.status(200).send({ message: Date.now() });
|
|
});
|
|
|
|
app.post('/', async (req, res) => {
|
|
const body = req.body as GatewayEvent;
|
|
|
|
try {
|
|
handleGatewayEvent(body.payload, body.shardId);
|
|
|
|
res.status(200).send();
|
|
} catch (error) {
|
|
bot.logger.error('There was an error handling the incoming gateway command', error);
|
|
res.status(500).send();
|
|
}
|
|
});
|
|
|
|
await app.listen({
|
|
host: EVENT_HANDLER_HOST,
|
|
port: EVENT_HANDLER_PORT,
|
|
});
|
|
|
|
bot.logger.info(`Bot event handler is listening on port ${EVENT_HANDLER_PORT}`);
|
|
|
|
async function handleGatewayEvent(payload: DiscordGatewayPayload, shardId: number): Promise<void> {
|
|
bot.events.raw?.(payload, shardId);
|
|
|
|
// If we don't have the event type we don't process it further
|
|
if (!payload.t) return;
|
|
|
|
// Run the dispatch check
|
|
await bot.events.dispatchRequirements?.(payload, shardId);
|
|
|
|
bot.handlers[payload.t as GatewayDispatchEventNames]?.(bot, payload, shardId);
|
|
}
|
|
|
|
async function connectToRabbitMQ(): Promise<void> {
|
|
const connection = await connectAmqp(`amqp://${MESSAGEQUEUE_USERNAME}:${MESSAGEQUEUE_PASSWORD}@${MESSAGEQUEUE_URL}`).catch((error) => {
|
|
bot.logger.error('Failed to connect to RabbitMQ, retrying in 1s.', error);
|
|
setTimeout(connectToRabbitMQ, 1000);
|
|
});
|
|
|
|
if (!connection) return;
|
|
|
|
connection.on('close', () => {
|
|
setTimeout(connectToRabbitMQ, 1000);
|
|
});
|
|
connection.on('error', (error) => {
|
|
bot.logger.error('There was an error in the connection with RabbitMQ, reconnecting in 1s.', error);
|
|
setTimeout(connectToRabbitMQ, 1000);
|
|
});
|
|
|
|
const channel = await connection.createChannel().catch((error) => {
|
|
bot.logger.error('There was an error creating the RabbitMQ channel', error);
|
|
});
|
|
|
|
if (!channel) return;
|
|
|
|
const exchange = await channel
|
|
.assertExchange('gatewayMessage', 'x-message-deduplication', {
|
|
durable: true,
|
|
arguments: {
|
|
'x-cache-size': 1000, // maximum number of entries
|
|
'x-cache-ttl': 500, // 500ms
|
|
},
|
|
})
|
|
.catch((error) => {
|
|
bot.logger.error('There was an error asserting the exchange', error);
|
|
});
|
|
|
|
if (!exchange) return;
|
|
|
|
await channel.assertQueue('gatewayMessageQueue').catch(bot.logger.error);
|
|
await channel.bindQueue('gatewayMessageQueue', 'gatewayMessage', '').catch(bot.logger.error);
|
|
await channel
|
|
.consume('gatewayMessageQueue', async (message) => {
|
|
if (!message) return;
|
|
|
|
try {
|
|
const messageBody = JSON.parse(message.content.toString()) as GatewayEvent;
|
|
|
|
await handleGatewayEvent(messageBody.payload, messageBody.shardId);
|
|
|
|
channel.ack(message);
|
|
} catch (error) {
|
|
bot.logger.error('There was an error handling events received from RabbitMQ', error);
|
|
}
|
|
})
|
|
.catch(bot.logger.error);
|
|
}
|
|
|
|
interface GatewayEvent {
|
|
payload: DiscordGatewayPayload;
|
|
shardId: number;
|
|
}
|