moleculer-discord

0.3.4 • Public • Published

moleculer-discord

Build Status Discord Gateway for Moleculer.js framework.

Features
1. Configurations
2. Slash Commands
2.1 Slash Commands Options
2.2 Slash Commands Responses
3.2 Message Commands
4 Actions

Configuration

This gateway uses Discord.js lib, so to setup a Discord Bot its recommended to see this tutorial Setup Discord Bot , after setting bot lets begin to Code:

const DiscordGateway = require("moleculer-discord");
module.exports = {
    name: "discord",
    mixins: [DiscordGateway],
    settings: {
        token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        clientId: "xxxxxxxxxxxxxxx",
        guildId: "xxxxxxxxxxxxxxx",
        clientOpts: {intents: ["GUILDS", "GUILD_MESSAGES", "GUILD_MESSAGE_REACTIONS"]},
    },
};
Settings Type Required Description
token String X Access Token of Discord Bot obtained in OAuth2 page
clientId String X Client of Discord Bot obtained in OAuth2 page
guildId String, String[] GuildId represents in which Servers the bot will work, all servers if undefined
clientOpts Object Options to Create DiscordBot Instance, More Info

Slash Commands

To register Commands that Start with Slash(/), we need to create a object that represents all options of these commands.

SlashCommands Type Required Description
name String X Name of SlashCommand(used as Key of SlashCommand)
description String X Description of Command that appears in discord
action String, Function X Action which moleculer will call
deferred Boolean, Object If you need hadle a action who takes more than 3 seconds(doc)
options Object Input options of Command(check below)

Slash Commands Options

SlashCommands Options Type Required Description
name String X Name of SlashCommand Option(used as Key of SlashCommand Options)
description String X Description of Command that appears in discord
type String X Input type, "integer", "string", "channel", "user", all list in doc
require Boolean

SlashCommands Registration Example:

module.exports = {
    name: "discord",
    mixins: [DiscordGateway],
    settings: {
        clientOpts: {},
        token: "xxxxx",
        clientId: "xxxx",
    },
    slashes: {
        ping: {
            action: "users.ping",
            description: "Replies with pong!",
        },
        clear: {
            action: "users.clear",
            description: "Clean Messages",
            options: {
                amount: {type: "integer", description: "How many messages to deletee", required: true,},
                channel: {type: "channel", description: "Channel that will delete messages"}
            },
        },           
    }
};

Slash Commands Responses

Have some standardized ways to return response back to response back to Discord gate way with

    1) String

    Returning a string in called action, the gateway will response current Chat

ping: {
    handler(ctx){
        return "pong"
    }
}
    2) Multiple Messages

    Returning a array of strings in called action, the gateway will response a series of messages at current Chat

ping: {
    handler(ctx) {
        return ["pong", "ping"]
    }
}
    3) Embed Message

    To return Embed Message just return a object with key "embed" and value true and set the rest of configurations, see docs

ping: {
    handler(ctx) {
        return {type: "embed", title: "foo"}
    }
}
    4) Ephemeral Message

    You may not always want everyone who has access to the channel to see a slash command's response, so set ephemeral as true in resposne, see docs

ping: {
    handler(ctx) {
        return { content: 'Pong!', ephemeral: true }
    }
}
    5) Deferred Message

    Some actions take more than 3 seconds, so you need set actions as deferred, to say to Discord give you more time(up to 15 minutes) to process and give a response, so in slash command declaration you need to set deffered as true. See docs

//Slash Command declaration
slashes: {
    ping: {
        action: "users.ping",
        description: "Replies with pong!",
        deferred: true   
    }      
}
//Action
ping: {
    async handler(ctx) {
        await (new Promise((resolve, reject) => { setTimeout(resolve, 10000)}));
        return 'pong';
    }
}
    6) Deferred + Ephemeral Message

    If you need a long task with ephemeral mode, just set ephemeral in slash command declation with object with ephemeral.

//Slash Command declaration
slashes: {
    ping: {
        action: "users.ping",
        description: "Replies with pong!",
        deferred: { ephemeral: true }   
    }      
}
//Action
ping: {
    async handler(ctx) {
        await (new Promise((resolve, reject) => { setTimeout(resolve, 10000)}));
        return 'pong';
    }
}
    7) Delete Timer Message

    If you need to delete message after some time just add delete attribute and the time in milliseconds.

//Action
ping: {
    async handler(ctx) {
        return {content: 'pong', delete: 10000};
    }
}

    If response is ephemeral, use a object in delete, to edit message after timeout.

//Action
ping: {
    async handler(ctx) {
        return {content: 'pong', delete: {timeout: 10000, content: "timeout!!"}, ephemeral: true};
    }
}
    8) components

    If you need to show some buttons or selects for the user, just return component attribute just like the doc, the on difference is that you need to pass a action to be called in component, and if you wanna pass a user filter, just add a userId in attribute, and if you wanna pass some param to button handler, add params attribute, its util to persist some date between actions, if you wanna set timeout for your actions just set time attribute in milliseconds.

//Action
buttons: {
    async handler() {
        return  {
            content: "*`Esta mensagem será deletada em 30 segundos`*",
            components: [
                {
                    type: 1,
                    params: { foo: "bar" },
                    time: 15000,
                    components: [{
                        type: 2,
                        label: "Verify",
                        style: 3,
                        custom_id: "verify",
                        action: "users.acceptButton",
                    }, {
                        type: 2,
                        label: "Cancel",
                        style: 4,
                        custom_id: "cancel",
                        action: "users.cancelButton",
                    }
                    ]
                }
            ]
        };
    }
}
    9) update

    If you need current interaction just user "update" type in response(used to update buttons ).

//Action
buttonHandler: {
    async handler(ctx) {
        return {type: "update", content: "OK", components: []}
    }
}

Message Commands

It's possible to register commands in text messages like MeeSix make with commands "!play " or "!clean ", to set a message command just create a object like slashes commands:

module.exports = {
    name: "discord",
    mixins: [DiscordGateway],
    settings: {
        clientOpts: {},
        token: "xxxxxxxx",
        guildId: "xxxxxxxxx",
        clientId: "xxxxxx",
    },
    messages: {
        "!ping": {action: "users.ping"},
        "!say {message}": {action: "users.say"},
    },
}

In this example, all messages that starts with "!ping" will call "users.ping" action, in the second message command is declared a param named message(message params is always a string), so if we send "!say 12345" to discord, the gateway will call "users.say" action and send {message: "12345"} as params

Actions

In Discord Gateway has some actions that could be very helpful to control messages, channels, guilds, and users.

guilds

List all Guilds(or discord servers) connected to your Discord Bot, if you pass a "guildId" in params, the action will search with this Id.

let guilds = await ctx.call("discord.guilds");
let guild = await ctx.call("discord.guilds", {guildId: "xxxxxxxxx"});

channels

List all Channels connect to your Discord Bot, if you pass a "channelId" in params, the action will search with this Id.

let channels = await ctx.call("discord.channels");
let channel = await ctx.call("discord.channels", {channelId: "xxxxxxxxx"});

send

Send message in channel by channelId or user param;

await ctx.call("discord.send", {channelId: "xxxxxxxxx", message: "ping"});
await ctx.call("discord.send", {userId: "xxxxxxxxx", message: "ping"});
await ctx.call("discord.send", {channelId: "xxxxxxxxx", message: {type: "embed", title: "foo"}})

clear

Clear amount of messages by channelId param;

await ctx.call("discord.clear", {channelId: "xxxxxxxx", amount: 5});

Life Cycle Events

It's possible to register some events before and after call action, or for error handling. just create a Method in Discord Gateway with event name(onBeforeCall, onAfterCall, authorize, onError), all these methods comes with a ctx and a interaction object

onBeforeCall

OnBeforeCall it's useful to put author of message and the channel which message comes.

    methods: {
        onBeforeCall(ctx, interaction) {
            ctx.meta.author = interaction.user;
            ctx.meta.channel = interaction.channel;
        },
        authorize(ctx, interaction) {
            if(interaction.user.hasRole('123445555')) {
                throw new MoleculerClientError("UNAUTHORIZED");
            }
            ctx.meta.user = await ctx.call("dbUser.get", {where: {discordId: interaction.user.id}});
        }
        onError(ctx, interaction, error){
            if(error.type === "UNAUTHORIZED"){
                return "You dont have Permission"
            }   
        }   
    }

Readme

Keywords

none

Package Sidebar

Install

npm i moleculer-discord

Weekly Downloads

0

Version

0.3.4

License

MIT

Unpacked Size

373 kB

Total Files

22

Last publish

Collaborators

  • caiofilus