Files
discordeno/examples/bigbot/src/bot/index.ts
Fleny 27c261fee2 formatter: Use semicolons (#4686)
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.
2026-01-17 21:54:15 +01:00

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;
}