Giter Site home page Giter Site logo

srgaabriel / discordinteraktions Goto Github PK

View Code? Open in Web Editor NEW

This project forked from lorittabot/discordinteraktions

0.0 0.0 0.0 244 KB

๐Ÿ‘พ Kotlin Library for Receiving and Handling Discord Interactions via Web Servers

License: GNU Affero General Public License v3.0

Kotlin 100.00%

discordinteraktions's Introduction

Discord InteraKTions

Not finished yet so you shouldn't use it yet!!

Discord InteraKTions allows you to create, receive and process Discord's Slash Commands via a HTTP Web Server. Built on top of Kord, using interactions is easy and fun!

Status of Discord InteraKTions

Nothing works yet so you shouldn't use it!! (Okay technically sending messages already work)

  • Receiving Discord Interactions via Web Server/Webhooks
  • Validating Discord Interactions via Web Server/Webhooks
  • Processing Discord Interactions/Slash Commands
  • Sending Messages
  • Sending Messages Directly on Discord's POST Request
  • Sending Follow Up Messages via REST
  • Registering Slash Commands on Discord
  • Sending Embeds
  • Abstractions On Top of Kord
  • Good Documentation
  • Being a good project :3

How it Works

Discord InteraKTions uses a Web Server (with Ktor) ready to receive interactions from Discord! All of the "dirty work", like interaction request validation and parsing, is already done for you, so you only need to care about creating your nifty slash commands and having fun!

Discord InteraKTions uses Kord's common and rest modules for data serialization and REST interactions, keep in mind that Discord InteraKTions creates a abstraction layer between Discord InteraKTions and Kord, to avoid interacting directly with Kord's 1:1 Discord mappings. (Which is a good and ver cool thing that Kord works like that! You can create your abstractions on top of Kord very easily!)

Discord Interactions has a very nice thing that you can reply to a interaction directly on Discord's POST request, but you can also defer the message (if you are going to take more than three seconds to process it) and/or send follow up messages. Discord InteraKTions automatically handles deferring and message follow ups via REST, so if your command is like this:

override suspend fun executes(context: SlashCommandContext) {
    context.sendMessage {
        content = "Hello World! Loritta is very cute!! :3"
    }
}

Discord InteraKTions will handle this as "reply directly on Discord's POST request", which is nice because you avoid consuming rate limits and is pretty useful if your command won't take more than three seconds to process.

But if your command is like this

override suspend fun executes(context: SlashCommandContext) {
    context.sendMessage {
        content = "Hello World! Loritta is very cute!! :3"
    }

    context.sendMessage {
        content = "Bye World! Pantufa and Gabriela are also very cute!! :3"
    }
}

The first sendMessage will be processed as a "reply directly on Discord's POST request" while the second one will be sent as a follow up message via REST.

You can of course handle deferring yourself, if you already know that your command replies will need to be deferred due to your processing taking too long (example: image processing, pulling stuff from a external slow API, etc)

override suspend fun executes(context: SlashCommandContext) {
    context.defer() // Defer the message, we will follow up later

    delay(10_000) // Very slow task here

    context.sendMessage {
        content = "We searched everywhere on the world, and we found out that Loritta is still very cute!! :3"
    }
}

Modules

core

Contains the web server and other nifty stuff.

interaction-declarations

Contains the classes related to declaration of slash commands.

requests-verifier

Contains the code used to verify Discord requests, useful if you want to create your own way to process Discord requests with your own Web Server!

val keyVerifier = InteractionRequestVerifier(publicKey)

...

val signature = call.request.header("X-Signature-Ed25519")!!
val timestamp = call.request.header("X-Signature-Timestamp")!!

val verified = keyVerifier.verifyKey(
    text,
    signature,
    timestamp
)

if (!verified) {
    // Request is not valid, oh no...
    call.respondText("", ContentType.Application.Json, HttpStatusCode.Unauthorized)
    return
}

// Request is valid, yay!

How to Use

Installation

First, add the PerfectDreams repository to your project

repositories {
    maven("https://oss.sonatype.org/content/repositories/snapshots") // Required by Kord
    maven("https://repo.perfectdreams.net/")
}

Then add the Discord InteraKTions dependency!

dependencies {
    ...
    implementation("net.perfectdreams.discordinteraktions:core:0.0.2-SNAPSHOT")
    ...
}

Creating Slash Commands

First we need to create a Slash Command, here's a example of how you can create your own

class CharacterCommand : SlashCommand(CharacterCommand) {
    companion object : SlashCommandDeclaration() {
        // This is the slash command declaration, this is used when registering the command on Discord
        //
        // The reason it is a companion object is to allow you to register the command on Discord without
        // needing to initialize the command class! (which can be a *pain* if your command requires dependency injection)
        override val name = "character" // The command label
        override val description = "So many choices, so little time..." // The command description shown in the Discord UI

        // By default, if you don't override the options, no options will be set
        override val options = Options

        object Options : SlashCommandDeclaration.Options() {
            val character = string("character", "Select a Character!") // Here we are creating a String option
                .required() // ...and it is required
                .choice("loritta", "Loritta Morenitta :3") // ...with custom choices!
                .choice("pantufa", "Pantufa ;w;")
                .choice("gabriela", "Gabriela ^-^")
                .register() // Don't forget to register!

            val repeat = integer("repeat", "How many times the character name should be repeated") // Here we are creating a Int option
                .register() // This isn't required (so it is optional!) and, as always, don't forget to register!
        }
    }

    override suspend fun executes(context: SlashCommandContext) {
        val character = options.character.get(context) // This is a "String" because the option is required
        val repeatCount = options.repeat.get(context) ?: 1 // This is a "Int?" because the option is not required (optional)

        val characterName = when (character) {
            "loritta" -> "Loritta Morenitta"
            "pantufa" -> "Pantufa"
            "gabriela" -> "Gabriela"
            else -> throw IllegalArgumentException("I don't know how to handle $character!")
        }

        val builder = StringBuilder("You selected... ")
        repeat(repeatCount) {
            builder.append(characterName)
        }
        
        context.sendMessage {
            // Sends a message
            //
            // Because we use Web Servers for responses, this response will be replied directly on Discord's POST request!
            // This has the advantage of not consuming any rate limits, which is pretty nifty!
            //
            // If you send multiple messages, the first message will be replied directly on Discord's POST request and the rest of them will
            // be sent as follow up messages using Discord's REST API
            content = builder.toString()
        }
    }
}

After that, you have two options on how to process and handle the interactions...

Interactions via HTTP POST

val interactions = InteractionsServer(
    applicationId = 12345L, // Change the Application ID to your Bot's Application ID
    publicKey = "bot_public_key_here",
    token = "bot_token_here"
)

// Register the command...
interactions.commandManager.register(CharacterCommand())

// And now register all commands registered in our command manager!
interactions.commandManager.updateAllCommandsInGuild(
    Snowflake(40028922L), // Change to your Guild ID
    // This compares the currently registered commands on Discord with the commands in the Command Manager
    // If a command is missing from the Command Manager but is present on Discord, it is deleted from Discord!
    deleteUnknownCommands = true
)

interactions.start() // This starts the interactions web server on port 12212!

// Now we are live! Set your interaction URL on Discord's Developer Portal and have fun!
//
// Don't forget that your Web Server should be accessible from the outside world!
// If you are doing this for tests & stuff, you can use ngrok or a SSH Reverse Tunnel

Interactions via the Gateway

Kord

Add the Kord Gateway Support module to your project

dependencies {
    ...
    implementation("net.perfectdreams.discordinteraktions:gateway-kord:0.0.2-SNAPSHOT")
    ...
}
suspend fun main() {
    val applicationId = Snowflake(12345L) // Change the Application ID to your Bot's Application ID
    val client = Kord("bot_token_here")

    val commandManager = CommandManager(
        client.rest,
        applicationId
    )

    commandManager.register(CharacterCommand())

    // And now register all commands registered in our command manager!
    interactions.commandManager.updateAllCommandsInGuild(
        Snowflake(40028922L), // Change to your Guild ID
        // This compares the currently registered commands on Discord with the commands in the Command Manager
        // If a command is missing from the Command Manager but is present on Discord, it is deleted from Discord!
        deleteUnknownCommands = true
    )

    client.gateway.gateways.forEach {
        it.value.installDiscordInteraKTions( // We will install the Discord InteraKTions listener on every gateway
            commandManager
        )
    }
    
    client.login()
}

discordinteraktions's People

Contributors

mrpowergamerbr avatar srgaabriel avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.