The Party Corgi Network Discord server is reaching a point where we need some automation. That comes in the flavor of a discord bot for us. In a perfect world I'd be connecting the discord websocket API over to AWS APIGateway websockets backed by lambdas. This is not a perfect world so we're using Docker and Digital Ocean.
tldr; the code
Our bot starts out pretty small. I've included Honeycomb because I want some insight into what happens while this bot is running. We set the transmission to "writer" so that the events get logged out to stdout. We'll switch this later in production.
const Discord = require("discord.js");const libhoney = require("libhoney");const hny = new libhoney({writeKey: process.env.HONEYCOMB_TOKEN || "asf",dataset: "discord",serviceName: "corgo-discord-bot",transmission: "writer",});const CORGO_BOT_ID = "714618235458289804";// Create an instance of a Discord clientconst client = new Discord.Client();/*** The ready event is vital, it means that only _after_ this will your bot start reacting to information* received from Discord*/client.on("ready", () => {console.log("corgo ready!");});// Create an event listener for messagesclient.on("message", (message) => {let ev = hny.newEvent();ev.add({ eventType: "message", authorId: message.author.id });if (message.author.id === CORGO_BOT_ID) {ev.addField("isBot", true);ev.send();return;}if (message.content === "!avatar") {// If the message is "what is my avatar"// Send the user's avatar URLmessage.reply(message.author.displayAvatarURL());ev.addField("avatar", true);}ev.send();});hny.sendNow({ booting: true });// Log our bot in using the token from https://discordapp.com/developers/applications/meclient.login(process.env.DISCORD_TOKEN);
We're basing our Dockerfile on a specific version of node (v14) and a specific version of alpine linux (3.11). Then we set the entrypoint
to node index.js
.
FROM node:14.3.0-alpine3.11COPY . /opt/botWORKDIR /opt/botRUN yarnENTRYPOINT node index.js
I used the docker hub registry for testing because it was easy and I already had an account. We can build the dockerfile into an image and run a container based on that image using the following. Note that we also need to set the DISCORD_TOKEN
env var, which I already had set in my environment so I passed it through.
docker build -t biscarch/corgo-bot .docker run -ite DISCORD_TOKEN=$DISCORD_TOKEN biscarch/corgo-bot
With the built image we can push it to the registry
docker push biscarch/corgo-bot:latest
Then ssh into our digital ocean droplit. You'll need to get the IP address from the console and also have set up the droplit with an ssh key you have access to.
ssh root@xxx.xx.xx.xx
Once in, we can pull and run to test.
docker push biscarch/corgo-botdocker run -ite DISCORD_TOKEN=$DISCORD_TOKEN biscarch/corgo-bot
You should see output that looks like this when messages get sent. This is the bare scaffolded honeycomb events. We'll make these more interesting later.
"{\"time\":\"2020-05-26T00:53:20.869Z\",\"samplerate\":1,\"data\":{\"booting\":true}}"corgo ready!"{\"time\":\"2020-05-26T00:53:37.052Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"103513724052082688\",\"avatar\":true}}""{\"time\":\"2020-05-26T00:53:37.156Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"714618235458289804\",\"isBot\":true}}""{\"time\":\"2020-05-26T00:53:41.696Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"681453482590339081\"}}"
If you ssh in again from a different terminal, a docker ps
will show us what containers are running.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESfe5419ebf09b biscarch/corgo-bot "/bin/sh -c 'node in…" 8 hours ago Up 8 hours charming_swartz