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,10 +8,93 @@ if (not isNil(tokenStream)):
tokenStream.close() tokenStream.close()
var bot = newDiscordClient(tkn) var bot = newDiscordClient(tkn, "?")
let pingCommand = Command(name: "ping", commandBody: proc(ctx: CommandContext) =
discard ctx.channel.sendMessage("PONG")
)
let modifyChannelTopicCommand = Command(name: "modifyChannelTopic", commandBody: proc(ctx: CommandContext) =
let modifyTopic = ctx.message.content.substr(20)
discard ctx.channel.sendMessage("Modifing Channel!")
discard ctx.channel.modifyChannel(ChannelFields(topic: some(modifyTopic)))
)
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 ctx.channel.sendMessage("Deleted Channel!")
)
let bulkDeleteMessagesCommand = Command(name: "bulkDeleteMessages", commandBody: proc(ctx: CommandContext) =
var amount: int = 25
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 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.")
embed.addField("Title", "value")
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 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 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
let file = DiscordFile(filePath: filePath, fileName: fileName)
var embed = Embed()
embed.setTitle("Image attachment test.")
embed.setImage("attachment://" & fileName)
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) = registerEventListener(EventType.evtReady, proc(bEvt: BaseEvent) =
let event = ReadyEvent(bEvt) # Cast the BaseEvent to the ReadyEvent which is what we're listening to.
let event = ReadyEvent(bEvt)
echo "Ready! (v", 0, ".", 0, ".", 1, ")" echo "Ready! (v", 0, ".", 0, ".", 1, ")"
echo "Logged in as: ", bot.clientUser.username, "#", bot.clientUser.discriminator echo "Logged in as: ", bot.clientUser.username, "#", bot.clientUser.discriminator
@ -20,83 +103,16 @@ registerEventListener(EventType.evtReady, proc(bEvt: BaseEvent) =
let presence = newPresence("with Nimcord", activityTypeGame, clientStatusIdle, false) let presence = newPresence("with Nimcord", activityTypeGame, clientStatusIdle, false)
asyncCheck event.shard.updateClientPresence(presence) asyncCheck event.shard.updateClientPresence(presence)
)
registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) = # Register commands. You don't need to register them in EventReady.
let event = MessageCreateEvent(bEvt) registerCommand(pingCommand)
registerCommand(modifyChannelTopicCommand)
if (event.message.content == "?ping"): registerCommand(deleteChannelCommand)
var channel: Channel = event.message.getMessageChannel(event.shard.client.cache) registerCommand(bulkDeleteMessagesCommand)
if (channel != nil): registerCommand(reactToMessageCommand)
discard channel.sendMessage("PONG") registerCommand(testEmbedCommand)
elif (event.message.content.startsWith("?modifyChannelTopic")): registerCommand(sendFileCommand)
let modifyTopic = event.message.content.substr(20) registerCommand(sendImageCommand)
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)
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):
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):
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):
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.")
embed.addField("Title", "value")
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)
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)
let splitFile = splitFile(filePath)
let fileName = splitFile.name & splitFile.ext
let file = DiscordFile(filePath: filePath, fileName: fileName)
var embed = Embed()
embed.setTitle("Image attachment test.")
embed.setImage("attachment://" & fileName)
discard channel.sendMessage("", false, embed, @[file])
) )
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) =