How I have Built Jeeves using Discord.js
A quick look on how I've created a simple Discord bot to manage an AzerothCore server with no extra effort, plug and play.
Published on May 28, 2020

A few months ago I’ve tried to make a new private WOTLK server, the idea was simple, manage everything through a Discord bot for ease of use and accessibility, sadly, we didn’t gather enough players to keep the server going, so I’ve decided to release the source code so everyone using AzerothCore could benefit from it.
If you wish to see the full code, please refer to my repository here.
Walkthrough
I’ll show you, in parts, how it was built. To get started, we must create a new git
repository (you don’t need a remote), to do so create a new directory and type the following command:
yarn init
Awesome, now let’s add a few packages, we will be using discord.js
for the bot framework, mysql
to handle all the database related tasks and dotenv
to keep our credentials secret.
yarn add discord.js mysql dotenv
You also may want a linter, in that case use:
yarn add -D eslint
Great, time to get to work! Create a new file named index.js
at the root of your project.
Fill this file with the following data:
// index.js
// importing dotenv
require('dotenv').config()
// package imports
const fs = require('fs')
const Discord = require('discord.js')
// setting the command prefix
const prefix = process.env.PREFIX || '!'
// bot initialization
const client = new Discord.Client()
// commands handler
client.commands = new Discord.Collection()
// searches the commands dir for `.js` files
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'))
// for each command found, import and register it
for (const file of commandFiles) {
const command = require(`./commands/${file}`)
client.commands.set(command.name, command)
}
// whenever the bot is ready display a console message
client.once('ready', () => {
console.log('Jeeves ready for duty!')
})
// this is where the real code lays
client.on('message', message => { /* code stripped for readiness purposes */ })
// login using our credentials
client.login(process.env.TOKEN)
Now that the base code is done (aside from the stripped part) we can create commands, make a new folder called commands
at the root directory of your project.
Creating a command:
// commands/help.js
// load secrets
require('dotenv').config()
// prefix once again
const prefix = process.env.PREFIX
module.exports = {
// command name
name: 'help',
// command description
description: 'List all of my commands or info about a specific command.',
// command aliases
aliases: ['commands'],
// command cooldown
cooldown: 1,
execute(message, args) {
// your code goes here
}
}
You get the point, so let’s dissect one of the more useful commands like the registration for example. For this example I’ll include the full snippet, but do remember that the source code is on Github, in case you wish to check it out later…
// commands/join.js
// import stuff
require('dotenv').config()
const mysql = require('mysql')
const crypto = require('crypto')
// create a new connection with your database
const connection = mysql.createConnection(`mysql://${process.env.MYSQL_USER}:${process.env.MYSQL_PASSWORD}@${process.env.MYSQL_HOST}/acore_auth`)
module.exports = {
name: 'join',
description: 'Command used to create an account into the world server.',
aliases: ['signup', 'register', 'login'],
usage: '<usernane> <password>',
cooldown: 30,
execute (message, args) {
// fails if the user doesn't provide arguments
if (!args.length) return message.reply('Missing arguments, type `!help join` for more info.')
// store both given username and password
const username = args[0]
const password = args[1]
// basic password checks
if (!username || !password) return
if (username.length <= 3) return
if (password.length <= 6) return
// hashing function to encrypt your password to be stored in the database
const toPassword = (username, password) => {
const hash = crypto.createHash('sha1')
const data = hash.update(`${username.toUpperCase()}:${password.toUpperCase()}`, 'utf-8')
return data.digest('hex').toUpperCase()
}
// checks if the account already exists
connection.query('select exists(select id from account where reg_mail = ?)', [message.author.id], (error, results, fields) => {
// if mysql couldn't connect or anything, display an error
if (error) return message.reply('An error occured.')
// if everything checks out then insert the values into the database
if (Object.values(results[0])[0] === 0) {
connection.query('insert into account (username, sha_pass_hash, reg_mail) values (?, ?, ?)', [username, toPassword(username, password), message.author.id], (error, results, fields) => {
if (error) {
return message.reply('Syntax error, please check your input arguments.')
} else { message.reply('Account created, you may login now.') }
})
} else {
message.reply('You already have an account!')
}
})
}
}
You should probably have an idea of what’s going on by now, in the next section we will be looking on how to setup and deploy this project.
Setup
In order to use this bot you will need to do some setup on Discord first, follow along:
- Login on Discord.
- Head over to the Developer Portal.
- Create a new application.
- Click the “Bot” tab and create a new bot.
- Save the token somewhere safe, you will need it later.
- Click the “OAuth2” tab and copy the client ID.
- Head over to
https://discord.com/oauth2/authorize?client_id=CLIENT_ID&scope=bot
to add your bot to a server. - Done.
Feel free to manage the bot’s profile picture, description and the server role.
Since the repo provides a Dockerfile
and heroku.yml
configurations you can pretty much automatically deploy to Heroku.
In case you want to deploy somewhere else, modify Dockerfile
and add the CMD
line like the block below, else your bot won’t start.
FROM node:latest
WORKDIR /app
COPY . /app
RUN yarn install
CMD yarn start
There are plenty of good hosts out there but if you want a cheap and performant option, check out Digital Ocean, use this link to get $100 in credit.
Deployment
Deployment methods will be different for each platform, if you are using Heroku, just clone the repository, create a new project and push your local branch.
# login
heroku login
# create a new app
heroku create
# update stack to container
heroku set stack:container
# push to remote
git push heroku master
Finally, add the required environment variables, you can use a .env
file or configure them within the settings page if you are deploying to Heroku.
PREFIX
, TOKEN
, MYSQL_USER
, MYSQL_PASSWORD
and MYSQL_HOST
.
Atfer setting that your bot should be online within a few minutes.
Conclusion
Even though I didn’t succeed on my server I sincerely hope that you do on yours. Feel free to open an issue/pull request if you wish to have more features added.
Thanks for reading!