Merge pull request #1 from avahe-kellenberger/master
Clean-up and Nim version fix.
This commit is contained in:
commit
3216b4481f
|
@ -4,4 +4,4 @@ description = "Discord API wrapper written in Nim. Inspired by DisC++, my othe
|
|||
license = "MIT"
|
||||
srcDir = "src"
|
||||
|
||||
requires "nim >= 1.0.0", "websocket >= 0.4.0 & <= 0.4.1"
|
||||
requires "nim >= 1.2.0", "websocket >= 0.4.0 & <= 0.4.1"
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import message, member, channel, guild, discordobject, nimcordutils, httpcore, user, tables
|
||||
|
||||
type Cache* = ref object
|
||||
members*: Table[snowflake, GuildMember]
|
||||
messages*: Table[snowflake, Message]
|
||||
channels*: Table[snowflake, Channel]
|
||||
guilds*: Table[snowflake, Guild]
|
||||
members*: Table[Snowflake, GuildMember]
|
||||
messages*: Table[Snowflake, Message]
|
||||
channels*: Table[Snowflake, Channel]
|
||||
guilds*: Table[Snowflake, Guild]
|
||||
|
||||
proc getChannel*(cache: var Cache, id: snowflake): Channel =
|
||||
proc getChannel*(cache: var Cache, id: Snowflake): Channel =
|
||||
## Get a channel object from the id.
|
||||
##
|
||||
## If for some reason the channel is not in cache, it gets requested via the
|
||||
## Discord REST API.
|
||||
if (cache.channels.hasKey(id)):
|
||||
if cache.channels.hasKey(id):
|
||||
return cache.channels[id]
|
||||
|
||||
result = newChannel(sendRequest(endpoint("/channels/" & $id), HttpGet, defaultHeaders(),
|
||||
|
@ -25,12 +25,12 @@ proc getMessageChannel*(msg: Message, cache: var Cache): Channel =
|
|||
## Discord REST API.
|
||||
return cache.getChannel(msg.channelID)
|
||||
|
||||
proc getGuild*(cache: var Cache, id: snowflake): Guild =
|
||||
proc getGuild*(cache: var Cache, id: Snowflake): Guild =
|
||||
## Get a guild object from it's id.
|
||||
##
|
||||
## If for some reason the guild is not in cache, it gets requested via the
|
||||
## Discord REST API.
|
||||
if (cache.guilds.hasKey(id)):
|
||||
if cache.guilds.hasKey(id):
|
||||
return cache.guilds[id]
|
||||
|
||||
result = newGuild(sendRequest(endpoint("/guilds/" & $id), HttpGet, defaultHeaders(),
|
||||
|
@ -44,17 +44,17 @@ proc getChannelGuild*(channel: Channel, cache: var Cache): Guild =
|
|||
## Discord REST API.
|
||||
return cache.getGuild(channel.guildID)
|
||||
|
||||
proc getUser*(cache: Cache, id: snowflake): User =
|
||||
proc getUser*(cache: Cache, id: Snowflake): User =
|
||||
## Get a user object from it's id.
|
||||
##
|
||||
## If for some reason the user is not in cache, it gets requested via the
|
||||
## Discord REST API.
|
||||
if (cache.members.hasKey(id)):
|
||||
if cache.members.hasKey(id):
|
||||
return cache.members[id].user
|
||||
|
||||
return newUser(sendRequest(endpoint("/users/" & $id), HttpGet, defaultHeaders()))
|
||||
|
||||
proc cacheGuildChannel*(cache: var Cache, guildID: snowflake, channel: Channel) =
|
||||
proc cacheGuildChannel*(cache: var Cache, guildID: Snowflake, channel: Channel) =
|
||||
## Adds a channel in cache.guilds[guildID].channels.
|
||||
## Only used for internal library, dont touch!
|
||||
var guild = cache.getGuild(guildID)
|
||||
|
|
|
@ -14,21 +14,21 @@ type
|
|||
Channel* = ref object of DiscordObject
|
||||
## Discord channel object.
|
||||
`type`*: ChannelType ## The type of channel.
|
||||
guildID*: snowflake ## The id of the guild.
|
||||
guildID*: Snowflake ## The id of the guild.
|
||||
position*: int ## Sorting position of the channel.
|
||||
permissionOverwrites*: seq[Permissions] ## Explicit permission overwrites for members and roles.
|
||||
name*: string ## The name of the channel (2-100 characters).
|
||||
topic*: string ## The channel topic (0-1024 characters).
|
||||
nsfw*: bool ## Whether the channel is nsfw.
|
||||
lastMessageID*: snowflake ## The id of the last message sent in this channel (may not point to an existing or valid message).
|
||||
lastMessageID*: Snowflake ## The id of the last message sent in this channel (may not point to an existing or valid message).
|
||||
bitrate*: int ## The bitrate (in bits) of the voice channel.
|
||||
userLimit*: int ## The user limit of the voice channel.
|
||||
rateLimitPerUser*: int ## Amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission manage_messages or manage_channel, are unaffected.
|
||||
recipients*: seq[User] ## The recipients of the DM
|
||||
icon*: string ## Icon hash
|
||||
ownerID*: snowflake ## ID of the DM creator
|
||||
applicationID*: snowflake ## Application id of the group DM creator if it is bot-created
|
||||
parentID*: snowflake ## ID of the parent category for a channel
|
||||
ownerID*: Snowflake ## ID of the DM creator
|
||||
applicationID*: Snowflake ## Application id of the group DM creator if it is bot-created
|
||||
parentID*: Snowflake ## ID of the parent category for a channel
|
||||
lastPinTimestamp*: string ## When the last pinned message was pinned
|
||||
|
||||
ChannelFields* = ref object
|
||||
|
@ -41,13 +41,13 @@ type
|
|||
rateLimitPerUser*: Option[int]
|
||||
position*: Option[int]
|
||||
permissionOverwrites*: Option[seq[Permissions]] ## Explicit permission overwrites for members and roles.
|
||||
parentID*: Option[snowflake]
|
||||
parentID*: Option[Snowflake]
|
||||
nsfw*: Option[bool]
|
||||
|
||||
Invite* = object
|
||||
## Represents a code that when used, adds a user to a guild or group DM channel.
|
||||
code*: string ## The invite code (unique ID)
|
||||
guildID*: snowflake ## The guild this invite is for
|
||||
guildID*: Snowflake ## The guild this invite is for
|
||||
channel*: Channel ## The channel this invite is for
|
||||
inviter*: User ## The user who created the invite
|
||||
targetUser*: User ## The target user for this invite
|
||||
|
@ -74,39 +74,39 @@ proc newChannel*(channel: JsonNode): Channel {.inline.} =
|
|||
`type`: ChannelType(channel["type"].getInt())
|
||||
)
|
||||
|
||||
if (channel.contains("guild_id")):
|
||||
if channel.contains("guild_id"):
|
||||
chan.guildID = getIDFromJson(channel["guild_id"].getStr())
|
||||
if (channel.contains("position")):
|
||||
if channel.contains("position"):
|
||||
chan.position = channel["position"].getInt()
|
||||
if (channel.contains("permission_overwrites")):
|
||||
if channel.contains("permission_overwrites"):
|
||||
for perm in channel["permission_overwrites"]:
|
||||
chan.permissionOverwrites.add(newPermissions(perm))
|
||||
if (channel.contains("name")):
|
||||
if channel.contains("name"):
|
||||
chan.name = channel["name"].getStr()
|
||||
if (channel.contains("topic")):
|
||||
if channel.contains("topic"):
|
||||
chan.topic = channel["topic"].getStr()
|
||||
if (channel.contains("nsfw")):
|
||||
if channel.contains("nsfw"):
|
||||
chan.nsfw = channel["nsfw"].getBool()
|
||||
if (channel.contains("last_message_id")):
|
||||
if channel.contains("last_message_id"):
|
||||
chan.lastMessageID = getIDFromJson(channel["last_message_id"].getStr())
|
||||
if (channel.contains("bitrate")):
|
||||
if channel.contains("bitrate"):
|
||||
chan.bitrate = channel["bitrate"].getInt()
|
||||
if (channel.contains("user_limit")):
|
||||
if channel.contains("user_limit"):
|
||||
chan.userLimit = channel["user_limit"].getInt()
|
||||
if (channel.contains("rate_limit_per_user")):
|
||||
if channel.contains("rate_limit_per_user"):
|
||||
chan.rateLimitPerUser = channel["rate_limit_per_user"].getInt()
|
||||
if (channel.contains("recipients")):
|
||||
if channel.contains("recipients"):
|
||||
for recipient in channel["recipients"]:
|
||||
chan.recipients.insert(newUser(recipient))
|
||||
if (channel.contains("icon")):
|
||||
if channel.contains("icon"):
|
||||
chan.icon = channel["icon"].getStr()
|
||||
if (channel.contains("owner_id")):
|
||||
if channel.contains("owner_id"):
|
||||
chan.ownerID = getIDFromJson(channel["owner_id"].getStr())
|
||||
if (channel.contains("application_id")):
|
||||
if channel.contains("application_id"):
|
||||
chan.applicationID = getIDFromJson(channel["application_id"].getStr())
|
||||
if (channel.contains("parent_id")):
|
||||
if channel.contains("parent_id"):
|
||||
chan.parentID = getIDFromJson(channel["parent_id"].getStr())
|
||||
if (channel.contains("last_pin_timestamp")):
|
||||
if channel.contains("last_pin_timestamp"):
|
||||
chan.lastPinTimestamp = channel["last_pin_timestamp"].getStr()
|
||||
|
||||
return chan
|
||||
|
@ -117,23 +117,23 @@ proc newInvite*(json: JsonNode): Invite {.inline.} =
|
|||
code: json["code"].getStr(),
|
||||
channel: newChannel(json["channel"])
|
||||
)
|
||||
if (json.contains("guild")):
|
||||
if json.contains("guild"):
|
||||
invite.guildID = getIDFromJson(json["guild"]["id"].getStr())
|
||||
if (json.contains("target_user")):
|
||||
if json.contains("target_user"):
|
||||
invite.targetUser = newUser(json["target_user"])
|
||||
if (json.contains("approximate_presence_count")):
|
||||
if json.contains("approximate_presence_count"):
|
||||
invite.approximatePresenceCount = json["approximate_presence_count"].getInt()
|
||||
if (json.contains("approximate_member_count")):
|
||||
if json.contains("approximate_member_count"):
|
||||
invite.approximateMemberCount = json["approximate_member_count"].getInt()
|
||||
if (json.contains("uses")):
|
||||
if json.contains("uses"):
|
||||
invite.uses = json["uses"].getInt()
|
||||
if (json.contains("max_uses")):
|
||||
if json.contains("max_uses"):
|
||||
invite.maxUsers = json["max_uses"].getInt()
|
||||
if (json.contains("max_age")):
|
||||
if json.contains("max_age"):
|
||||
invite.maxAge = json["max_age"].getInt()
|
||||
if (json.contains("temporary")):
|
||||
if json.contains("temporary"):
|
||||
invite.temporary = json["temporary"].getBool()
|
||||
if (json.contains("created_at")):
|
||||
if json.contains("created_at"):
|
||||
invite.createdAt = json["created_at"].getStr()
|
||||
|
||||
return invite
|
||||
|
@ -142,10 +142,10 @@ proc sendMessage*(channel: Channel, content: string, tts: bool = false, embed: E
|
|||
## Send a message through the channel.
|
||||
var messagePayload = %*{"content": content, "tts": tts}
|
||||
|
||||
if (not embed.isNil()):
|
||||
if not embed.isNil():
|
||||
messagePayload.add("embed", embed.embedJson)
|
||||
|
||||
if (files.len != 0):
|
||||
if files.len != 0:
|
||||
var client = newHttpClient()
|
||||
let endpoint = endpoint("/channels/" & $channel.id & "/messages")
|
||||
var multipart = newMultipartData()
|
||||
|
@ -154,7 +154,7 @@ proc sendMessage*(channel: Channel, content: string, tts: bool = false, embed: E
|
|||
|
||||
for index, file in files:
|
||||
var imageStream = newFileStream(file.filePath, fmRead)
|
||||
if (not isNil(imageStream)):
|
||||
if not isNil(imageStream):
|
||||
let data = imageStream.readALL()
|
||||
multipart.add("file" & $index, data, file.fileName, "application/octet-stream", false)
|
||||
|
||||
|
@ -184,37 +184,37 @@ proc modifyChannel*(channel: Channel, modify: ChannelFields): Future[Channel] {.
|
|||
|
||||
var modifyPayload = %*{}
|
||||
|
||||
if (modify.name.isSome):
|
||||
if modify.name.isSome:
|
||||
modifyPayload.add("name", %modify.name.get())
|
||||
|
||||
if (modify.`type`.isSome):
|
||||
if modify.`type`.isSome:
|
||||
modifyPayload.add("type", %modify.`type`.get())
|
||||
|
||||
if (modify.position.isSome):
|
||||
if modify.position.isSome:
|
||||
modifyPayload.add("position", %modify.position.get())
|
||||
|
||||
if (modify.topic.isSome):
|
||||
if modify.topic.isSome:
|
||||
modifyPayload.add("topic", %modify.topic.get())
|
||||
|
||||
if (modify.nsfw.isSome):
|
||||
if modify.nsfw.isSome:
|
||||
modifyPayload.add("nsfw", %modify.nsfw.get())
|
||||
|
||||
if (modify.rateLimitPerUser.isSome):
|
||||
if modify.rateLimitPerUser.isSome:
|
||||
modifyPayload.add("rate_limit_per_user", %modify.rateLimitPerUser.get())
|
||||
|
||||
if (modify.bitrate.isSome):
|
||||
if modify.bitrate.isSome:
|
||||
modifyPayload.add("bitrate", %modify.bitrate.get())
|
||||
|
||||
if (modify.userLimit.isSome):
|
||||
if modify.userLimit.isSome:
|
||||
modifyPayload.add("user_limit", %modify.userLimit.get())
|
||||
|
||||
if (modify.permissionOverwrites.isSome):
|
||||
if modify.permissionOverwrites.isSome:
|
||||
var permOverwrites = parseJson("[]")
|
||||
for perm in modify.permissionOverwrites.get():
|
||||
permOverwrites.add(perm.permissionsToJson())
|
||||
modifyPayload.add("permission_overwrites", permOverwrites)
|
||||
|
||||
if (modify.parentID.isSome):
|
||||
if modify.parentID.isSome:
|
||||
modifyPayload.add("parent_id", %modify.parentID.get())
|
||||
|
||||
return newChannel(sendRequest(endpoint("/channels/" & $channel.id), HttpPatch,
|
||||
|
@ -229,9 +229,9 @@ proc deleteChannel*(channel: Channel) {.async.} =
|
|||
type MessagesGetRequest* = object
|
||||
## Use this type to get a channel's messages by setting some of the fields.
|
||||
## You can only set one of `around`, `before`, or `after`.
|
||||
around*: Option[snowflake]
|
||||
before*: Option[snowflake]
|
||||
after*: Option[snowflake]
|
||||
around*: Option[Snowflake]
|
||||
before*: Option[Snowflake]
|
||||
after*: Option[Snowflake]
|
||||
limit*: Option[int]
|
||||
|
||||
proc getMessages*(channel: Channel, request: MessagesGetRequest): seq[Message] =
|
||||
|
@ -245,24 +245,24 @@ proc getMessages*(channel: Channel, request: MessagesGetRequest): seq[Message] =
|
|||
|
||||
var url: string = endpoint("/channels/" & $channel.id & "/messages?")
|
||||
|
||||
if (request.around.isSome):
|
||||
if request.around.isSome:
|
||||
url = url & "around=" & $request.around.get()
|
||||
|
||||
# Raise some exceptions to make sure the user doesn't
|
||||
# try to set more than one of these fields
|
||||
if (request.before.isSome):
|
||||
if (request.around.isSome):
|
||||
if request.before.isSome:
|
||||
if request.around.isSome:
|
||||
raise newException(Defect, "You cannot get around and before a message! Choose one...")
|
||||
url = url & "before=" & $request.before.get()
|
||||
|
||||
if (request.after.isSome):
|
||||
if (request.around.isSome or request.before.isSome):
|
||||
if request.after.isSome:
|
||||
if request.around.isSome or request.before.isSome:
|
||||
raise newException(Defect, "You cannot get around/before and after a message! Choose one...")
|
||||
url = url & "after=" & $request.after.get()
|
||||
|
||||
if (request.limit.isSome):
|
||||
if request.limit.isSome:
|
||||
# Add the `&` for the url if something else is set.
|
||||
if (request.around.isSome or request.before.isSome or request.after.isSome):
|
||||
if request.around.isSome or request.before.isSome or request.after.isSome:
|
||||
url = url & "&"
|
||||
|
||||
url = url & "limit=" & $request.limit.get()
|
||||
|
@ -273,15 +273,15 @@ proc getMessages*(channel: Channel, request: MessagesGetRequest): seq[Message] =
|
|||
for message in response:
|
||||
result.add(newMessage(message))
|
||||
|
||||
proc getMessage*(channel: Channel, messageID: snowflake): Message =
|
||||
proc getMessage*(channel: Channel, messageID: Snowflake): Message =
|
||||
## Requests a message from the channel via the Discord REST API.
|
||||
return newMessage(sendRequest(endpoint("/channels/" & $channel.id & "/messages/" & $messageID), HttpGet,
|
||||
defaultHeaders(), channel.id, RateLimitBucketType.channel))
|
||||
|
||||
|
||||
proc bulkDeleteMessages*(channel: Channel, messageIDs: seq[snowflake]) {.async.} =
|
||||
proc bulkDeleteMessages*(channel: Channel, messageIDs: seq[Snowflake]) {.async.} =
|
||||
## Bulk delete channel messages. This endpoint can only delete 2-100 messages.
|
||||
## This proc takes a seq[snowflakes] represtenting the message's IDs.
|
||||
## This proc takes a seq[Snowflakes] represtenting the message's IDs.
|
||||
## The messages can not be older than 2 weeks!
|
||||
##
|
||||
## See also:
|
||||
|
@ -301,8 +301,8 @@ proc bulkDeleteMessages*(channel: Channel, messages: seq[Message]) {.async.} =
|
|||
## The messages can not be older than 2 weeks!
|
||||
##
|
||||
## See also:
|
||||
## * `bulkDeleteMessages(channel: Channel, messageIDs: seq[snowflake])`_
|
||||
var messageIDs: seq[snowflake]
|
||||
## * `bulkDeleteMessages(channel: Channel, messageIDs: seq[Snowflake])`_
|
||||
var messageIDs: seq[Snowflake]
|
||||
for msg in messages:
|
||||
messageIDs.add(msg.id)
|
||||
|
||||
|
@ -329,7 +329,7 @@ type CreateInviteFields* = object
|
|||
maxUses: Option[int] ## Max number of uses or 0 for unlimited
|
||||
temporary: Option[bool] ## Whether this invite only grants temporary membership
|
||||
unique: Option[bool] ## If true, don't try to reuse a similar invite (useful for creating many unique one time use invites)
|
||||
targetUser: Option[snowflake] ## The target user id for this invite
|
||||
targetUser: Option[Snowflake] ## The target user id for this invite
|
||||
targetUserType: Option[int] ## The type of target user for this invite
|
||||
|
||||
proc createChannelInvite*(channel: Channel, fields: CreateInviteFields): Invite =
|
||||
|
@ -344,18 +344,18 @@ proc createChannelInvite*(channel: Channel, fields: CreateInviteFields): Invite
|
|||
## channel.createChannelInvite(CreateInviteFields(maxAge: 3600, maxUses: 10))
|
||||
var createPayload = %*{}
|
||||
|
||||
if (fields.maxAge.isSome):
|
||||
if fields.maxAge.isSome:
|
||||
createPayload.add("max_age", %fields.maxAge.get())
|
||||
if (fields.maxUses.isSome):
|
||||
if fields.maxUses.isSome:
|
||||
createPayload.add("max_uses", %fields.maxUses.get())
|
||||
if (fields.temporary.isSome):
|
||||
if fields.temporary.isSome:
|
||||
createPayload.add("temporary", %fields.temporary.get())
|
||||
if (fields.unique.isSome):
|
||||
if fields.unique.isSome:
|
||||
createPayload.add("unique", %fields.unique.get())
|
||||
if (fields.targetUser.isSome):
|
||||
if fields.targetUser.isSome:
|
||||
createPayload.add("target_user", %fields.targetUser.get())
|
||||
# Not sure if its needed because it can only be `1`
|
||||
#[ if (fields.targetUserType.isSome):
|
||||
#[ if fields.targetUserType.isSome:
|
||||
createPayload.add("target_user_type", %fields.targetUserType.get()) ]#
|
||||
|
||||
return newInvite(sendRequest(endpoint("/channels/" & $channel.id & "/invites"), HttpPost,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import websocket, asyncdispatch, json, httpClient, eventdispatcher, strformat
|
||||
import eventhandler, streams, nimcordutils, discordobject, user, cache, clientobjects
|
||||
import strutils, channel, options, message, emoji, guild, embed, os, presence
|
||||
import nimcordutils, cache, clientobjects
|
||||
import strutils, options, presence
|
||||
|
||||
type
|
||||
DiscordOpCode = enum
|
||||
|
@ -16,10 +16,23 @@ type
|
|||
opHello = 10,
|
||||
opHeartbeatAck = 11
|
||||
|
||||
# Forward declarations
|
||||
proc closeConnection*(shard: Shard, code: int = 1000) {.async.}
|
||||
proc getIdentifyPacket(shard: Shard): JsonNode
|
||||
proc handleGatewayDisconnect(shard: Shard, error: string) {.async.}
|
||||
proc handleHeartbeat(shard: Shard) {.async.}
|
||||
proc handleWebsocketPacket(shard: Shard) {.async.}
|
||||
proc newDiscordClient*(tkn: string): DiscordClient
|
||||
proc newShard(shardID: int, client: DiscordClient): Shard
|
||||
proc reconnectShard(shard: Shard) {.async.}
|
||||
proc sendGatewayRequest*(shard: Shard, request: JsonNode, msg: string = "") {.async.}
|
||||
proc startConnection*(client: DiscordClient, shardAmount: int = 1) {.async.}
|
||||
proc updateClientPresence*(shard: Shard, presence: Presence) {.async.}
|
||||
|
||||
proc sendGatewayRequest*(shard: Shard, request: JsonNode, msg: string = "") {.async.} =
|
||||
## Send a gateway request.
|
||||
## Don't use this unless you know what you're doing!
|
||||
if (msg.len == 0):
|
||||
if msg.len == 0:
|
||||
echo "Sending gateway payload: ", request
|
||||
else:
|
||||
echo msg
|
||||
|
@ -29,7 +42,7 @@ proc sendGatewayRequest*(shard: Shard, request: JsonNode, msg: string = "") {.as
|
|||
proc handleHeartbeat(shard: Shard) {.async.} =
|
||||
while true:
|
||||
var heartbeatPayload: JsonNode
|
||||
if (shard.lastSequence == 0):
|
||||
if shard.lastSequence == 0:
|
||||
heartbeatPayload = %* { "d": nil, "op": ord(DiscordOpCode.opHeartbeat) }
|
||||
else:
|
||||
heartbeatPayload = %* { "d": shard.lastSequence, "op": ord(DiscordOpCode.opHeartbeat) }
|
||||
|
@ -53,12 +66,9 @@ proc getIdentifyPacket(shard: Shard): JsonNode =
|
|||
}
|
||||
}
|
||||
|
||||
if (shard.client.shardCount != -1):
|
||||
if shard.client.shardCount != -1:
|
||||
result.add("shard", %*[shard.id, shard.client.shardCount])
|
||||
|
||||
# For some reason this shows as an error in VSCode, but it compiles fine.
|
||||
#proc startConnection*(client: DiscordClient, shardCount: int = 1) {.async.}
|
||||
|
||||
proc closeConnection*(shard: Shard, code: int = 1000) {.async.} =
|
||||
echo "Disconnecting with code: ", code
|
||||
await shard.ws.close(code)
|
||||
|
@ -87,21 +97,20 @@ proc handleGatewayDisconnect(shard: Shard, error: string) {.async.} =
|
|||
let c = disconnectData.code
|
||||
|
||||
# 4003, 4004, 4005, 4007, 4010, 4011, 4012, 4013 are not reconnectable.
|
||||
if ( (c >= 4003 and c <= 4005) or c == 4007 or (c >= 4010 and c <= 4013) ):
|
||||
if (c >= 4003 and c <= 4005) or c == 4007 or (c >= 4010 and c <= 4013):
|
||||
echo "The Discord gateway sent a disconnect code that we cannot reconnect to."
|
||||
else:
|
||||
if (not shard.reconnecting):
|
||||
if not shard.reconnecting:
|
||||
waitFor shard.reconnectShard()
|
||||
else:
|
||||
echo "Gateway is cannot reconnect due to already reconnecting..."
|
||||
|
||||
|
||||
#TODO: Reconnecting may be done, just needs testing.
|
||||
proc handleWebsocketPacket(shard: Shard) {.async.} =
|
||||
while true:
|
||||
var packet: tuple[opcode: Opcode, data: string]
|
||||
|
||||
packet = await shard.ws.readData();
|
||||
packet = await shard.ws.readData()
|
||||
echo "[SHARD ", $shard.id, "] Received gateway payload: ", packet.data
|
||||
|
||||
if packet.opcode == Opcode.Close:
|
||||
|
@ -111,12 +120,12 @@ proc handleWebsocketPacket(shard: Shard) {.async.} =
|
|||
|
||||
# If we fail to parse the json just stop this loop
|
||||
try:
|
||||
json = parseJson(packet.data);
|
||||
json = parseJson(packet.data)
|
||||
except:
|
||||
echo "Failed to parse websocket payload: ", packet.data
|
||||
continue
|
||||
|
||||
if (json.contains("s")):
|
||||
if json.contains("s"):
|
||||
shard.lastSequence = json["s"].getInt()
|
||||
|
||||
case json["op"].getInt()
|
||||
|
@ -173,7 +182,7 @@ proc startConnection*(client: DiscordClient, shardAmount: int = 1) {.async.} =
|
|||
## .. code-block:: nim
|
||||
## var tokenStream = newFileStream("token.txt", fmRead)
|
||||
## var tkn: string
|
||||
## if (not isNil(tokenStream)):
|
||||
## if not isNil(tokenStream):
|
||||
## discard tokenStream.readLine(tkn)
|
||||
## echo "Read token from the file: ", tkn
|
||||
##
|
||||
|
@ -182,13 +191,14 @@ proc startConnection*(client: DiscordClient, shardAmount: int = 1) {.async.} =
|
|||
## var bot = newDiscordClient(tkn)
|
||||
echo "Connecting..."
|
||||
|
||||
let urlResult = sendRequest(endpoint("/gateway/bot"), HttpMethod.HttpGet, defaultHeaders())
|
||||
if (urlResult.contains("url")):
|
||||
# let urlResult = sendRequest(endpoint("/gateway/bot"), HttpMethod.HttpGet, defaultHeaders())
|
||||
let urlResult = sendRequest(endpoint("/gateway"), HttpMethod.HttpGet, defaultHeaders())
|
||||
if urlResult.contains("url"):
|
||||
let url = urlResult["url"].getStr()
|
||||
client.endpoint = url
|
||||
|
||||
var shardCount = shardAmount
|
||||
if (shardCount < urlResult["shards"].getInt()):
|
||||
if urlResult.hasKey("shards") and shardCount < urlResult["shards"].getInt():
|
||||
shardCount = urlResult["shards"].getInt()
|
||||
client.shardCount = shardCount
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
type
|
||||
snowflake* = uint64
|
||||
Snowflake* = uint64
|
||||
DiscordObject* = object of RootObj
|
||||
id*: snowflake
|
||||
id*: Snowflake
|
||||
|
||||
proc `==`*(obj1: DiscordObject, obj2: DiscordObject): bool =
|
||||
return obj1.id == obj2.id
|
|
@ -12,10 +12,10 @@ proc setTitle*(embed: var Embed, title: string) =
|
|||
##
|
||||
## Contstraints:
|
||||
## * `title` must be set and cannot be larger than 256 characters.
|
||||
if (title.len < 0 or title.len > 256):
|
||||
if title.len < 0 or title.len > 256:
|
||||
raise newException(EmbedFieldException, "Embed title can only be 0-256 characters")
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("title", %title)
|
||||
|
@ -25,17 +25,17 @@ proc setDescription*(embed: var Embed, description: string) =
|
|||
##
|
||||
## Contstraints:
|
||||
## * `description` must be set and cannot be larger than 2048 characters.
|
||||
if (description.len < 0 or description.len > 2048):
|
||||
if description.len < 0 or description.len > 2048:
|
||||
raise newException(EmbedFieldException, "Embed description can only be 0-2048 characters")
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("description", %description)
|
||||
|
||||
proc setURL*(embed: var Embed, url: string) =
|
||||
## Set the url of the embed.
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("url", %url)
|
||||
|
@ -43,14 +43,14 @@ proc setURL*(embed: var Embed, url: string) =
|
|||
proc setTimestamp*(embed: var Embed, timestamp: string) =
|
||||
## Set the timestamp of the embed.
|
||||
## The timestamp is in `ISO8601` format.
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("timestamp", %timestamp)
|
||||
|
||||
proc setColor*(embed: var Embed, color: uint) =
|
||||
## Set the color of the embed.
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("color", %color)
|
||||
|
@ -62,7 +62,7 @@ proc setFooter*(embed: var Embed, text: string, iconURL: string = "", proxyIconU
|
|||
##
|
||||
## Contstraints:
|
||||
## * `text` must be set and cannot be larger than 2048 characters.
|
||||
if (text.len < 0 or text.len > 2048):
|
||||
if text.len < 0 or text.len > 2048:
|
||||
raise newException(EmbedFieldException, "Embed's footer text can only be 0-2048 characters")
|
||||
|
||||
let footer = %* {
|
||||
|
@ -71,7 +71,7 @@ proc setFooter*(embed: var Embed, text: string, iconURL: string = "", proxyIconU
|
|||
"proxy_icon_url": proxyIconURL
|
||||
}
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("footer", footer)
|
||||
|
@ -84,12 +84,12 @@ proc setImage*(embed: var Embed, url: string, proxyIconURL: string = "", height:
|
|||
"proxy_icon_url": proxyIconURL
|
||||
}
|
||||
|
||||
if (height != -1):
|
||||
if height != -1:
|
||||
image.add("height", %height)
|
||||
if (width != -1):
|
||||
if width != -1:
|
||||
image.add("width", %width)
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("image", image)
|
||||
|
@ -102,12 +102,12 @@ proc setThumbnail*(embed: var Embed, url: string, proxyIconURL: string = "", hei
|
|||
"proxy_icon_url": proxyIconURL
|
||||
}
|
||||
|
||||
if (height != -1):
|
||||
if height != -1:
|
||||
thumbnail.add("height", %height)
|
||||
if (width != -1):
|
||||
if width != -1:
|
||||
thumbnail.add("width", %width)
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("thumbnail", thumbnail)
|
||||
|
@ -118,12 +118,12 @@ proc setVideo*(embed: var Embed, url: string, height: int = -1, width: int = -1)
|
|||
"url": url
|
||||
}
|
||||
|
||||
if (height != -1):
|
||||
if height != -1:
|
||||
video.add("height", %height)
|
||||
if (width != -1):
|
||||
if width != -1:
|
||||
video.add("width", %width)
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("video", video)
|
||||
|
@ -135,7 +135,7 @@ proc setProvider*(embed: var Embed, name: string, url: string = "") =
|
|||
"url": url
|
||||
}
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("provider", provider)
|
||||
|
@ -146,7 +146,7 @@ proc setAuthor*(embed: var Embed, name: string, url: string = "", iconURL: strin
|
|||
##
|
||||
## Contstraints:
|
||||
## * `name` cannot be larger than 256 characters
|
||||
if (name.len < 0 or name.len > 256):
|
||||
if name.len < 0 or name.len > 256:
|
||||
raise newException(EmbedFieldException, "Embed's author name can only be 0-256 characters")
|
||||
|
||||
let author = %* {
|
||||
|
@ -156,7 +156,7 @@ proc setAuthor*(embed: var Embed, name: string, url: string = "", iconURL: strin
|
|||
"proxy_icon_url": proxyIconURL
|
||||
}
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
embed.embedJson.add("author", author)
|
||||
|
@ -167,11 +167,11 @@ proc addField*(embed: var Embed, name: string, value: string, inline: bool = fal
|
|||
## Contstraints:
|
||||
## * `name` must be set and cannot be larger than 256 characters
|
||||
## * `value` must be set and cannot be larger than 1024 characters
|
||||
if (name.len == 0 or value.len == 0):
|
||||
if name.len == 0 or value.len == 0:
|
||||
raise newException(EmbedFieldException, "Embed's field name or values must be set")
|
||||
elif (name.len > 256):
|
||||
elif name.len > 256:
|
||||
raise newException(EmbedFieldException, "Embed's field name can only be 0-256 characters")
|
||||
elif (value.len > 1024):
|
||||
elif value.len > 1024:
|
||||
raise newException(EmbedFieldException, "Embed's field value can only be 0-1024 characters")
|
||||
|
||||
let field = %* {
|
||||
|
@ -180,11 +180,11 @@ proc addField*(embed: var Embed, name: string, value: string, inline: bool = fal
|
|||
"inline": inline
|
||||
}
|
||||
|
||||
if (embed.embedJson.isNil()):
|
||||
if embed.embedJson.isNil():
|
||||
embed.embedJson = %*{}
|
||||
|
||||
if embed.embedJson.contains("fields"):
|
||||
if (embed.embedJson["fields"].len > 25):
|
||||
if embed.embedJson["fields"].len > 25:
|
||||
raise newException(EmbedFieldException, "Embeds can only have upto 25 fields")
|
||||
embed.embedJson["fields"].add(field)
|
||||
else:
|
||||
|
|
|
@ -3,15 +3,15 @@ import json, discordobject, nimcordutils, user, httpcore, strutils, uri, strform
|
|||
type
|
||||
Emoji* = ref object of DiscordObject
|
||||
name*: string
|
||||
roles*: seq[snowflake]
|
||||
roles*: seq[Snowflake]
|
||||
user*: User
|
||||
requireColons*: bool
|
||||
managed*: bool
|
||||
animated*: bool
|
||||
available*: bool
|
||||
guildID*: snowflake
|
||||
guildID*: Snowflake
|
||||
|
||||
proc newEmoji*(json: JsonNode, guild: snowflake): Emoji =
|
||||
proc newEmoji*(json: JsonNode, guild: Snowflake): Emoji =
|
||||
## Construct an emoji with json.
|
||||
## This shouldn't really be used by the user, only internal use.
|
||||
result = Emoji(
|
||||
|
@ -19,23 +19,23 @@ proc newEmoji*(json: JsonNode, guild: snowflake): Emoji =
|
|||
guildID: guild
|
||||
)
|
||||
|
||||
if (json.contains("id")):
|
||||
if json.contains("id"):
|
||||
result.id = getIDFromJson(json["id"].getStr())
|
||||
if (json.contains("roles")):
|
||||
if json.contains("roles"):
|
||||
for role in json["roles"]:
|
||||
result.roles.add(getIDFromJson(role.getStr()))
|
||||
if (json.contains("user")):
|
||||
if json.contains("user"):
|
||||
result.user = newUser(json["user"])
|
||||
if (json.contains("require_colons")):
|
||||
if json.contains("require_colons"):
|
||||
result.requireColons = json["require_colons"].getBool()
|
||||
if (json.contains("managed")):
|
||||
if json.contains("managed"):
|
||||
result.managed = json["managed"].getBool()
|
||||
if (json.contains("animated")):
|
||||
if json.contains("animated"):
|
||||
result.requireColons = json["animated"].getBool()
|
||||
if (json.contains("available")):
|
||||
if json.contains("available"):
|
||||
result.requireColons = json["available"].getBool()
|
||||
|
||||
proc newEmoji*(name: string, id: snowflake): Emoji =
|
||||
proc newEmoji*(name: string, id: Snowflake): Emoji =
|
||||
## Construct an emoji using its name, and id.
|
||||
return Emoji(name: name, id: id)
|
||||
|
||||
|
@ -49,7 +49,7 @@ proc `$`*(emoji: Emoji): string =
|
|||
# Check if the emoji has a name but not id.
|
||||
# If its true, this means that the emoji is just a unicode
|
||||
# representation of the emoji.
|
||||
if (emoji.id == 0 and not emoji.name.isEmptyOrWhitespace()):
|
||||
if emoji.id == 0 and not emoji.name.isEmptyOrWhitespace():
|
||||
return emoji.name
|
||||
else:
|
||||
result = $emoji.id & ":" & emoji.name
|
||||
|
@ -61,13 +61,13 @@ proc `$`*(emoji: Emoji): string =
|
|||
proc `==`*(a: Emoji, b: Emoji): bool =
|
||||
## Check if two Emojis are equal.
|
||||
# Check if emojis have name but no id
|
||||
if (a.id == 0 and b.id == 0 and a.name.isEmptyOrWhitespace() and b.name.isEmptyOrWhitespace()):
|
||||
if a.id == 0 and b.id == 0 and a.name.isEmptyOrWhitespace() and b.name.isEmptyOrWhitespace():
|
||||
return a.name == b.name
|
||||
# Check if emoji has IDs, but no name
|
||||
elif (a.id != 0 and b.id != 0 and a.name.isEmptyOrWhitespace() and b.name.isEmptyOrWhitespace()):
|
||||
elif a.id != 0 and b.id != 0 and a.name.isEmptyOrWhitespace() and b.name.isEmptyOrWhitespace():
|
||||
return a.id == b.id
|
||||
# Check if emoji has IDs, and a name
|
||||
elif (a.id != 0 and b.id != 0 and not a.name.isEmptyOrWhitespace() and not b.name.isEmptyOrWhitespace()):
|
||||
elif a.id != 0 and b.id != 0 and not a.name.isEmptyOrWhitespace() and not b.name.isEmptyOrWhitespace():
|
||||
return $a == $b
|
||||
return false
|
||||
|
||||
|
@ -77,7 +77,7 @@ proc toUrlEncoding*(emoji: Emoji): string =
|
|||
## library use.
|
||||
return encodeUrl($emoji, true)
|
||||
|
||||
proc modifyEmoji*(emoji: var Emoji, name: string, roles: seq[snowflake] = @[]): Future[Emoji] {.async.} =
|
||||
proc modifyEmoji*(emoji: var Emoji, name: string, roles: seq[Snowflake]): Future[Emoji] {.async.} =
|
||||
## Modify the given emoji. Requires the `MANAGE_EMOJIS` permission.
|
||||
## Changes will be reflected in given `emoji`.
|
||||
var jsonBody = %* {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import eventhandler, json, tables, message, emoji, user, member, role
|
||||
import guild, channel, nimcordutils, httpClient, strformat, cache
|
||||
import sequtils, asyncdispatch, clientobjects, discordobject, presence
|
||||
import asyncdispatch, clientobjects, discordobject, presence
|
||||
|
||||
proc readyEvent(shard: Shard, json: JsonNode) =
|
||||
var readyEvent = ReadyEvent(shard: shard, readyPayload: json, name: $EventType.evtReady)
|
||||
|
@ -26,7 +26,7 @@ proc channelCreateEvent(shard: Shard, json: JsonNode) =
|
|||
let channelCreateEvent = ChannelCreateEvent(shard: shard, channel: chnl, name: $EventType.evtChannelCreate)
|
||||
|
||||
# Add the channel to its guild's `channels` field
|
||||
if (chnl.guildID != 0):
|
||||
if chnl.guildID != 0:
|
||||
shard.client.cache.cacheGuildChannel(chnl.guildID, chnl)
|
||||
shard.client.cache.channels[chnl.id] = chnl
|
||||
|
||||
|
@ -38,15 +38,15 @@ proc channelUpdateEvent(shard: Shard, json: JsonNode) =
|
|||
|
||||
shard.client.cache.channels[chnl.id] = chnl
|
||||
|
||||
if (chnl.guildID != 0):
|
||||
if chnl.guildID != 0:
|
||||
let g = shard.client.cache.getGuild(chnl.guildID)
|
||||
|
||||
var index = -1
|
||||
for i, channel in g.channels:
|
||||
if (channel.id == chnl.id):
|
||||
if channel.id == chnl.id:
|
||||
index = i
|
||||
|
||||
if (index != -1):
|
||||
if index != -1:
|
||||
g.channels[index] = chnl
|
||||
else:
|
||||
g.channels.add(chnl)
|
||||
|
@ -68,7 +68,7 @@ proc channelPinsUpdate(shard: Shard, json: JsonNode) =
|
|||
let channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
|
||||
var channel: Channel
|
||||
if (shard.client.cache.channels.hasKey(channelID)):
|
||||
if shard.client.cache.channels.hasKey(channelID):
|
||||
channel = shard.client.cache.channels[channelID]
|
||||
channel.lastPinTimestamp = json["last_pin_timestamp"].getStr()
|
||||
|
||||
|
@ -194,15 +194,15 @@ proc guildMembersChunk(shard: Shard, json: JsonNode) =
|
|||
event.chunkIndex = json["chunk_index"].getInt()
|
||||
event.chunkCount = json["chunk_count"].getInt()
|
||||
|
||||
if (json.contains("not_found")):
|
||||
if json.contains("not_found"):
|
||||
for id in json["not_found"]:
|
||||
event.notFound.add(getIDFromJson(id.getStr()))
|
||||
|
||||
if (json.contains("presences")):
|
||||
if json.contains("presences"):
|
||||
for presence in json["presences"]:
|
||||
event.presences.add(newPresence(presence))
|
||||
|
||||
if (json.contains("nonce")):
|
||||
if json.contains("nonce"):
|
||||
event.nonce = json["nonce"].getStr()
|
||||
|
||||
dispatchEvent(event)
|
||||
|
@ -252,7 +252,7 @@ proc inviteCreate(shard: Shard, json: JsonNode) =
|
|||
|
||||
invite.channel = shard.client.cache.getChannel(getIDFromJson(json["channel_id"].getStr()))
|
||||
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
invite.guildID =getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
var event = InviteCreateEvent(shard: shard, invite: invite, name: $EventType.evtInviteCreate)
|
||||
|
@ -264,7 +264,7 @@ proc inviteDelete(shard: Shard, json: JsonNode) =
|
|||
event.channel = shard.client.cache.getChannel(getIDFromJson(json["channel_id"].getStr()))
|
||||
event.code = json["code"].getStr()
|
||||
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
event.guild = shard.client.cache.getGuild(getIDFromJson(json["guild_id"].getStr()))
|
||||
|
||||
dispatchEvent(event)
|
||||
|
@ -295,7 +295,7 @@ proc messageDeleteEvent(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID)
|
||||
|
||||
msg.channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
let event = MessageDeleteEvent(shard: shard, message: msg, name: $EventType.evtMessageDelete)
|
||||
|
@ -305,7 +305,7 @@ proc messageDeleteBulkEvent(shard: Shard, json: JsonNode) =
|
|||
var event = MessageDeleteBulkEvent(shard: shard, name: $EventType.evtMessageDeleteBulk)
|
||||
|
||||
event.channel = shard.client.cache.getChannel(getIDFromJson(json["channel_id"].getStr()))
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
event.guild = shard.client.cache.getGuild(getIDFromJson(json["guild_id"].getStr()))
|
||||
|
||||
for msgIDJson in json["ids"]:
|
||||
|
@ -319,7 +319,7 @@ proc messageDeleteBulkEvent(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID, channelID: channelID)
|
||||
|
||||
event.channel = shard.client.cache.getChannel(msg.channelID)
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
event.messages.add(msg)
|
||||
|
@ -337,12 +337,12 @@ proc messageReactionAdd(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID)
|
||||
|
||||
msg.channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
event.user = shard.client.cache.getUser(getIDFromJson(json["user_id"].getStr()))
|
||||
|
||||
if (json.contains("member")):
|
||||
if json.contains("member"):
|
||||
event.member = newGuildMember(json["member"], msg.guildID)
|
||||
|
||||
event.emoji = newEmoji(json["emoji"], msg.guildID)
|
||||
|
@ -360,7 +360,7 @@ proc messageReactionRemove(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID)
|
||||
|
||||
msg.channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
event.user = shard.client.cache.getUser(getIDFromJson(json["user_id"].getStr()))
|
||||
|
@ -380,7 +380,7 @@ proc messageReactionRemoveAll(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID)
|
||||
|
||||
msg.channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
dispatchEvent(event)
|
||||
|
@ -396,7 +396,7 @@ proc messageReactionRemoveEmoji(shard: Shard, json: JsonNode) =
|
|||
msg = Message(id: msgID)
|
||||
|
||||
msg.channelID = getIDFromJson(json["channel_id"].getStr())
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
msg.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
event.emoji = newEmoji(json["emoji"], msg.guildID)
|
||||
|
@ -414,9 +414,9 @@ proc presenceUpdate(shard: Shard, json: JsonNode) =
|
|||
for role in json["roles"]:
|
||||
member.roles.add(getIDFromJson(role.getStr()))
|
||||
|
||||
if (json.contains("premium_since")):
|
||||
if json.contains("premium_since"):
|
||||
member.premiumSince = json["premium_since"].getStr()
|
||||
if (json.contains("nick")):
|
||||
if json.contains("nick"):
|
||||
member.nick = json["nick"].getStr()
|
||||
|
||||
member.presence = newPresence(json)
|
||||
|
@ -426,12 +426,12 @@ proc typingStart(shard: Shard, json: JsonNode) =
|
|||
|
||||
event.channel = shard.client.cache.getChannel(getIDFromJson(json["channel_id"].getStr()))
|
||||
|
||||
if (json.contains("guild_id")):
|
||||
if json.contains("guild_id"):
|
||||
event.channel.guildID = getIDFromJson(json["guild_id"].getStr())
|
||||
|
||||
event.user = shard.client.cache.getUser(getIDFromJson(json["user_id"].getStr()))
|
||||
|
||||
if (json.contains("member")):
|
||||
if json.contains("member"):
|
||||
event.member = newGuildMember(json["member"], event.channel.guildID)
|
||||
|
||||
dispatchEvent(event)
|
||||
|
@ -504,7 +504,7 @@ let internalEventTable: Table[string, proc(shard: Shard, json: JsonNode) {.nimca
|
|||
|
||||
proc handleDiscordEvent*(shard: Shard, json: JsonNode, eventName: string) {.async.} =
|
||||
## Handles, and dispatches, a gateway event. Only used internally.
|
||||
if (internalEventTable.hasKey(eventName)):
|
||||
if internalEventTable.hasKey(eventName):
|
||||
let eventProc: proc(shard: Shard, json: JsonNode) = internalEventTable[eventName]
|
||||
eventProc(shard, json)
|
||||
else:
|
||||
|
|
|
@ -130,7 +130,7 @@ type
|
|||
members*: seq[GuildMember]
|
||||
chunkIndex*: int
|
||||
chunkCount*: int
|
||||
notFound*: seq[snowflake]
|
||||
notFound*: seq[Snowflake]
|
||||
presences*: seq[Presence]
|
||||
nonce*: string
|
||||
|
||||
|
@ -252,7 +252,7 @@ proc registerEventListener*(event: EventType, listener: proc(event: BaseEvent))
|
|||
## echo "ID: ", bot.clientUser.id
|
||||
## echo "--------------------"
|
||||
## )
|
||||
if (eventListeners.hasKey($event)):
|
||||
if eventListeners.hasKey($event):
|
||||
eventListeners[$event].add(cast[proc(event: BaseEvent)](listener))
|
||||
|
||||
echo "Added other event listener: ", $event
|
||||
|
@ -264,7 +264,7 @@ proc registerEventListener*(event: EventType, listener: proc(event: BaseEvent))
|
|||
|
||||
proc dispatchEvent*[T: BaseEvent](event: T) =
|
||||
## Dispatches an event so something can listen to it.
|
||||
if (eventListeners.hasKey(event.name)):
|
||||
if eventListeners.hasKey(event.name):
|
||||
let listeners = eventListeners[event.name]
|
||||
echo "Dispatching event: ", event.name
|
||||
for index, eventListener in listeners.pairs:
|
||||
|
|
|
@ -53,9 +53,9 @@ type
|
|||
|
||||
VoiceState* = ref object
|
||||
## Used to represent a user's voice connection status
|
||||
guildID*: snowflake
|
||||
channelID*: snowflake
|
||||
userID*: snowflake
|
||||
guildID*: Snowflake
|
||||
channelID*: Snowflake
|
||||
userID*: Snowflake
|
||||
member*: GuildMember
|
||||
sessionID*: string
|
||||
deaf*: bool
|
||||
|
@ -72,10 +72,10 @@ type
|
|||
splash*: string
|
||||
discoverySplash*: string
|
||||
owner*: bool
|
||||
ownerID: snowflake
|
||||
ownerID: Snowflake
|
||||
permissions*: Permissions
|
||||
region*: string
|
||||
afkChannelID*: snowflake
|
||||
afkChannelID*: Snowflake
|
||||
afkTimeout*: int
|
||||
verificationLevel*: VerificationLevel
|
||||
defaultMessageNotifications*: MessageNotificationsLevel
|
||||
|
@ -84,12 +84,12 @@ type
|
|||
emojis*: seq[Emoji]
|
||||
features*: seq[string]
|
||||
mfaLevel*: MFALevel
|
||||
applicationID*: snowflake
|
||||
applicationID*: Snowflake
|
||||
widgetEnabled*: bool
|
||||
widgetChannelID*: snowflake
|
||||
systemChannelID*: snowflake
|
||||
widgetChannelID*: Snowflake
|
||||
systemChannelID*: Snowflake
|
||||
systemChannelFlags*: int
|
||||
rulesChannelID*: snowflake
|
||||
rulesChannelID*: Snowflake
|
||||
joinedAt*: string
|
||||
large*: bool
|
||||
unavailable*: bool
|
||||
|
@ -106,7 +106,7 @@ type
|
|||
premiumTier*: PremiumTier
|
||||
premiumSubscriptionCount*: int
|
||||
preferredLocale*: string
|
||||
publicUpdatesChannelID*: snowflake
|
||||
publicUpdatesChannelID*: Snowflake
|
||||
maxVideoChannelUsers*: int
|
||||
approximateMemberCount*: int
|
||||
approximatePresenceCount*: int
|
||||
|
@ -150,7 +150,7 @@ type
|
|||
`type`*: string ## Integration type (twitch, youtube, etc)
|
||||
enabled*: bool
|
||||
syncing*: bool
|
||||
roleID*: snowflake
|
||||
roleID*: Snowflake
|
||||
enableEmoticons*: bool
|
||||
expireBehavior*: IntegrationExpireBehavior
|
||||
expireGracePeriod*: int
|
||||
|
@ -160,7 +160,7 @@ type
|
|||
|
||||
GuildWidget* = ref object
|
||||
enabled*: bool
|
||||
channelID*: snowflake
|
||||
channelID*: Snowflake
|
||||
|
||||
GuildWidgetStyle* = enum
|
||||
guildWidgetStyleShield = "shield",
|
||||
|
@ -199,9 +199,9 @@ proc newGuild*(json: JsonNode): Guild {.inline.} =
|
|||
)
|
||||
|
||||
# Parse all non guaranteed fields
|
||||
if (json.contains("owner")):
|
||||
if json.contains("owner"):
|
||||
g.owner = json["owner"].getBool()
|
||||
if (json.contains("permissions")):
|
||||
if json.contains("permissions"):
|
||||
g.permissions = newPermissions(json["permissions"])
|
||||
for role in json["roles"]:
|
||||
g.roles.add(newRole(role, g.id))
|
||||
|
@ -209,17 +209,17 @@ proc newGuild*(json: JsonNode): Guild {.inline.} =
|
|||
g.emojis.add(newEmoji(emoji, g.id))
|
||||
for feature in json["features"]:
|
||||
g.features.add(feature.getStr())
|
||||
if (json.contains("widget_enabled")):
|
||||
if json.contains("widget_enabled"):
|
||||
g.widgetEnabled = json["widget_enabled"].getBool()
|
||||
if (json.contains("widget_channel_id")):
|
||||
if json.contains("widget_channel_id"):
|
||||
g.widgetChannelID = getIDFromJson(json["widget_channel_id"].getStr())
|
||||
if (json.contains("large")):
|
||||
if json.contains("large"):
|
||||
g.large = json["large"].getBool()
|
||||
if (json.contains("unavailable")):
|
||||
if json.contains("unavailable"):
|
||||
g.unavailable = json["unavailable"].getBool()
|
||||
if (json.contains("member_count")):
|
||||
if json.contains("member_count"):
|
||||
g.memberCount = json["member_count"].getInt()
|
||||
if (json.contains("voice_states")):
|
||||
if json.contains("voice_states"):
|
||||
for voicestate in json["voice_states"]:
|
||||
var state = VoiceState(
|
||||
guildID: g.id,
|
||||
|
@ -234,47 +234,47 @@ proc newGuild*(json: JsonNode): Guild {.inline.} =
|
|||
suppress: voicestate["suppress"].getBool()
|
||||
)
|
||||
|
||||
if (voicestate.contains("member")):
|
||||
if voicestate.contains("member"):
|
||||
state.member = newGuildMember(voicestate["member"], g.id)
|
||||
|
||||
g.voiceStates.add(state)
|
||||
if (json.contains("members")):
|
||||
if json.contains("members"):
|
||||
for member in json["members"]:
|
||||
g.members.insert(newGuildMember(member, g.id))
|
||||
if (json.contains("channels")):
|
||||
if json.contains("channels"):
|
||||
for channel in json["channels"]:
|
||||
g.channels.insert(newChannel(channel))
|
||||
if (json.contains("presences")):
|
||||
if json.contains("presences"):
|
||||
# Parse all presences
|
||||
var tmpPresences = initTable[snowflake, Presence]()
|
||||
var tmpPresences = initTable[Snowflake, Presence]()
|
||||
for presence in json["presences"]:
|
||||
tmpPresences.add(getIDFromJson(presence["user"]["id"].getStr()), newPresence(presence))
|
||||
|
||||
# Check if the `tmpPresences` variable has a presence for the member,
|
||||
# if it does, then update the member to include its presence.
|
||||
for member in g.members:
|
||||
if (tmpPresences.hasKey(member.user.id)):
|
||||
if tmpPresences.hasKey(member.user.id):
|
||||
member.presence = tmpPresences[member.user.id]
|
||||
|
||||
if (json.contains("max_presences")):
|
||||
if json.contains("max_presences"):
|
||||
g.maxPresences = json["max_presences"].getInt()
|
||||
if (json.contains("max_members")):
|
||||
if json.contains("max_members"):
|
||||
g.maxMembers = json["max_members"].getInt()
|
||||
if (json.contains("premium_subscription_count")):
|
||||
if json.contains("premium_subscription_count"):
|
||||
g.premiumSubscriptionCount = json["premium_subscription_count"].getInt()
|
||||
if (json.contains("max_video_channel_users")):
|
||||
if json.contains("max_video_channel_users"):
|
||||
g.maxVideoChannelUsers = json["max_video_channel_users"].getInt()
|
||||
if (json.contains("approximate_member_count")):
|
||||
if json.contains("approximate_member_count"):
|
||||
g.approximateMemberCount = json["approximate_member_count"].getInt()
|
||||
if (json.contains("approximate_presence_count")):
|
||||
if json.contains("approximate_presence_count"):
|
||||
g.approximatePresenceCount = json["approximate_presence_count"].getInt()
|
||||
|
||||
return g
|
||||
|
||||
proc createGuild*(name: string, region: Option[string], icon: Option[string], verificationLevel: Option[VerificationLevel],
|
||||
defaultMessageNotifications: Option[MessageNotificationsLevel], explicitContentFilter: Option[ExplicitContentFilterLevel],
|
||||
roles: Option[seq[Role]], channels: Option[seq[Channel]], afkChannelID: Option[snowflake], afkTimeout: Option[int],
|
||||
systemChannelID: Option[snowflake]): Guild =
|
||||
roles: Option[seq[Role]], channels: Option[seq[Channel]], afkChannelID: Option[Snowflake], afkTimeout: Option[int],
|
||||
systemChannelID: Option[Snowflake]): Guild =
|
||||
## Create a new guild.
|
||||
##
|
||||
## Some restraints/notes for this endpoint:
|
||||
|
@ -296,17 +296,17 @@ proc createGuild*(name: string, region: Option[string], icon: Option[string], ve
|
|||
|
||||
var json = %* {"name": name}
|
||||
|
||||
if (region.isSome):
|
||||
if region.isSome:
|
||||
json.add("region", %region.get())
|
||||
if (icon.isSome):
|
||||
if icon.isSome:
|
||||
json.add("icon", %icon.get())
|
||||
if (verificationLevel.isSome):
|
||||
if verificationLevel.isSome:
|
||||
json.add("verification_level", %ord(verificationLevel.get()))
|
||||
if (defaultMessageNotifications.isSome):
|
||||
if defaultMessageNotifications.isSome:
|
||||
json.add("default_message_notifications", %ord(defaultMessageNotifications.get()))
|
||||
if (explicitContentFilter.isSome):
|
||||
if explicitContentFilter.isSome:
|
||||
json.add("explicit_content_filter", %ord(explicitContentFilter.get()))
|
||||
if (roles.isSome):
|
||||
if roles.isSome:
|
||||
#json.add("verification_level", %ord(verificationLevel.get()))
|
||||
var rolesJson = parseJson("[]")
|
||||
for role in roles.get():
|
||||
|
@ -322,7 +322,7 @@ proc createGuild*(name: string, region: Option[string], icon: Option[string], ve
|
|||
rolesJson.add(roleJson)
|
||||
|
||||
json.add("channels", rolesJson)
|
||||
if (channels.isSome):
|
||||
if channels.isSome:
|
||||
var channelsJson = parseJson("[]")
|
||||
for channel in channels.get():
|
||||
var channelJson = %*{
|
||||
|
@ -336,7 +336,7 @@ proc createGuild*(name: string, region: Option[string], icon: Option[string], ve
|
|||
"parent_id": channel.parentID
|
||||
}
|
||||
|
||||
if (channel.permissionOverwrites.len != 0):
|
||||
if channel.permissionOverwrites.len != 0:
|
||||
channelsJson.add("permission_overwrites", parseJson("[]"))
|
||||
for permOverwrite in channel.permissionOverwrites:
|
||||
channelsJson["permission_overwrites"].add(permOverwrite.permissionsToJson())
|
||||
|
@ -344,11 +344,11 @@ proc createGuild*(name: string, region: Option[string], icon: Option[string], ve
|
|||
channelsJson.add(channelJson)
|
||||
|
||||
json.add("channels", channelsJson)
|
||||
if (afkChannelID.isSome):
|
||||
if afkChannelID.isSome:
|
||||
json.add("afk_channel_id", %ord(afkChannelID.get()))
|
||||
if (afkTimeout.isSome):
|
||||
if afkTimeout.isSome:
|
||||
json.add("afk_timeout", %ord(afkTimeout.get()))
|
||||
if (systemChannelID.isSome):
|
||||
if systemChannelID.isSome:
|
||||
json.add("system_channel_id", %ord(systemChannelID.get()))
|
||||
|
||||
return newGuild(sendRequest(endpoint("/guilds"), HttpPost,
|
||||
|
@ -386,15 +386,15 @@ type GuildModify* = ref object
|
|||
verificationLevel*: Option[VerificationLevel]
|
||||
defaultMessageNotifications*: Option[MessageNotificationsLevel]
|
||||
explicitContentFilter*: Option[ExplicitContentFilterLevel]
|
||||
afkChannelID*: Option[snowflake]
|
||||
afkChannelID*: Option[Snowflake]
|
||||
afkTimeout*: Option[int]
|
||||
icon*: Option[Image]
|
||||
ownerID*: Option[snowflake]
|
||||
ownerID*: Option[Snowflake]
|
||||
splash*: Option[Image]
|
||||
banner*: Option[Image]
|
||||
systemChannelID*: Option[snowflake]
|
||||
rulesChannelID*: Option[snowflake]
|
||||
publicUpdatesChannelID*: Option[snowflake]
|
||||
systemChannelID*: Option[Snowflake]
|
||||
rulesChannelID*: Option[Snowflake]
|
||||
publicUpdatesChannelID*: Option[Snowflake]
|
||||
preferredLocale*: Option[string]
|
||||
|
||||
proc modifyGuild*(guild: Guild, modify: GuildModify): Future[Guild] {.async.} =
|
||||
|
@ -408,49 +408,49 @@ proc modifyGuild*(guild: Guild, modify: GuildModify): Future[Guild] {.async.} =
|
|||
|
||||
var modifyPayload = %*{}
|
||||
|
||||
if (modify.name.isSome):
|
||||
if modify.name.isSome:
|
||||
modifyPayload.add("name", %modify.name.get())
|
||||
|
||||
if (modify.region.isSome):
|
||||
if modify.region.isSome:
|
||||
modifyPayload.add("region", %modify.region.get())
|
||||
|
||||
if (modify.verificationLevel.isSome):
|
||||
if modify.verificationLevel.isSome:
|
||||
modifyPayload.add("verification_level", %modify.verificationLevel.get())
|
||||
|
||||
if (modify.defaultMessageNotifications.isSome):
|
||||
if modify.defaultMessageNotifications.isSome:
|
||||
modifyPayload.add("default_message_notifications", %modify.defaultMessageNotifications.get())
|
||||
|
||||
if (modify.explicitContentFilter.isSome):
|
||||
if modify.explicitContentFilter.isSome:
|
||||
modifyPayload.add("explicit_content_filter", %modify.explicitContentFilter.get())
|
||||
|
||||
if (modify.afkChannelID.isSome):
|
||||
if modify.afkChannelID.isSome:
|
||||
modifyPayload.add("afk_channel_id", %modify.afkChannelID.get())
|
||||
|
||||
if (modify.afkTimeout.isSome):
|
||||
if modify.afkTimeout.isSome:
|
||||
modifyPayload.add("afk_timeout", %modify.afkTimeout.get())
|
||||
|
||||
if (modify.icon.isSome):
|
||||
if modify.icon.isSome:
|
||||
modifyPayload.add("icon", %modify.icon.get().imageToDataURI())
|
||||
|
||||
if (modify.ownerID.isSome):
|
||||
if modify.ownerID.isSome:
|
||||
modifyPayload.add("owner_id", %modify.ownerID.get())
|
||||
|
||||
if (modify.splash.isSome):
|
||||
if modify.splash.isSome:
|
||||
modifyPayload.add("splash", %modify.splash.get().imageToDataURI())
|
||||
|
||||
if (modify.banner.isSome):
|
||||
if modify.banner.isSome:
|
||||
modifyPayload.add("banner", %modify.banner.get().imageToDataURI())
|
||||
|
||||
if (modify.systemChannelID.isSome):
|
||||
if modify.systemChannelID.isSome:
|
||||
modifyPayload.add("system_channel_id", %modify.systemChannelID.get())
|
||||
|
||||
if (modify.rulesChannelID.isSome):
|
||||
if modify.rulesChannelID.isSome:
|
||||
modifyPayload.add("rules_channel_id", %modify.rulesChannelID.get())
|
||||
|
||||
if (modify.publicUpdatesChannelID.isSome):
|
||||
if modify.publicUpdatesChannelID.isSome:
|
||||
modifyPayload.add("public_updates_channel_id", %modify.publicUpdatesChannelID.get())
|
||||
|
||||
if (modify.preferredLocale.isSome):
|
||||
if modify.preferredLocale.isSome:
|
||||
modifyPayload.add("preferred_locale", %modify.preferredLocale.get())
|
||||
|
||||
return newGuild(sendRequest(endpoint("/guilds/" & $guild.id), HttpPatch,
|
||||
|
@ -488,33 +488,33 @@ proc createGuildChannel*(guild: var Guild, create: ChannelFields): Future[Channe
|
|||
var createPayload = %*{}
|
||||
|
||||
# Make sure that the name is supplied since its required for this endpoint.
|
||||
if (create.name.isSome):
|
||||
if create.name.isSome:
|
||||
createPayload.add("name", %create.name.get())
|
||||
else:
|
||||
raise newException(Defect, "You must have a channel name when creating it!")
|
||||
|
||||
if (create.`type`.isSome):
|
||||
if create.`type`.isSome:
|
||||
createPayload.add("type", %create.`type`.get())
|
||||
|
||||
if (create.position.isSome):
|
||||
if create.position.isSome:
|
||||
createPayload.add("position", %create.position.get())
|
||||
|
||||
if (create.topic.isSome):
|
||||
if create.topic.isSome:
|
||||
createPayload.add("topic", %create.topic.get())
|
||||
|
||||
if (create.nsfw.isSome):
|
||||
if create.nsfw.isSome:
|
||||
createPayload.add("nsfw", %create.nsfw.get())
|
||||
|
||||
if (create.rateLimitPerUser.isSome):
|
||||
if create.rateLimitPerUser.isSome:
|
||||
createPayload.add("rate_limit_per_user", %create.rateLimitPerUser.get())
|
||||
|
||||
if (create.bitrate.isSome):
|
||||
if create.bitrate.isSome:
|
||||
createPayload.add("bitrate", %create.bitrate.get())
|
||||
|
||||
if (create.userLimit.isSome):
|
||||
if create.userLimit.isSome:
|
||||
createPayload.add("user_limit", %create.userLimit.get())
|
||||
|
||||
if (create.permissionOverwrites.isSome):
|
||||
if create.permissionOverwrites.isSome:
|
||||
var permOverwrites = parseJson("[]")
|
||||
for perm in create.permissionOverwrites.get():
|
||||
permOverwrites.add(perm.permissionsToJson())
|
||||
|
@ -536,7 +536,7 @@ proc modifyGuildChannelPositions*(guild: var Guild, channels: seq[Channel]) {.as
|
|||
defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})),
|
||||
guild.id, RateLimitBucketType.guild, jsonBody)
|
||||
|
||||
proc getGuildMember*(guild: var Guild, memberID: snowflake): GuildMember =
|
||||
proc getGuildMember*(guild: var Guild, memberID: Snowflake): GuildMember =
|
||||
## Get a guild member.
|
||||
## This first checks `guild.members`, but if it doesn't exist there,
|
||||
## it will be requested from Discord's REST API.
|
||||
|
@ -544,7 +544,7 @@ proc getGuildMember*(guild: var Guild, memberID: snowflake): GuildMember =
|
|||
## If we end up requesting one, it will add it to `guild.members`
|
||||
|
||||
for member in guild.members:
|
||||
if (member.id == memberID):
|
||||
if member.id == memberID:
|
||||
return member
|
||||
|
||||
result = newGuildMember(sendRequest(endpoint(fmt("/guilds/{guild.id}/members/{memberID}")),
|
||||
|
@ -576,7 +576,7 @@ proc getGuildBans*(guild: Guild): seq[GuildBan] =
|
|||
user: newUser(json["user"])
|
||||
))
|
||||
|
||||
proc getGuildBan*(guild: Guild, userID: snowflake): GuildBan =
|
||||
proc getGuildBan*(guild: Guild, userID: Snowflake): GuildBan =
|
||||
## Returns a ban object for the given user or nil if the ban cannot be found.
|
||||
## Requires the BAN_MEMBERS permission.
|
||||
let response = sendRequest(endpoint(fmt("/guilds/{guild.id}/bans{userID}")), HttpGet,
|
||||
|
@ -590,22 +590,22 @@ proc getGuildBan*(guild: Guild, userID: snowflake): GuildBan =
|
|||
else:
|
||||
return nil
|
||||
|
||||
proc banGuildMember*(guild: Guild, userID: snowflake, reason: Option[string] = none(string), deleteMessageDays: Option[int] = none(int)) {.async.} =
|
||||
proc banGuildMember*(guild: Guild, userID: Snowflake, reason: Option[string] = none(string), deleteMessageDays: Option[int] = none(int)) {.async.} =
|
||||
## Create a guild ban, and optionally delete previous messages sent by the
|
||||
## banned user. Requires the BAN_MEMBERS permission.
|
||||
|
||||
var jsonBody: JsonNode
|
||||
|
||||
if (reason.isSome):
|
||||
if reason.isSome:
|
||||
jsonBody.add("reason", %reason.get())
|
||||
if (deleteMessageDays.isSome):
|
||||
if deleteMessageDays.isSome:
|
||||
jsonBody.add("deleteMessageDays", %deleteMessageDays.get())
|
||||
|
||||
discard sendRequest(endpoint(fmt("/guilds/{guild.id}/bans/{userID}")), HttpPut,
|
||||
defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})),
|
||||
guild.id, RateLimitBucketType.guild, jsonBody)
|
||||
|
||||
proc unbanGuildMember*(guild: Guild, userID: snowflake) {.async.} =
|
||||
proc unbanGuildMember*(guild: Guild, userID: Snowflake) {.async.} =
|
||||
## Remove the ban for a user. Requires the BAN_MEMBERS permissions.
|
||||
discard sendRequest(endpoint(fmt("/guilds/{guild.id}/bans/{userID}")), HttpDelete,
|
||||
defaultHeaders(), guild.id, RateLimitBucketType.guild)
|
||||
|
@ -634,19 +634,19 @@ proc createGuildRole*(guild: Guild, name: Option[string] = none(string), permiss
|
|||
|
||||
var jsonBody: JsonNode
|
||||
|
||||
if (name.isSome):
|
||||
if name.isSome:
|
||||
jsonBody.add("name", %name)
|
||||
|
||||
if (permissions.isSome):
|
||||
if permissions.isSome:
|
||||
jsonBody.add("permissions", %permissions.get().allowPerms)
|
||||
|
||||
if (color.isSome):
|
||||
if color.isSome:
|
||||
jsonBody.add("color", %color)
|
||||
|
||||
if (hoist.isSome):
|
||||
if hoist.isSome:
|
||||
jsonBody.add("hoist", %hoist)
|
||||
|
||||
if (mentionable.isSome):
|
||||
if mentionable.isSome:
|
||||
jsonBody.add("mentionable", %mentionable)
|
||||
|
||||
return newRole(sendRequest(endpoint(fmt("/guilds/{guild.id}/roles")), HttpPost,
|
||||
|
@ -665,7 +665,7 @@ proc modifyGuildRolePositions*(guild: var Guild, roles: seq[Role]) {.async.} =
|
|||
defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})),
|
||||
guild.id, RateLimitBucketType.guild, jsonBody)
|
||||
|
||||
proc getGuildPruneCount*(guild: Guild, days: int = 7, includedRoles: seq[snowflake] = @[]): int =
|
||||
proc getGuildPruneCount*(guild: Guild, days: int = 7, includedRoles: seq[Snowflake]): int =
|
||||
## Returns the number of members that would be removed in a prune operation.
|
||||
## Requires the `KICK_MEMBERS` permission.
|
||||
##
|
||||
|
@ -687,7 +687,7 @@ proc getGuildPruneCount*(guild: Guild, days: int = 7, includedRoles: seq[snowfla
|
|||
let jsonBody = sendRequest(url, HttpGet, defaultHeaders(), guild.id, RateLimitBucketType.guild)
|
||||
return jsonBody["pruned"].getInt()
|
||||
|
||||
proc beginGuildPrune*(guild: Guild, days: int = 7, computePruneCount: bool = false, includedRoles: seq[snowflake] = @[]): Future[Option[int]] {.async.} =
|
||||
proc beginGuildPrune*(guild: Guild, days: int = 7, computePruneCount: bool = false, includedRoles: seq[Snowflake]): Future[Option[int]] {.async.} =
|
||||
## Returns the number of members that would be removed in a prune operation.
|
||||
## Requires the `KICK_MEMBERS` permission.
|
||||
##
|
||||
|
@ -792,15 +792,15 @@ proc modifyGuildIntegration*(guild: Guild, integration: var Integration,
|
|||
## discard integration.modifyGuildIntegration(enable_emoticons = true)
|
||||
var modifyPayload = %*{}
|
||||
|
||||
if (expireBehavior.isSome):
|
||||
if expireBehavior.isSome:
|
||||
modifyPayload.add("expire_behavior", %expireBehavior.get())
|
||||
integration.expireBehavior = (expireBehavior.get())
|
||||
|
||||
if (expireGracePeriod.isSome):
|
||||
if expireGracePeriod.isSome:
|
||||
modifyPayload.add("expire_grace_period", %expireGracePeriod.get())
|
||||
integration.expireGracePeriod = expireGracePeriod.get()
|
||||
|
||||
if (enableEmoticons.isSome):
|
||||
if enableEmoticons.isSome:
|
||||
modifyPayload.add("enable_emoticons", %enableEmoticons.get())
|
||||
integration.enableEmoticons = enableEmoticons.get()
|
||||
|
||||
|
@ -827,7 +827,7 @@ proc getGuildWidget*(guild: Guild): GuildWidget =
|
|||
return GuildWidget(enabled: jsonBody["enabled"].getBool(),
|
||||
channelID: getIDFromJson(jsonBody{"channel_id"}.getStr()))
|
||||
|
||||
proc modifyGuildWidget*(guild: Guild, widget: var GuildWidget, enabled: bool, channelID: snowflake) {.async.} =
|
||||
proc modifyGuildWidget*(guild: Guild, widget: var GuildWidget, enabled: bool, channelID: Snowflake) {.async.} =
|
||||
## Modify a guild widget object for the guild. Requires the `MANAGE_GUILD` permission.
|
||||
widget.enabled = enabled
|
||||
widget.channelID = channelID
|
||||
|
@ -863,16 +863,16 @@ proc getGuildWidgetImage*(guild: Guild, style: GuildWidgetStyle): string =
|
|||
## and a "JOIN MY SERVER" button at the bottom. [Example](https://discord.com/api/guilds/81384788765712384/widget.png?style=banner4)
|
||||
result = fmt("guilds/{guild.id}/widget.png")
|
||||
|
||||
case (style)
|
||||
of (GuildWidgetStyle.guildWidgetStyleShield):
|
||||
case style
|
||||
of GuildWidgetStyle.guildWidgetStyleShield:
|
||||
result &= "?style=shield"
|
||||
of (GuildWidgetStyle.guildWidgetStyleBanner1):
|
||||
of GuildWidgetStyle.guildWidgetStyleBanner1:
|
||||
result &= "?style=banner1"
|
||||
of (GuildWidgetStyle.guildWidgetStyleBanner2):
|
||||
of GuildWidgetStyle.guildWidgetStyleBanner2:
|
||||
result &= "?style=banner2"
|
||||
of (GuildWidgetStyle.guildWidgetStyleBanner3):
|
||||
of GuildWidgetStyle.guildWidgetStyleBanner3:
|
||||
result &= "?style=banner3"
|
||||
of (GuildWidgetStyle.guildWidgetStyleBanner4):
|
||||
of GuildWidgetStyle.guildWidgetStyleBanner4:
|
||||
result &= "?style=banner4"
|
||||
|
||||
proc requestEmojis*(guild: Guild): seq[Emoji] =
|
||||
|
@ -887,7 +887,7 @@ proc requestEmojis*(guild: Guild): seq[Emoji] =
|
|||
result.add(newEmoji(emoji, guild.id))
|
||||
guild.emojis = result
|
||||
|
||||
proc getEmoji*(guild: Guild, emojiID: snowflake): Emoji =
|
||||
proc getEmoji*(guild: Guild, emojiID: Snowflake): Emoji =
|
||||
## Returns a guild's emoji with `emojiID`.
|
||||
## If the emoji isn't found in `guild.emojis` then it will request on
|
||||
## from the Discord REST API.
|
||||
|
@ -898,7 +898,7 @@ proc getEmoji*(guild: Guild, emojiID: snowflake): Emoji =
|
|||
return newEmoji(sendRequest(endpoint("/guilds/{guild.id}/emojis/{emojiID}"), HttpGet,
|
||||
defaultHeaders(), guild.id, RateLimitBucketType.guild), guild.id)
|
||||
|
||||
proc createEmoji*(guild: Guild, name: string, image: Image, roles: seq[snowflake] = @[]): Future[Emoji] {.async.} =
|
||||
proc createEmoji*(guild: Guild, name: string, image: Image, roles: seq[Snowflake]): Future[Emoji] {.async.} =
|
||||
## Create a new emoji for the guild. Requires the `MANAGE_EMOJIS` permission.
|
||||
var jsonBody = %* {
|
||||
"name": name,
|
||||
|
@ -914,5 +914,5 @@ proc createEmoji*(guild: Guild, name: string, image: Image, roles: seq[snowflake
|
|||
proc getGuildMemberRoles*(guild: Guild, member: GuildMember): seq[Role] =
|
||||
## Get the role objects for a member's roles.
|
||||
for role in guild.roles:
|
||||
if (member.roles.contains(role.id)):
|
||||
if member.roles.contains(role.id):
|
||||
result.add(role)
|
|
@ -9,7 +9,7 @@ proc newImage*(filepath: string): Image =
|
|||
## Reads from a file that exists at `filepath`. It reads the image data,
|
||||
## and image extension for later use.
|
||||
var imageStream = newFileStream(filepath, fmRead)
|
||||
if (not isNil(imageStream)):
|
||||
if not isNil(imageStream):
|
||||
let data = imageStream.readALL()
|
||||
|
||||
# Get the file's extension and remove the `.` from the start of it
|
||||
|
|
|
@ -25,7 +25,7 @@ proc newLog*(flags: int, filePath: string = ""): Log =
|
|||
var log = Log(flags: flags)
|
||||
if filePath.len > 0:
|
||||
log.logFile = newFileStream(filePath, fmWrite)
|
||||
if (isNil(log.logFile)):
|
||||
if isNil(log.logFile):
|
||||
raise newException(IOError, "Failed to open log file: " & filePath)
|
||||
|
||||
return log
|
||||
|
@ -38,18 +38,18 @@ proc canLog(log: Log, sev: LogSeverity): bool =
|
|||
elif (log.flags and int(LoggerFlags.loggerFlagDebugSeverity)) == int(LoggerFlags.loggerFlagDebugSeverity):
|
||||
return true
|
||||
|
||||
case (sev)
|
||||
case sev
|
||||
of LogSeverity.logSevInfo:
|
||||
return (log.flags and int(LoggerFlags.loggerFlagInfoSeverity)) == int(LoggerFlags.loggerFlagInfoSeverity);
|
||||
return (log.flags and int(LoggerFlags.loggerFlagInfoSeverity)) == int(LoggerFlags.loggerFlagInfoSeverity)
|
||||
of LogSeverity.logSevWarn:
|
||||
return (log.flags and int(LoggerFlags.loggerFlagWarnSeverity)) == int(LoggerFlags.loggerFlagWarnSeverity);
|
||||
return (log.flags and int(LoggerFlags.loggerFlagWarnSeverity)) == int(LoggerFlags.loggerFlagWarnSeverity)
|
||||
of LogSeverity.logSevError:
|
||||
return (log.flags and int(LoggerFlags.loggerFlagErrorSeverity)) == int(LoggerFlags.loggerFlagErrorSeverity);
|
||||
return (log.flags and int(LoggerFlags.loggerFlagErrorSeverity)) == int(LoggerFlags.loggerFlagErrorSeverity)
|
||||
else:
|
||||
return false;
|
||||
return false
|
||||
|
||||
proc severityToString(sev: LogSeverity): string =
|
||||
case (sev)
|
||||
case sev
|
||||
of LogSeverity.logSevInfo:
|
||||
return "INFO"
|
||||
of LogSeverity.logSevWarn:
|
||||
|
@ -61,7 +61,7 @@ proc severityToString(sev: LogSeverity): string =
|
|||
|
||||
#TODO: Remove colors from file.
|
||||
template autoLog(log: Log, sev: LogSeverity, args: varargs[untyped]) =
|
||||
if (log.canLog(sev)):
|
||||
if log.canLog(sev):
|
||||
let timeFormated = getTime().format("[HH:mm:ss]")
|
||||
let sevStr = "[" & severityToString(sev) & "]"
|
||||
|
||||
|
@ -69,7 +69,7 @@ template autoLog(log: Log, sev: LogSeverity, args: varargs[untyped]) =
|
|||
|
||||
terminal.styledEcho(logHeader, args)
|
||||
|
||||
if (log.logFile != nil):
|
||||
if log.logFile != nil:
|
||||
log.logFile.writeLine(logHeader, args)
|
||||
|
||||
template debug*(log: Log, args: varargs[untyped]) =
|
||||
|
@ -90,6 +90,6 @@ template info*(log: Log, args: varargs[untyped]) =
|
|||
|
||||
proc closeLog*(log: Log) =
|
||||
## Close log file if it was ever open.
|
||||
if (log.logFile != nil):
|
||||
if log.logFile != nil:
|
||||
log.info(fgYellow, "Closing log...")
|
||||
log.logFile.close()
|
|
@ -1,18 +1,18 @@
|
|||
import discordobject, user, json, role, options, asyncdispatch, nimcordutils, httpcore, strformat, strutils, presence
|
||||
import discordobject, user, json, options, asyncdispatch, nimcordutils, httpcore, strformat, strutils, presence
|
||||
|
||||
type GuildMember* = ref object of DiscordObject
|
||||
## This type is a guild member.
|
||||
user*: User ## The user this guild member represents.
|
||||
nick*: string ## This users guild nickname.
|
||||
roles*: seq[snowflake] ## Array of roles.
|
||||
roles*: seq[Snowflake] ## Array of roles.
|
||||
joinedAt*: string ## When the user joined the guild.
|
||||
premiumSince*: string ## When the user started boosting the guild.
|
||||
deaf*: bool ## Whether the user is deafened in voice channels.
|
||||
mute*: bool ## Whether the user is muted in voice channels.
|
||||
guildID*: snowflake ## The guild this member is in.
|
||||
guildID*: Snowflake ## The guild this member is in.
|
||||
presence*: Presence ## The member's presence.
|
||||
|
||||
proc newGuildMember*(json: JsonNode, guild: snowflake): GuildMember {.inline.} =
|
||||
proc newGuildMember*(json: JsonNode, guild: Snowflake): GuildMember {.inline.} =
|
||||
## Construct a GuildMember using json.
|
||||
result = GuildMember(
|
||||
nick: json{"nick"}.getStr(),
|
||||
|
@ -24,7 +24,7 @@ proc newGuildMember*(json: JsonNode, guild: snowflake): GuildMember {.inline.} =
|
|||
guildID: guild
|
||||
)
|
||||
|
||||
if (json.contains("user")):
|
||||
if json.contains("user"):
|
||||
result.user = newUser(json["user"])
|
||||
|
||||
# Add roles
|
||||
|
@ -33,46 +33,46 @@ proc newGuildMember*(json: JsonNode, guild: snowflake): GuildMember {.inline.} =
|
|||
|
||||
type GuildMemberModify* = ref object
|
||||
nick: Option[string]
|
||||
roles: Option[seq[snowflake]]
|
||||
roles: Option[seq[Snowflake]]
|
||||
mute: Option[bool]
|
||||
deaf: Option[bool]
|
||||
channelID: Option[snowflake]
|
||||
channelID: Option[Snowflake]
|
||||
|
||||
proc modifyGuildMember*(member: GuildMember, memberID: snowflake, modify: GuildMemberModify) {.async.} =
|
||||
proc modifyGuildMember*(member: GuildMember, memberID: Snowflake, modify: GuildMemberModify) {.async.} =
|
||||
## Modify attributes of a guild member. If the `channel_id` is set to null,
|
||||
## this will force the target user to be disconnected from voice.
|
||||
##
|
||||
## The member's new attributes will be reflected to `guild.members`.
|
||||
var modifyPayload = %*{}
|
||||
|
||||
if (modify.nick.isSome):
|
||||
if modify.nick.isSome:
|
||||
modifyPayload.add("nick", %modify.nick.get())
|
||||
|
||||
if (modify.roles.isSome):
|
||||
if modify.roles.isSome:
|
||||
# Convert the roles array to a string representation and remove the `@`
|
||||
# that is at the front of a conversion like this.
|
||||
var rolesStr = ($modify.roles.get()).substr(1)
|
||||
modifyPayload.add(parseJson(rolesStr))
|
||||
|
||||
if (modify.mute.isSome):
|
||||
if modify.mute.isSome:
|
||||
modifyPayload.add("mute", %modify.mute.get())
|
||||
|
||||
if (modify.deaf.isSome):
|
||||
if modify.deaf.isSome:
|
||||
modifyPayload.add("deaf", %modify.deaf.get())
|
||||
|
||||
if (modify.channelID.isSome):
|
||||
if modify.channelID.isSome:
|
||||
modifyPayload.add("channel_id", %modify.channelID.get())
|
||||
|
||||
discard sendRequest(endpoint(fmt("/guilds/{member.guildID}/members/{member.id}")), HttpPatch,
|
||||
defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})),
|
||||
member.guildID, RateLimitBucketType.guild, modifyPayload)
|
||||
|
||||
proc addGuildMemberRole*(member: GuildMember, roleID: snowflake) {.async.} =
|
||||
proc addGuildMemberRole*(member: GuildMember, roleID: Snowflake) {.async.} =
|
||||
## Adds a role to a guild member. Requires the `MANAGE_ROLES` permission.
|
||||
discard sendRequest(endpoint(fmt("/guilds/{member.guildID}/members/{member.id}/roles/{roleID}")),
|
||||
HttpPut, defaultHeaders(), member.guildID, RateLimitBucketType.guild)
|
||||
|
||||
proc removeGuildMemberRole*(member: GuildMember, roleID: snowflake) {.async.} =
|
||||
proc removeGuildMemberRole*(member: GuildMember, roleID: Snowflake) {.async.} =
|
||||
## Remove's a role to a guild member. Requires the `MANAGE_ROLES` permission.
|
||||
discard sendRequest(endpoint(fmt("/guilds/{member.guildID}/members/{member.id}/roles/{roleID}")),
|
||||
HttpDelete, defaultHeaders(), member.guildID, RateLimitBucketType.guild)
|
|
@ -1,4 +1,4 @@
|
|||
import json, discordobject, nimcordutils, user, member, httpcore, asyncdispatch, emoji, options, embed, role, emoji
|
||||
import json, discordobject, nimcordutils, user, member, httpcore, asyncdispatch, emoji, options, embed, emoji
|
||||
|
||||
type
|
||||
MessageType* = enum
|
||||
|
@ -35,9 +35,9 @@ type
|
|||
name*: string
|
||||
|
||||
MessageReference* = ref object
|
||||
messageID*: snowflake
|
||||
channelID*: snowflake
|
||||
guildID*: snowflake
|
||||
messageID*: Snowflake
|
||||
channelID*: Snowflake
|
||||
guildID*: Snowflake
|
||||
|
||||
MessageFlags* = enum
|
||||
msgFlagCrossposted = 0,
|
||||
|
@ -53,8 +53,8 @@ type
|
|||
|
||||
ChannelMention* = ref object
|
||||
## Represents a channel mention inside of a message.
|
||||
channelID*: snowflake
|
||||
guildID*: snowflake
|
||||
channelID*: Snowflake
|
||||
guildID*: Snowflake
|
||||
channelType*: int
|
||||
name*: string
|
||||
|
||||
|
@ -68,8 +68,8 @@ type
|
|||
width*: int
|
||||
|
||||
Message* = ref object of DiscordObject
|
||||
channelID*: snowflake
|
||||
guildID*: snowflake
|
||||
channelID*: Snowflake
|
||||
guildID*: Snowflake
|
||||
author*: User
|
||||
member*: GuildMember
|
||||
content*: string
|
||||
|
@ -78,13 +78,13 @@ type
|
|||
tts*: bool
|
||||
mentionEveryone*: bool
|
||||
mentions*: seq[User]
|
||||
mentionRoles*: seq[snowflake]
|
||||
mentionRoles*: seq[Snowflake]
|
||||
mentionChannels*: seq[ChannelMention]
|
||||
attachments*: seq[MessageAttachment]
|
||||
embeds*: seq[Embed]
|
||||
reactions*: seq[Reaction]
|
||||
pinned*: bool
|
||||
webhookID*: snowflake
|
||||
webhookID*: Snowflake
|
||||
`type`*: MessageType
|
||||
activity*: MessageActivity
|
||||
application*: MessageApplication
|
||||
|
@ -107,19 +107,19 @@ proc newMessage*(messageJson: JsonNode): Message =
|
|||
flags: messageJson{"flags"}.getInt()
|
||||
)
|
||||
|
||||
if (messageJson.contains("author")):
|
||||
if messageJson.contains("author"):
|
||||
msg.author = newUser(messageJson["author"])
|
||||
if (messageJson.contains("member")):
|
||||
if messageJson.contains("member"):
|
||||
msg.member = newGuildMember(messageJson["member"], msg.guildID)
|
||||
|
||||
if (messageJson.contains("mentions")):
|
||||
if messageJson.contains("mentions"):
|
||||
for userJson in messageJson["mentions"]:
|
||||
msg.mentions.add(newUser(userJson))
|
||||
|
||||
for role in messageJson["mention_roles"]:
|
||||
msg.mentionRoles.add(getIDFromJson(role.getStr()))
|
||||
|
||||
if (messageJson.contains("mention_channels")):
|
||||
if messageJson.contains("mention_channels"):
|
||||
for channel in messageJson["mention_channels"]:
|
||||
msg.mentionChannels.add(ChannelMention(
|
||||
channelID: getIDFromJson(channel["id"].getStr()),
|
||||
|
@ -142,7 +142,7 @@ proc newMessage*(messageJson: JsonNode): Message =
|
|||
for embed in messageJson["embeds"]:
|
||||
msg.embeds.add(Embed(embedJson: embed))
|
||||
|
||||
if (messageJson.contains("reactions")):
|
||||
if messageJson.contains("reactions"):
|
||||
for reaction in messageJson["reactions"]:
|
||||
msg.reactions.add(Reaction(
|
||||
count: uint(reaction["count"].getInt()),
|
||||
|
@ -150,10 +150,10 @@ proc newMessage*(messageJson: JsonNode): Message =
|
|||
emoji: newEmoji(reaction["emoji"], msg.guildID)
|
||||
))
|
||||
|
||||
if (messageJson.contains("activity")):
|
||||
if messageJson.contains("activity"):
|
||||
msg.activity = MessageActivity(`type`: MessageActivityType(messageJson["activity"]["type"].getInt()),
|
||||
partyID: messageJson["activity"]["party_id"].getStr())
|
||||
if (messageJson.contains("application")):
|
||||
if messageJson.contains("application"):
|
||||
msg.application = MessageApplication(
|
||||
id: getIDFromJson(messageJson["application"]["id"].getStr()),
|
||||
coverImage: messageJson["application"]{"cover_image"}.getStr(),
|
||||
|
@ -161,7 +161,7 @@ proc newMessage*(messageJson: JsonNode): Message =
|
|||
icon: messageJson["application"]{"icon"}.getStr(),
|
||||
name: messageJson["application"]["name"].getStr()
|
||||
)
|
||||
if (messageJson.contains("message_reference")):
|
||||
if messageJson.contains("message_reference"):
|
||||
msg.messageReference = MessageReference(
|
||||
messageID: getIDFromJson(messageJson["message_reference"]{"message_id"}.getStr()),
|
||||
channelID: getIDFromJson(messageJson["message_reference"]["channel_id"].getStr()),
|
||||
|
@ -212,8 +212,8 @@ type ReactantsGetRequest* = object
|
|||
## Use this type to get a messages's reactants by setting
|
||||
## some of the fields.
|
||||
## You can only set one of `before` and `after`.
|
||||
before*: Option[snowflake]
|
||||
after*: Option[snowflake]
|
||||
before*: Option[Snowflake]
|
||||
after*: Option[Snowflake]
|
||||
limit*: Option[int]
|
||||
|
||||
proc getReactants*(message: Message, emoji: Emoji, request: ReactantsGetRequest): seq[User] =
|
||||
|
@ -224,17 +224,17 @@ proc getReactants*(message: Message, emoji: Emoji, request: ReactantsGetRequest)
|
|||
|
||||
# Raise some exceptions to make sure the user doesn't
|
||||
# try to set more than one of these fields
|
||||
if (request.before.isSome):
|
||||
if request.before.isSome:
|
||||
url = url & "before=" & $request.before.get()
|
||||
|
||||
if (request.after.isSome):
|
||||
if (request.before.isSome):
|
||||
if request.after.isSome:
|
||||
if request.before.isSome:
|
||||
raise newException(Defect, "You cannot get before and after a message! Choose one...")
|
||||
url = url & "after=" & $request.after.get()
|
||||
|
||||
if (request.limit.isSome):
|
||||
if request.limit.isSome:
|
||||
# Add the `&` for the url if something else is set.
|
||||
if (request.before.isSome or request.after.isSome):
|
||||
if request.before.isSome or request.after.isSome:
|
||||
url = url & "&"
|
||||
|
||||
url = url & "limit=" & $request.limit.get()
|
||||
|
@ -276,7 +276,7 @@ proc editMessage*(message: Message, content: string, embed: Embed = nil): Future
|
|||
## Edit a previously sent message.
|
||||
var jsonBody = %*{"content": content}
|
||||
|
||||
if (not embed.isNil()):
|
||||
if embed != nil:
|
||||
jsonBody.add("embed", embed.embedJson)
|
||||
|
||||
return newMessage(sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import parseutils, json, httpClient, strformat, tables, times, asyncdispatch
|
||||
from discordobject import snowflake
|
||||
from discordobject import Snowflake
|
||||
|
||||
proc getIDFromJson*(str: string): uint64 =
|
||||
var num: uint64
|
||||
|
@ -17,10 +17,11 @@ proc endpoint*(url: string): string =
|
|||
var globalToken*: string
|
||||
|
||||
proc defaultHeaders*(added: HttpHeaders = newHttpHeaders()): HttpHeaders =
|
||||
added.add("Authorization", fmt("Bot {globalToken}"))
|
||||
# added.add("Authorization", fmt("Bot {globalToken}"))
|
||||
added.add("Authorization", fmt("{globalToken}"))
|
||||
added.add("User-Agent", "NimCord (https://github.com/SeanOMik/nimcord, v0.0.0)")
|
||||
added.add("X-RateLimit-Precision", "millisecond")
|
||||
return added;
|
||||
return added
|
||||
|
||||
type
|
||||
RateLimitBucketType* = enum
|
||||
|
@ -37,16 +38,16 @@ proc newRateLimit(lmt: int = 500, remLmnt: int = 500, ratelmtReset: float = 0):
|
|||
return RateLimit(limit: lmt, remainingLimit: remLmnt, ratelimitReset: ratelmtReset)
|
||||
|
||||
# Rate limit buckets
|
||||
let channelRatelimitBucket = newTable[snowflake, RateLimit]()
|
||||
let guildRatelimitBucket = newTable[snowflake, RateLimit]()
|
||||
let webhookRatelimitBucket = newTable[snowflake, RateLimit]()
|
||||
let channelRatelimitBucket = newTable[Snowflake, RateLimit]()
|
||||
let guildRatelimitBucket = newTable[Snowflake, RateLimit]()
|
||||
let webhookRatelimitBucket = newTable[Snowflake, RateLimit]()
|
||||
var globalRateLimit: RateLimit = newRateLimit()
|
||||
|
||||
proc handleRateLimits*(headers: HttpHeaders, objectID: snowflake, bucketType: RateLimitBucketType) =
|
||||
proc handleRateLimits*(headers: HttpHeaders, objectID: Snowflake, bucketType: RateLimitBucketType) =
|
||||
var obj: RateLimit
|
||||
if (headers.hasKey("x-ratelimit-global")):
|
||||
if headers.hasKey("x-ratelimit-global"):
|
||||
obj = globalRateLimit
|
||||
elif (headers.hasKey("x-ratelimit-limit")):
|
||||
elif headers.hasKey("x-ratelimit-limit"):
|
||||
case bucketType:
|
||||
of RateLimitBucketType.channel:
|
||||
obj = channelRatelimitBucket[objectID]
|
||||
|
@ -68,33 +69,33 @@ proc handleRateLimits*(headers: HttpHeaders, objectID: snowflake, bucketType: Ra
|
|||
discard parseFloat(headers["x-ratelimit-reset"], obj.ratelimitReset)
|
||||
|
||||
|
||||
proc handleResponse*(response: Response, objectID: snowflake, bucketType: RateLimitBucketType): JsonNode =
|
||||
proc handleResponse*(response: Response, objectID: Snowflake, bucketType: RateLimitBucketType): JsonNode =
|
||||
echo fmt("Received requested payload: {response.body}")
|
||||
|
||||
handleRateLimits(response.headers, objectID, bucketType)
|
||||
|
||||
return parseJson(response.body())
|
||||
|
||||
proc waitForRateLimits*(objectID: snowflake, bucketType: RateLimitBucketType) =
|
||||
proc waitForRateLimits*(objectID: Snowflake, bucketType: RateLimitBucketType) =
|
||||
var rlmt: RateLimit
|
||||
if (globalRateLimit.remainingLimit == 0):
|
||||
if globalRateLimit.remainingLimit == 0:
|
||||
rlmt = globalRateLimit
|
||||
else:
|
||||
case bucketType:
|
||||
of RateLimitBucketType.channel:
|
||||
if (channelRatelimitBucket.hasKey(objectID)):
|
||||
if channelRatelimitBucket.hasKey(objectID):
|
||||
rlmt = channelRatelimitBucket[objectID]
|
||||
else:
|
||||
channelRatelimitBucket.add(objectID, newRateLimit())
|
||||
rlmt = channelRatelimitBucket[objectID]
|
||||
of RateLimitBucketType.guild:
|
||||
if (guildRatelimitBucket.hasKey(objectID)):
|
||||
if guildRatelimitBucket.hasKey(objectID):
|
||||
rlmt = guildRatelimitBucket[objectID]
|
||||
else:
|
||||
guildRatelimitBucket.add(objectID, newRateLimit())
|
||||
rlmt = guildRatelimitBucket[objectID]
|
||||
of RateLimitBucketType.webhook:
|
||||
if (webhookRatelimitBucket.hasKey(objectID)):
|
||||
if webhookRatelimitBucket.hasKey(objectID):
|
||||
rlmt = webhookRatelimitBucket[objectID]
|
||||
else:
|
||||
webhookRatelimitBucket.add(objectID, newRateLimit())
|
||||
|
@ -102,21 +103,21 @@ proc waitForRateLimits*(objectID: snowflake, bucketType: RateLimitBucketType) =
|
|||
of RateLimitBucketType.global:
|
||||
rlmt = globalRateLimit
|
||||
|
||||
if (rlmt != nil and rlmt.remainingLimit == 0):
|
||||
if rlmt != nil and rlmt.remainingLimit == 0:
|
||||
let millisecondTime: float = rlmt.ratelimitReset * 1000 - epochTime() * 1000
|
||||
|
||||
if (millisecondTime > 0):
|
||||
if millisecondTime > 0:
|
||||
echo fmt("Rate limit wait time: {millisecondTime} miliseconds")
|
||||
waitFor sleepAsync(millisecondTime)
|
||||
|
||||
proc sendRequest*(endpoint: string, httpMethod: HttpMethod, headers: HttpHeaders, objectID: snowflake = 0,
|
||||
proc sendRequest*(endpoint: string, httpMethod: HttpMethod, headers: HttpHeaders, objectID: Snowflake = 0,
|
||||
bucketType: RateLimitBucketType = global, jsonBody: JsonNode = nil): JsonNode =
|
||||
var client = newHttpClient()
|
||||
# Add headers
|
||||
client.headers = headers
|
||||
|
||||
var strPayload: string
|
||||
if (jsonBody == nil):
|
||||
if jsonBody == nil:
|
||||
strPayload = ""
|
||||
else:
|
||||
strPayload = $jsonBody
|
||||
|
|
|
@ -39,12 +39,12 @@ type
|
|||
|
||||
Permissions* = ref object
|
||||
## This type referes to a user's permissions given by the role or per user.
|
||||
roleUserID*: snowflake
|
||||
roleUserID*: Snowflake
|
||||
allowPerms*: uint
|
||||
denyPerms*: uint
|
||||
permissionType*: PermissionType
|
||||
|
||||
proc newPermissions*(id: snowflake, `type`: PermissionType, byteSet: uint): Permissions =
|
||||
proc newPermissions*(id: Snowflake, `type`: PermissionType, byteSet: uint): Permissions =
|
||||
## Create a new `Permissions` using an id, type, and byte set.
|
||||
result = Permissions(roleUserID: id, permissionType: `type`, allowPerms: byteSet)
|
||||
|
||||
|
@ -56,7 +56,7 @@ proc newPermissions*(json: JsonNode): Permissions =
|
|||
denyPerms: uint(json["deny"].getInt())
|
||||
)
|
||||
|
||||
if (json["type"].getStr() == "role"):
|
||||
if json["type"].getStr() == "role":
|
||||
result.permissionType = PermissionType.permTypeRole
|
||||
else:
|
||||
result.permissionType = PermissionType.permTypeMember
|
||||
|
@ -71,7 +71,7 @@ proc addAllowPermission*(perms: Permissions, perm: Permission): Future[Permissio
|
|||
## If it finds the permission in denyPerms, it will remove it from that also.
|
||||
|
||||
# Check if the permission is in deny, and remove it.
|
||||
if ((perms.denyPerms and uint(perm)) == uint(perm)):
|
||||
if (perms.denyPerms and uint(perm)) == uint(perm):
|
||||
perms.denyPerms = perms.denyPerms and (not uint(perm))
|
||||
|
||||
perms.allowPerms = perms.allowPerms or uint(perm)
|
||||
|
@ -81,7 +81,7 @@ proc addDenyPermission*(perms: Permissions, perm: Permission): Future[Permission
|
|||
## If it finds the permission in allowPerms, it will remove it from that also.
|
||||
|
||||
# Check if the permission is in allowed, and remove it.
|
||||
if ((perms.allowPerms and uint(perm)) == uint(perm)):
|
||||
if (perms.allowPerms and uint(perm)) == uint(perm):
|
||||
perms.allowPerms = perms.allowPerms and (not uint(perm))
|
||||
|
||||
perms.denyPerms = perms.denyPerms or uint(perm)
|
||||
|
@ -94,7 +94,7 @@ proc permissionsToJson*(perms: Permissions): JsonNode =
|
|||
"deny": perms.denyPerms
|
||||
}
|
||||
|
||||
if (perms.permissionType == PermissionType.permTypeMember):
|
||||
if perms.permissionType == PermissionType.permTypeMember:
|
||||
json.add("type", %"member")
|
||||
else:
|
||||
json.add("type", %"role")
|
|
@ -48,7 +48,7 @@ type
|
|||
url*: string
|
||||
createdAt*: uint
|
||||
timestamps*: seq[ActivityTimestamp]
|
||||
applicationID*: snowflake
|
||||
applicationID*: Snowflake
|
||||
details*: string
|
||||
state*: string
|
||||
emoji*: Emoji
|
||||
|
@ -64,7 +64,7 @@ type
|
|||
activities*: seq[Activity]
|
||||
afk*: bool
|
||||
|
||||
proc newActivity*(json: JsonNode, guildID: snowflake): Activity =
|
||||
proc newActivity*(json: JsonNode, guildID: Snowflake): Activity =
|
||||
## Parse a new activity from json.
|
||||
var act = Activity(
|
||||
name: json["name"].getStr(),
|
||||
|
@ -78,44 +78,44 @@ proc newActivity*(json: JsonNode, guildID: snowflake): Activity =
|
|||
flags: uint(json{"flags"}.getInt()),
|
||||
)
|
||||
|
||||
if (json.contains("timestamps")):
|
||||
if json.contains("timestamps"):
|
||||
var time = ActivityTimestamp()
|
||||
if (json["timestamps"].contains("start")):
|
||||
if json["timestamps"].contains("start"):
|
||||
time.startTime = uint(json["timestamps"]{"start"}.getInt())
|
||||
if (json["timestamps"].contains("end")):
|
||||
if json["timestamps"].contains("end"):
|
||||
time.endTime = uint(json["timestamps"]{"end"}.getInt())
|
||||
|
||||
act.timestamps.add(time)
|
||||
|
||||
if (json.contains("emoji")):
|
||||
if json.contains("emoji"):
|
||||
act.emoji = newEmoji(json["emoji"], guildID)
|
||||
|
||||
if (json.contains("party")):
|
||||
if json.contains("party"):
|
||||
var party = ActivityParty()
|
||||
if (json["party"].contains("id")):
|
||||
if json["party"].contains("id"):
|
||||
party.id = json["party"]["id"].getStr()
|
||||
if (json["party"].contains("size")):
|
||||
if json["party"].contains("size"):
|
||||
party.currentSize = uint(json["party"]["size"].elems[0].getInt())
|
||||
party.maxSize = uint(json["party"]["size"].elems[1].getInt())
|
||||
|
||||
if (json.contains("assets")):
|
||||
if json.contains("assets"):
|
||||
var assets = ActivityAssets()
|
||||
if (json["assets"].contains("large_image")):
|
||||
if json["assets"].contains("large_image"):
|
||||
assets.largeImg = json["assets"]["large_image"].getStr()
|
||||
if (json["assets"].contains("large_text")):
|
||||
if json["assets"].contains("large_text"):
|
||||
assets.largeText = json["assets"]["large_text"].getStr()
|
||||
if (json["assets"].contains("small_image")):
|
||||
if json["assets"].contains("small_image"):
|
||||
assets.smallImg = json["assets"]["small_image"].getStr()
|
||||
if (json["assets"].contains("small_text")):
|
||||
if json["assets"].contains("small_text"):
|
||||
assets.smallText = json["assets"]["small_text"].getStr()
|
||||
|
||||
if (json.contains("secrets")):
|
||||
if json.contains("secrets"):
|
||||
var secrets = ActivitySecrets()
|
||||
if (json["secrets"].contains("join")):
|
||||
if json["secrets"].contains("join"):
|
||||
secrets.join = json["secrets"]["join"].getStr()
|
||||
if (json["secrets"].contains("spectate")):
|
||||
if json["secrets"].contains("spectate"):
|
||||
secrets.spectate = json["secrets"]["spectate"].getStr()
|
||||
if (json["secrets"].contains("match")):
|
||||
if json["secrets"].contains("match"):
|
||||
secrets.match = json["secrets"]["match"].getStr()
|
||||
|
||||
proc newPresence*(json: JsonNode): Presence =
|
||||
|
@ -124,7 +124,7 @@ proc newPresence*(json: JsonNode): Presence =
|
|||
status: json["status"].getStr()
|
||||
)
|
||||
|
||||
if (json.contains("game") and json["game"].getFields().len > 0):
|
||||
if json.contains("game") and json["game"].getFields().len > 0:
|
||||
let guildID = if json.contains("guild_id"): getIDFromJson(json["guild_id"].getStr()) else: 0
|
||||
result.game = newActivity(json["game"], guildID)
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ type Role* = ref object of DiscordObject
|
|||
permissions*: Permissions
|
||||
managed*: bool
|
||||
mentionable*: bool
|
||||
guildID*: snowflake
|
||||
guildID*: Snowflake
|
||||
|
||||
proc newRole*(json: JsonNode, guild: snowflake): Role =
|
||||
proc newRole*(json: JsonNode, guild: Snowflake): Role =
|
||||
## Parses role from json.
|
||||
result = Role(
|
||||
id: getIDFromJson(json["id"].getStr()),
|
||||
|
@ -38,19 +38,19 @@ proc modifyGuildRole*(role: var Role, name: Option[string] = none(string), permi
|
|||
|
||||
var jsonBody: JsonNode
|
||||
|
||||
if (name.isSome):
|
||||
if name.isSome:
|
||||
jsonBody.add("name", %name)
|
||||
|
||||
if (permissions.isSome):
|
||||
if permissions.isSome:
|
||||
jsonBody.add("permissions", %permissions.get().allowPerms)
|
||||
|
||||
if (color.isSome):
|
||||
if color.isSome:
|
||||
jsonBody.add("color", %color)
|
||||
|
||||
if (hoist.isSome):
|
||||
if hoist.isSome:
|
||||
jsonBody.add("hoist", %hoist)
|
||||
|
||||
if (mentionable.isSome):
|
||||
if mentionable.isSome:
|
||||
jsonBody.add("mentionable", %mentionable)
|
||||
|
||||
result = newRole(sendRequest(endpoint(fmt("/guilds/{role.guildID}/roles/{role.id}")), HttpPatch,
|
||||
|
|
Reference in New Issue