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()
var bot = newDiscordClient(tkn)
var bot = newDiscordClient(tkn, "?")
registerEventListener(EventType.evtReady, proc(bEvt: BaseEvent) =
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)
let pingCommand = Command(name: "ping", commandBody: proc(ctx: CommandContext) =
discard ctx.channel.sendMessage("PONG")
)
registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) =
let event = MessageCreateEvent(bEvt)
let modifyChannelTopicCommand = Command(name: "modifyChannelTopic", commandBody: proc(ctx: CommandContext) =
let modifyTopic = ctx.message.content.substr(20)
if (event.message.content == "?ping"):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
discard channel.sendMessage("PONG")
elif (event.message.content.startsWith("?modifyChannelTopic")):
let modifyTopic = event.message.content.substr(20)
discard ctx.channel.sendMessage("Modifing Channel!")
discard ctx.channel.modifyChannel(ChannelFields(topic: some(modifyTopic)))
)
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
discard channel.sendMessage("Modifing Channel!")
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)
let deleteChannelCommand = Command(name: "deleteChannel", commandBody: proc(ctx: CommandContext) =
let channelID = getIDFromJson(ctx.arguments[0])
var channel: Channel = ctx.client.cache.getChannel(channelID)
# Check if we could find the channel to delete
if (channel != nil):
discard channel.sendMessage("Deleting Channel!")
discard channel.deleteChannel()
discard channel.sendMessage("Deleted Channel!")
elif (event.message.content.startsWith("?getMessages")):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
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):
discard ctx.channel.sendMessage("Deleted Channel!")
)
let bulkDeleteMessagesCommand = Command(name: "bulkDeleteMessages", commandBody: proc(ctx: CommandContext) =
var amount: int = 25
if (event.message.content.len > 19):
amount = parseIntEasy(event.message.content.substr(20))
let messages = channel.getMessages(MessagesGetRequest(limit: some(amount), before: some(event.message.id)))
discard channel.bulkDeleteMessages(messages)
elif (event.message.content.startsWith("?reactToMessage")):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
if (ctx.message.content.len > 19):
amount = parseIntEasy(ctx.arguments[0])
# Get the message to delete, then delete them.
let messages = ctx.channel.getMessages(MessagesGetRequest(limit: some(amount), before: some(ctx.message.id)))
discard ctx.channel.bulkDeleteMessages(messages)
# 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("⏭️")]
for emoji in emojis:
discard event.message.addReaction(emoji)
elif (event.message.content.startsWith("?testEmbed")):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
discard ctx.message.addReaction(emoji)
)
let testEmbedCommand = Command(name: "testEmbed", commandBody: proc(ctx: CommandContext) =
var embed = Embed()
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.")
@ -72,21 +59,21 @@ registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) =
embed.addField("Inline-0", "This is an inline field 0", true)
embed.addField("Inline-1", "This is an inline field 1", true)
embed.setColor(0xffb900)
discard channel.sendMessage("", false, embed)
elif (event.message.content.startsWith("?sendFile")):
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache)
if (channel != nil):
let filePath = event.message.content.substr(10)
discard ctx.channel.sendMessage("", false, embed)
)
let sendFileCommand = Command(name: "sendFile", commandBody: proc(ctx: CommandContext) =
let filePath = ctx.message.content.substr(10)
let splitFile = splitFile(filePath)
let fileName = splitFile.name & splitFile.ext
let file = DiscordFile(filePath: filePath, fileName: fileName)
discard 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 filePath = event.message.content.substr(11)
discard ctx.channel.sendMessage("", false, nil, @[file])
)
let sendImageCommand = Command(name: "sendImage", commandBody: proc(ctx: CommandContext) =
let filePath = ctx.message.content.substr(11)
let splitFile = splitFile(filePath)
let fileName = splitFile.name & splitFile.ext
@ -96,7 +83,36 @@ registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) =
var embed = Embed()
embed.setTitle("Image attachment test.")
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()

View File

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

View File

@ -247,7 +247,7 @@ proc updateClientPresence*(shard: Shard, presence: Presence) {.async.} =
await shard.sendGatewayRequest(jsonPayload)
proc newDiscordClient*(tkn: string): DiscordClient =
proc newDiscordClient*(tkn: string, commandPrefix: string): DiscordClient =
## Create a DiscordClient using a token.
##
## Sets globalDiscordClient to the newly created client.
@ -256,4 +256,4 @@ proc newDiscordClient*(tkn: string): DiscordClient =
var cac: Cache
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]
shardCount*: int
endpoint*: string
commandPrefix*: string
Shard* = ref object
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 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) =
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
let messageCreateEvnt = MessageCreateEvent(shard: shard, message: msg, name: $EventType.evtMessageCreate)
shard.client.fireCommand(msg) # Fire a command
dispatchEvent(messageCreateEvnt)
proc messageUpdateEvent(shard: Shard, json: JsonNode) =