🤖Discord Bot Programmed ... in Discord!
Tags: discord, javascript, programming
Published: 2023-04-28 12:30:00

Meet my bot **Kiryu**. His specialty is downloading JavaScript code from a Discord channel and executing it. To have Kiryu automatically add a role to new members who join my server, I write this message in the code channel:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zuw3ggps32jl7igd0zbu.png)

Kiryu sees the message, extracts the JavaScript code, and `eval()`s it. Now whenever a new member joins, he will give them a role.

Here's another one. This one makes Kiryu automatically ban anyone who sends a message including a banned word:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2atwdidu7r4i9lh3nrx.png)

Kiryu re-evaluates code when he starts, when a new message is created in the code channel, when a code message is updated, and when a code message is deleted, so his code always stays in sync with the code I have written in the code channel.

## Source Code

Check out Kiryu's core code [here](https://github.com/mistval/kiryu). It's just one source file, less than 200 lines.

## Run Your Own Instance

If you want to try running your own instance, I pushed an image to Docker Hub. You can easily launch an instance using Docker:

```bash
docker run \
  --name kiryu \
  --restart unless-stopped \
  -e PROGRAMMER_IDS='YOUR USER ID HERE' \
  -e BOT_TOKEN='YOUR BOT TOKEN HERE' \
  -e CODE_CHANNEL_IDS='YOUR CODE CHANNEL ID HERE' \
  -e LOG_CHANNEL_ID='YOUR LOG CHANNEL ID HERE' \
  -d \
  mistval/kiryu
```

If you don't know how to create a bot account, check out the [start of this great article](https://www.freecodecamp.org/news/create-a-discord-bot-with-python/) and follow the instructions up until you get a bot token, which you can then substitute into the command above, along with your user ID, the ID of the channel you want to write code in, and the channel where you want errors to be reported to.

Once the bot is online, try writing this in your code channel, surrounded by `js` code tags:

```js
messageHandlers.push(
  (msg) => {
    if (msg.content === 'hello') {
      return msg.channel.createMessage('world');
    }
  },
);
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhw0rn5scw864k759gbr.png)

The bot should react with a green checkmark. Then if you say `hello` (in a different channel), the bot should respond with `world`.

## Handling Events

As you may have noticed, Kiryu has a built-in `messageHandlers` array as a convenience. Any function added to that array will be called for every new message that isn't a code message and isn't from a bot. Errors thrown from inside of message handler functions will be automatically reported to the log channel.

For other types of events, you can subscribe to them directly on the `bot` object, as shown in the very first image in this article when I subscribe to the `guildMemberAdd` event.

You can see the available events in the [eris](https://abal.moe/Eris/docs/0.16.1/Client#event-callCreate) documentation here. Eris is a Discord bot library for Node.js. It's no longer well-maintained and it has never been as popular as the `discord.js` library, it's just what I'm personally used to, since I like it for performance reasons.

One gotcha here is that you have to be careful of double-subscribing to events, since the code in the code message may be evaluated multiple times. That's why I run `bot.removeAllListeners('guildMemberAdd');` before subscribing to the event in the earlier example.

## Module Loader

Kiryu can automatically download and install modules from npm. For one of Kiryu's fancier features, I use the `@pagerduty/pdjs` module. It's a library for interfacing with the PagerDuty API. Using Kiryu, moderators in my server have a way to open a PagerDuty incident, which will call my cell phone and wake me up from my beauty sleep. I have this feature because I have another bot in 30,000+ servers, and if something goes really wrong with it, I want to know ASAP!

The code for that feature is a bit longer, so I won't show it here, but here's a short example of using the [hello-world-npm](https://www.npmjs.com/package/hello-world-npm) module to re-implement the above hello world command:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ujwtgopd48ucg3na30ok.png)

If Kiryu doesn't have that module downloaded already, he'll download it and exit. When he restarts (which he will do automatically, if you use the Docker command above) he will have the module available. (I couldn't find a way to load a new module into a running process)

## Other Examples

If you want to see all the code that I'm running on Kiryu, feel free to check [my server](https://discord.gg/V4s8n275QE) where I have the aforementioned PagerDuty command plus a few more, plus SQLite integration.

## Security

I would be remiss if I didn't mention that downloading and `eval()`ing code from a Discord server isn't exactly an inherently secure thing to do. Although Kiryu is written to only evaluate code in messages sent by users whose IDs you specify in the `PROGRAMMER_IDS` environment variable, bugs in Kiryu or in Discord itself could lead to malicious code execution on the host machine.

## Conclusion

So why am I coding a bot like this? Well, just because it's fun, and it's a cool thing to show off in my server. I wouldn't really recommend doing this for a major production bot, but it gets the job done for little chores in my server, and looks cool while doing it! If you're interested in trying Kiryu, or this technique more generally, I'd love to hear what you think in the comments!