Add a command handler

This commit is contained in:
SeanOMik 2020-08-13 18:05:23 -05:00
parent 43b6959805
commit 4d2ebd211d
No known key found for this signature in database
GPG Key ID: FA4D55AC05268A88
6 changed files with 164 additions and 83 deletions

View File

@ -8,63 +8,50 @@ if (not isNil(tokenStream)):
tokenStream.close() tokenStream.close()
var bot = newDiscordClient(tkn) var bot = newDiscordClient(tkn, "?")
registerEventListener(EventType.evtReady, proc(bEvt: BaseEvent) = let pingCommand = Command(name: "ping", commandBody: proc(ctx: CommandContext) =
let event = ReadyEvent(bEvt) discard ctx.channel.sendMessage("PONG")
echo "Ready! (v", 0, ".", 0, ".", 1, ")"
echo "Logged in as: ", bot.clientUser.username, "#", bot.clientUser.discriminator
echo "ID: ", bot.clientUser.id
echo "--------------------"
let presence = newPresence("with Nimcord", activityTypeGame, clientStatusIdle, false)
asyncCheck event.shard.updateClientPresence(presence)
) )
registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) = let modifyChannelTopicCommand = Command(name: "modifyChannelTopic", commandBody: proc(ctx: CommandContext) =
let event = MessageCreateEvent(bEvt) let modifyTopic = ctx.message.content.substr(20)
if (event.message.content == "?ping"): discard ctx.channel.sendMessage("Modifing Channel!")
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache) discard ctx.channel.modifyChannel(ChannelFields(topic: some(modifyTopic)))
if (channel != nil): )
discard channel.sendMessage("PONG")
elif (event.message.content.startsWith("?modifyChannelTopic")):
let modifyTopic = event.message.content.substr(20)
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache) let deleteChannelCommand = Command(name: "deleteChannel", commandBody: proc(ctx: CommandContext) =
if (channel != nil): let channelID = getIDFromJson(ctx.arguments[0])
discard channel.sendMessage("Modifing Channel!") var channel: Channel = ctx.client.cache.getChannel(channelID)
discard channel.modifyChannel(ChannelFields(topic: some(modifyTopic)))
elif (event.message.content.startsWith("?deleteChannel")):
let channelID = getIDFromJson(event.message.content.substr(15))
var channel: Channel = event.shard.client.cache.getChannel(channelID)
# Check if we could find the channel to delete
if (channel != nil): if (channel != nil):
discard channel.sendMessage("Deleting Channel!") discard channel.sendMessage("Deleting Channel!")
discard channel.deleteChannel() discard channel.deleteChannel()
discard channel.sendMessage("Deleted Channel!") discard ctx.channel.sendMessage("Deleted Channel!")
elif (event.message.content.startsWith("?getMessages")): )
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil): let bulkDeleteMessagesCommand = Command(name: "bulkDeleteMessages", commandBody: proc(ctx: CommandContext) =
discard channel.getMessages(MessagesGetRequest(limit: some(15), before: some(event.message.id)))
elif (event.message.content.startsWith("?bulkDeleteMessages")):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
var amount: int = 25 var amount: int = 25
if (event.message.content.len > 19): if (ctx.message.content.len > 19):
amount = parseIntEasy(event.message.content.substr(20)) amount = parseIntEasy(ctx.arguments[0])
let messages = channel.getMessages(MessagesGetRequest(limit: some(amount), before: some(event.message.id)))
discard channel.bulkDeleteMessages(messages) # Get the message to delete, then delete them.
elif (event.message.content.startsWith("?reactToMessage")): let messages = ctx.channel.getMessages(MessagesGetRequest(limit: some(amount), before: some(ctx.message.id)))
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache) discard ctx.channel.bulkDeleteMessages(messages)
if (channel != nil):
# Delete the message that was used to run this command.
discard ctx.message.deleteMessage()
)
let reactToMessageCommand = Command(name: "reactToMessage", commandBody: proc(ctx: CommandContext) =
let emojis = @[newEmoji("⏮️"), newEmoji("⬅️"), newEmoji("⏹️"), newEmoji("➡️"), newEmoji("⏭️")] let emojis = @[newEmoji("⏮️"), newEmoji("⬅️"), newEmoji("⏹️"), newEmoji("➡️"), newEmoji("⏭️")]
for emoji in emojis: for emoji in emojis:
discard event.message.addReaction(emoji) discard ctx.message.addReaction(emoji)
elif (event.message.content.startsWith("?testEmbed")): )
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil): let testEmbedCommand = Command(name: "testEmbed", commandBody: proc(ctx: CommandContext) =
var embed = Embed() var embed = Embed()
embed.setTitle("This embed is being sent from Nimcord!") embed.setTitle("This embed is being sent from Nimcord!")
embed.setDescription("Nimcord was developed in about a week of actual work so there will likely be issues.") embed.setDescription("Nimcord was developed in about a week of actual work so there will likely be issues.")
@ -72,21 +59,21 @@ registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) =
embed.addField("Inline-0", "This is an inline field 0", true) embed.addField("Inline-0", "This is an inline field 0", true)
embed.addField("Inline-1", "This is an inline field 1", true) embed.addField("Inline-1", "This is an inline field 1", true)
embed.setColor(0xffb900) embed.setColor(0xffb900)
discard channel.sendMessage("", false, embed) discard ctx.channel.sendMessage("", false, embed)
elif (event.message.content.startsWith("?sendFile")): )
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil): let sendFileCommand = Command(name: "sendFile", commandBody: proc(ctx: CommandContext) =
let filePath = event.message.content.substr(10) let filePath = ctx.message.content.substr(10)
let splitFile = splitFile(filePath) let splitFile = splitFile(filePath)
let fileName = splitFile.name & splitFile.ext let fileName = splitFile.name & splitFile.ext
let file = DiscordFile(filePath: filePath, fileName: fileName) let file = DiscordFile(filePath: filePath, fileName: fileName)
discard channel.sendMessage("", false, nil, @[file]) discard ctx.channel.sendMessage("", false, nil, @[file])
elif (event.message.content.startsWith("?sendImage")): )
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil): let sendImageCommand = Command(name: "sendImage", commandBody: proc(ctx: CommandContext) =
let filePath = event.message.content.substr(11) let filePath = ctx.message.content.substr(11)
let splitFile = splitFile(filePath) let splitFile = splitFile(filePath)
let fileName = splitFile.name & splitFile.ext let fileName = splitFile.name & splitFile.ext
@ -96,7 +83,36 @@ registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) =
var embed = Embed() var embed = Embed()
embed.setTitle("Image attachment test.") embed.setTitle("Image attachment test.")
embed.setImage("attachment://" & fileName) embed.setImage("attachment://" & fileName)
discard channel.sendMessage("", false, embed, @[file]) discard ctx.channel.sendMessage("", false, embed, @[file])
)
# You can even register commands like this:
registerCommand(Command(name: "ping2", commandBody: proc(ctx: CommandContext) =
discard ctx.channel.sendMessage("PONG3")
))
# Listen for the ready event.
registerEventListener(EventType.evtReady, proc(bEvt: BaseEvent) =
# Cast the BaseEvent to the ReadyEvent which is what we're listening to.
let event = ReadyEvent(bEvt)
echo "Ready! (v", 0, ".", 0, ".", 1, ")"
echo "Logged in as: ", bot.clientUser.username, "#", bot.clientUser.discriminator
echo "ID: ", bot.clientUser.id
echo "--------------------"
let presence = newPresence("with Nimcord", activityTypeGame, clientStatusIdle, false)
asyncCheck event.shard.updateClientPresence(presence)
# Register commands. You don't need to register them in EventReady.
registerCommand(pingCommand)
registerCommand(modifyChannelTopicCommand)
registerCommand(deleteChannelCommand)
registerCommand(bulkDeleteMessagesCommand)
registerCommand(reactToMessageCommand)
registerCommand(testEmbedCommand)
registerCommand(sendFileCommand)
registerCommand(sendImageCommand)
) )
waitFor bot.startConnection() waitFor bot.startConnection()

View File

@ -16,11 +16,11 @@
import nimcord/[cache, channel, client, clientobjects, discordobject] import nimcord/[cache, channel, client, clientobjects, discordobject]
import nimcord/[embed, emoji, eventdispatcher, eventhandler, guild] import nimcord/[embed, emoji, eventdispatcher, eventhandler, guild]
import nimcord/[image, member, message, nimcordutils, permission] import nimcord/[image, member, message, nimcordutils, permission]
import nimcord/[presence, role, user] import nimcord/[presence, role, user, commandsystem]
export cache, channel, client, clientobjects, discordobject export cache, channel, client, clientobjects, discordobject
export embed, emoji, eventdispatcher, eventhandler, guild export embed, emoji, eventdispatcher, eventhandler, guild
export image, member, message, nimcordutils, permission export image, member, message, nimcordutils, permission
export presence, role, user export presence, role, user, commandsystem
const NimCordVersion = "v0.0.1" const NimCordVersion = "v0.0.1"

View File

@ -247,7 +247,7 @@ proc updateClientPresence*(shard: Shard, presence: Presence) {.async.} =
await shard.sendGatewayRequest(jsonPayload) await shard.sendGatewayRequest(jsonPayload)
proc newDiscordClient*(tkn: string): DiscordClient = proc newDiscordClient*(tkn: string, commandPrefix: string): DiscordClient =
## Create a DiscordClient using a token. ## Create a DiscordClient using a token.
## ##
## Sets globalDiscordClient to the newly created client. ## Sets globalDiscordClient to the newly created client.
@ -256,4 +256,4 @@ proc newDiscordClient*(tkn: string): DiscordClient =
var cac: Cache var cac: Cache
new(cac) new(cac)
result = DiscordClient(token: tkn, cache: cac) result = DiscordClient(token: tkn, cache: cac, commandPrefix: commandPrefix)

View File

@ -9,6 +9,7 @@ type
shards*: seq[Shard] shards*: seq[Shard]
shardCount*: int shardCount*: int
endpoint*: string endpoint*: string
commandPrefix*: string
Shard* = ref object Shard* = ref object
id*: int id*: int

View File

@ -0,0 +1,60 @@
import tables, message, member, user, channel, strutils, clientobjects, cache
type
CommandContext* = ref object of RootObj
## Object to make it easier to create commands.
message*: Message ## The message that ran the command
channel*: Channel ## The channel that this command was ran in.
author*: GuildMember ## The GuildMember that ran the command.
user*: User ## The user who ran the command.
arguments*: seq[string] ## The command arguments.
client*: DiscordClient ## The DiscordClient.
Command* = ref object of RootObj
## Command object.
name*: string ## The name of the command.
commandBody*: proc(ctx: CommandContext) ## The command body of the command.
commandRequirements*: proc(ctx: CommandContext): bool ## The requirements of the command,
## ran before commandBody to check if
## the command can run.
# Table storing all the commands
let registeredCommands = newTable[string, Command]()
proc registerCommand*(command: Command) =
## Register a Command.
##
## Examples:
##
## .. code-block:: nim
## registerCommand(Command(name: "ping", commandBody: proc(ctx: CommandContext) =
## discard ctx.channel.sendMessage("PONG")
## ))
registeredCommands.add(command.name, command)
proc fireCommand*(client: DiscordClient, message: Message) =
## Fire a command. This is already called by Nimcord. Not any need to call this.
# If the message doesn't start with the prefix, then
# it probably isn't a commnand.
if not message.content.startsWith(client.commandPrefix):
return
# Get the arguments for the command
var arguments: seq[string] = message.content.split(" ")
# Extract the command name from arguments
let commandName = arguments[0].substr(1)
arguments.del(0)
## Dispatches an event so something can listen to it.
if (registeredCommands.hasKey(commandName)):
let commandContext = CommandContext(message: message, channel: message.getMessageChannel(client.cache),
author: message.member, user: message.author, arguments: arguments, client: client)
let command = registeredCommands[commandName]
if command.commandRequirements != nil:
if command.commandRequirements(commandContext):
command.commandBody(commandContext)
else:
command.commandBody(commandContext)

View File

@ -1,6 +1,7 @@
import eventhandler, json, tables, message, emoji, user, member, role import eventhandler, json, tables, message, emoji, user, member, role
import guild, channel, nimcordutils, httpClient, strformat, cache import guild, channel, nimcordutils, httpClient, strformat, cache
import asyncdispatch, clientobjects, discordobject, presence import sequtils, asyncdispatch, clientobjects, discordobject, presence
import commandsystem
proc readyEvent(shard: Shard, json: JsonNode) = proc readyEvent(shard: Shard, json: JsonNode) =
var readyEvent = ReadyEvent(shard: shard, readyPayload: json, name: $EventType.evtReady) var readyEvent = ReadyEvent(shard: shard, readyPayload: json, name: $EventType.evtReady)
@ -275,6 +276,9 @@ proc messageCreateEvent(shard: Shard, json: JsonNode) =
shard.client.cache.messages[msg.id] = msg shard.client.cache.messages[msg.id] = msg
let messageCreateEvnt = MessageCreateEvent(shard: shard, message: msg, name: $EventType.evtMessageCreate) let messageCreateEvnt = MessageCreateEvent(shard: shard, message: msg, name: $EventType.evtMessageCreate)
shard.client.fireCommand(msg) # Fire a command
dispatchEvent(messageCreateEvnt) dispatchEvent(messageCreateEvnt)
proc messageUpdateEvent(shard: Shard, json: JsonNode) = proc messageUpdateEvent(shard: Shard, json: JsonNode) =