discord-bot-cdk-construct

A CDK Construct for creating a serverless Discord bot. All you need to do is supply your code to handle the commands!

MIT License

Downloads
232
Stars
27
Committers
2

discord-bot-cdk-construct

A CDK Construct for creating a serverless Discord bot. All you need to do is supply your code to handle the commands!

Architecture Overview

This is the architecture for how this project is laid out server-side. The tools used to create these diagrams are:

The bot has a fairly straightforward setup:

The biggest confusion likely stems from the use of two Lambda functions instead of one. This is to ensure that the initial request can respond within Discord's 3 second time limit and return a proper response to the user.

Sample Usage

The usage is split into two parts: The AWS CDK stack that will be used, and a "commands" script that actually handles responding. It's recommended that you are familiar with CDK first before diving into using this.

Handling Commands

For handling commands, you just need to provide a Lambda function for sending response to Discord's Web APIs. As an example of how this can be done:

import {Context, Callback} from 'aws-lambda';
import { IDiscordEventRequest, IDiscordResponseData, getDiscordSecrets, sendFollowupMessage } from 'discord-bot-cdk-construct';

export async function handler(event: IDiscordEventRequest, context: Context,
  callback: Callback): Promise<string> {

  const discordSecret = await getDiscordSecrets();
  const endpointInfo = {
    authToken: discordSecret?.authToken,
    applicationId: discordSecret?.applicationId
  };
  const response = {
    tts: false,
    content: 'Hello world!',
    embeds: [],
    allowedMentions: [],
  };
  if (event.jsonBody.token && await sendFollowupMessage(endpointInfo, event.jsonBody.token, response)) {
    console.log('Responded successfully!');
  } else {
    console.log('Failed to send response!');
  }
  return '200';
}

Using the Construct

To create a stack to make use of the above script, you can create a stack like so:

import {Duration, Stack} from 'aws-cdk-lib';
import {Runtime} from 'aws-cdk-lib/aws-lambda';
import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs';
import {DiscordBotConstruct} from 'discord-bot-cdk-construct';
import {Construct} from 'constructs';
import * as path from 'path';

/**
 * Creates a sample Discord bot endpoint that can be used.
 */
export class SampleDiscordBotStack extends Stack {
  /**
   * The constructor for building the stack.
   * @param {Construct} scope The Construct scope to create the stack in.
   * @param {string} id The ID of the stack to use.
   */
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Create the Commands Lambda.
    const discordCommandsLambda = new NodejsFunction(this, 'discord-commands-lambda', {
      runtime: Runtime.NODEJS_18_X,
      entry: path.join(__dirname, '../functions/DiscordCommands.ts'),
      handler: 'handler',
      timeout: Duration.seconds(60),
    });

    const discordBot = new DiscordBotConstruct(this, 'discord-bot-endpoint', {
      commandsLambdaFunction: discordCommandsLambda,
    });
  }
}

This can of course then be used in your CDK application like so:

import { App } from 'aws-cdk-lib';
import { SampleDiscordBotStack } from './stacks/sample-discord-bot-stack';

const app = new App();
const startAPIStack = new SampleDiscordBotStack(app, 'SampleDiscordBotStack');

Full Demo Project

A full example project utilzing this construct can be found here. Specifically, the start-api-stack.ts file uses the construct, with DiscordCommands.ts being the commands file (like shown above).

Packaging with JSII

In order to package everything with JSII, ensure you have the following installed:

  • Python3
  • Open JDK
  • Maven

See JSII's Prerequisites Documentation for more information.

Useful commands

  • npm run build compile typescript to js
  • npm run watch watch for changes and compile
  • npm run test perform the jest unit tests
  • npm run lint perform a lint check across the code
  • npm run fix-lint fix any lint issues automatically where possible
  • npm run package package all of the bindings for distribution