-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds the barebone code necessary to get a Discord bot running #1
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# How to setup a discord bot to start your satisfactory server remotely | ||
|
||
# Requirements | ||
|
||
You will need: | ||
|
||
* A discord account | ||
* A discord server that you manage (meaning you can add apps and bots to it) | ||
* A machine with internet access (or whatever access needed to start your satisfactory server remotely) where your bot will be running | ||
* NodeJS 16.6+ installed on that machine | ||
|
||
# Stage 1 : Setup the discord app and the code | ||
|
||
* Copy the code contained in this folder on your machine and install it by running `npm install` | ||
* Get yourself a discord application with a bot and add the bot to your Discord server. I suggest you follow the very good instructions here: https://discordjs.guide/preparations/setting-up-a-bot-application.html | ||
* Copy the important information (Bot Token, App Client Id and GuildId) in the `config.json` file | ||
* Create your custom code to start your Satisfactory server in the `commands/ficsit.js` file (You will need to modify this file so it calls Lambda or any other service you wish to use to start your bot) | ||
|
||
# Stage 2 : Deploy your code | ||
|
||
* From the machine where your bot will run, deploy your commands with `node deploy-commands.js` (This registers the commands with your bot application so they can be used). This need to be done everytime you add a new command | ||
* From the machine where your bot will run, start your bot with `node index.js` (This will login the bot in your server and he will be available to respond to commands and NEED to be running for your bot to stay online) | ||
* Test out your commands : `/ping`, `/user` and `/server` are example commands included to test that your bot work with the most basic of commands. | ||
* The `/ficsit` command is to be used to start your Satisfactory server. | ||
|
||
# Optional : If you want to run your bot as a linux service | ||
* Modify the `discord-bot.service` with your appropriate PATHS, USER and GROUP and copy it to `/etc/systemd/system/discord-bot.service` | ||
* Add `#!/usr/bin/env node` as the very first line of the `index.js` file | ||
* Make the `index.js` file executable by running `chmod +x index.js` | ||
* Use `sudo systemctl daemon-reload` followed by `sudo systemctl enable discord-bot.service` followed by `sudo systemctl start discord-bot.service` to register/enable/start your discord bot service |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const { SlashCommandBuilder } = require('@discordjs/builders'); | ||
|
||
|
||
module.exports = { | ||
data: new SlashCommandBuilder() | ||
.setName('ficsit') | ||
.setDescription('Start the satisfactory server!'), | ||
async execute(interaction) { | ||
await interaction.reply("Sending message to start Satisfactory Server!"); | ||
///////// Your code to start the Satisfactory Server here //////// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is in the repo that contains a way to start the server by hitting an http endpoint, I wonder if it would be good to have a config.ts setting for the lambda/api gateway url -- then this command could just hit that url with an http client to start the server. Maybe have it as an optional implementation if the config is set for the start url. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since I'm using GCP I removed all of my GCP-related code such as the centralised GCP config (And also because I use PubSub as the trigger for my GCP Cloud Functions so that's extra layer I have to deal with) from this file as this would have been pretty useless in your case since your whole setup is on AWS. But you are correct that config should be centralised for easier access. And in your particular case and having this command hit the URL is probably the simplest way to make it work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a small hiccup with this step. It's that the api url is generated after the resources have been deployed and the deployment does not affect local files. The deployment can output the api url once the deployment has completed and the user can then copy this value into the config file. |
||
}, | ||
}; | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const { SlashCommandBuilder } = require('@discordjs/builders'); | ||
|
||
module.exports = { | ||
data: new SlashCommandBuilder() | ||
.setName('ping') | ||
.setDescription('Replies with Pong!'), | ||
async execute(interaction) { | ||
await interaction.reply('Pong!'); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const { SlashCommandBuilder } = require('@discordjs/builders'); | ||
|
||
module.exports = { | ||
data: new SlashCommandBuilder().setName('server').setDescription('Replies with server info!'), | ||
async execute(interaction) { | ||
await interaction.reply(`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const { SlashCommandBuilder } = require('@discordjs/builders'); | ||
|
||
module.exports = { | ||
data: new SlashCommandBuilder().setName('user').setDescription('Replies with user info!'), | ||
async execute(interaction) { | ||
await interaction.reply(`Your tag: ${interaction.user.tag}\nYour id: ${interaction.user.id}`); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"token": "Your Bot Token", | ||
"clientId" : "Your App Oauth2 Client Id", | ||
"guildId" : "Your Server (Guild) Id" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const fs = require('fs'); | ||
const { SlashCommandBuilder } = require('@discordjs/builders'); | ||
const { REST } = require('@discordjs/rest'); | ||
const { Routes } = require('discord-api-types/v9'); | ||
const { clientId, guildId, token } = require('./config.json'); | ||
|
||
const commands = []; | ||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | ||
|
||
for (const file of commandFiles) { | ||
const command = require(`./commands/${file}`); | ||
commands.push(command.data.toJSON()); | ||
} | ||
|
||
const rest = new REST({ version: '9' }).setToken(token); | ||
|
||
rest.put(Routes.applicationGuildCommands(clientId,guildId), { body: commands }) | ||
.then(() => console.log('Successfully registered application commands.')) | ||
.catch(console.error); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[Unit] | ||
Description=Discord Bot | ||
|
||
[Service] | ||
ExecStart=/path/to/folder/discord-bot/index.js | ||
Restart=on-failure | ||
StandardOutput=journal | ||
User=YOUR_USER | ||
Group=YOUR_GROUP | ||
Environment=PATH=/usr/bin:/usr/local/bin | ||
Environment=NODE_ENV=production | ||
WorkingDirectory=/path/to/folder/discord-bot | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
name: 'interactionCreate', | ||
execute(interaction) { | ||
console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = { | ||
name: 'ready', | ||
once: true, | ||
execute(client) { | ||
console.log(`Ready! Logged in as ${client.user.tag}`); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Require the necessary discord.js classes | ||
const fs = require('fs'); | ||
const { Client, Collection, Intents } = require('discord.js'); | ||
const { token } = require('./config.json'); | ||
|
||
// Create a new client instance | ||
const client = new Client({ intents: [Intents.FLAGS.GUILDS] }); | ||
|
||
client.commands = new Collection(); | ||
|
||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | ||
const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); | ||
|
||
for (const file of commandFiles) { | ||
const command = require(`./commands/${file}`); | ||
// Set a new item in the Collection | ||
// With the key as the command name and the value as the exported module | ||
client.commands.set(command.data.name, command); | ||
} | ||
|
||
for (const file of eventFiles) { | ||
const event = require(`./events/${file}`); | ||
if (event.once) { | ||
client.once(event.name, (...args) => event.execute(...args)); | ||
} else { | ||
client.on(event.name, (...args) => event.execute(...args)); | ||
} | ||
} | ||
|
||
client.on('interactionCreate', async interaction => { | ||
if (!interaction.isCommand()) return; | ||
|
||
const command = client.commands.get(interaction.commandName); | ||
|
||
if (!command) return; | ||
|
||
try { | ||
await command.execute(interaction); | ||
} catch (error) { | ||
console.error(error); | ||
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); | ||
} | ||
}); | ||
|
||
// Login to Discord with your client's token | ||
client.login(token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't have to be part of this MR, but it would be nice as a future feature to integrate the creation of the micro instance that manages the bot into the cdk code. Eventually we could have a config variable boolean that could control whether you want the discord bot to be provisioned and deployed along with the other services. (this is just a note, nothing actionable here)