Port a commands and utils modules from getting-started

This commit is contained in:
Eryn Wells 2022-11-12 10:29:21 -08:00
parent 50febb14bd
commit 494576d19c
3 changed files with 105 additions and 1 deletions

14
app.js
View file

@ -1,5 +1,10 @@
import 'dotenv/config';
import express from 'express';
import { verifyDiscordRequest } from './utils.js';
import {
TEST_COMMAND,
hasGuildCommands,
} from './commands.js';
// Create an express app
const app = express();
@ -8,8 +13,15 @@ const app = express();
const PORT = process.env.PORT || 3000;
// Parse request body and verifies incoming requests using discord-interactions package
app.use(express.json({ verify: VerifyDiscordRequest(process.env.PUBLIC_KEY) }));
app.use(express.json({
verify: verifyDiscordRequest(process.env.PUBLIC_KEY)
}));
app.listen(PORT, () => {
console.log('Listening on port', PORT);
// Check if guild commands from commands.js are installed (if not, install them)
hasGuildCommands(process.env.APP_ID, process.env.GUILD_ID, [
TEST_COMMAND,
]);
});

47
commands.js Normal file
View file

@ -0,0 +1,47 @@
import { discordRequest } from './utils.js';
export const TEST_COMMAND = {
name: 'test',
description: 'Basic guild command',
type: 1,
};
export async function hasGuildCommands(appId, guildId, commands) {
if (guildId === '' || appId === '') {
return;
}
commands.forEach((c) => hasGuildCommand(appId, guildId, c));
}
async function hasGuildCommand(appId, guildId, command) {
const endpoint = `applications/${appId}/guilds/${guildId}/commands`;
try {
const res = await discordRequest(endpoint, { method: 'GET' });
const data = await res.json();
if (data) {
const installedNames = data.map((c) => c['name']);
// This is just matching on the name, so it's not good for updates
if (!installedNames.includes(command['name'])) {
console.log(`Installing "${command['name']}"`);
installGuildCommand(appId, guildId, command);
} else {
console.log(`"${command['name']}" command already installed`);
}
}
} catch (err) {
console.error(err);
}
}
export async function installGuildCommand(appId, guildId, command) {
const endpoint = `applications/${appId}/guilds/${guildId}/commands`;
try {
await discordRequest(endpoint, { method: 'POST', body: command });
} catch (err) {
console.error(err);
}
}

45
utils.js Normal file
View file

@ -0,0 +1,45 @@
import 'dotenv/config';
import fetch from 'node-fetch';
import { verifyKey } from 'discord-interactions';
const baseURL = 'https://discord.com/api/v10/';
export function verifyDiscordRequest(clientKey) {
return function (req, res, buf, encoding) {
const signature = req.get('X-Signature-Ed25519');
const timestamp = req.get('X-Signature-Timestamp');
const isValidRequest = verifyKey(buf, signature, timestamp, clientKey);
if (!isValidRequest) {
res.status(401).send('Bad request signature');
throw new Error('Bad request signature');
}
};
}
export async function discordRequest(endpoint, options) {
const url = baseURL + endpoint;
if (options.body) {
options.body = JSON.stringify(options.body);
}
// Use node-fetch to make requests
const res = await fetch(url, {
headers: {
'Authorization': `Bot ${process.env.DISCORD_TOKEN}`,
'Content-Type': 'application/json; charset=UTF-8',
'User-Agent': 'DiscordBot (https://github.com/erynofwales/thirteenth-friend, 1.0.0)',
},
...options
});
if (!res.ok) {
const data = await res.json();
console.error('Request failed with status:', res.status);
throw new Error(JSON.stringify(data));
}
return res;
}