diff --git a/generate_docs.sh b/generate_docs.sh old mode 100644 new mode 100755 diff --git a/nimcord.nimble b/nimcord.nimble index 4c62378..27c36e1 100644 --- a/nimcord.nimble +++ b/nimcord.nimble @@ -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" \ No newline at end of file +requires "nim >= 1.2.0", "websocket >= 0.4.0 & <= 0.4.1" diff --git a/src/nimcord/cache.nim b/src/nimcord/cache.nim index 0437a14..44bd286 100644 --- a/src/nimcord/cache.nim +++ b/src/nimcord/cache.nim @@ -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,18 +44,18 @@ 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) - guild.channels.add(channel) \ No newline at end of file + guild.channels.add(channel) diff --git a/src/nimcord/channel.nim b/src/nimcord/channel.nim index 49c057e..4292dbf 100644 --- a/src/nimcord/channel.nim +++ b/src/nimcord/channel.nim @@ -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, @@ -391,4 +391,4 @@ proc groupDMAddRecipient*(channel: Channel, user: User, accessToken: string, nic proc groupDMRemoveRecipient*(channel: Channel, user: User) {.async.} = ## Removes a recipient from a Group DM. discard sendRequest(endpoint("/channels/" & $channel.id & "/recipients/" & $user.id), - HttpPut, defaultHeaders(), channel.id, RateLimitBucketType.channel) \ No newline at end of file + HttpPut, defaultHeaders(), channel.id, RateLimitBucketType.channel) diff --git a/src/nimcord/client.nim b/src/nimcord/client.nim index 6b9f812..e629ba2 100644 --- a/src/nimcord/client.nim +++ b/src/nimcord/client.nim @@ -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) @@ -73,7 +83,7 @@ proc reconnectShard(shard: Shard) {.async.} = shard.reconnecting = false shard.heartbeatAcked = true - #waitFor client.startConnection() + # waitFor client.startConnection() # Handle discord disconnect. If it detects that we can reconnect, it will. proc handleGatewayDisconnect(shard: Shard, error: string) {.async.} = @@ -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 @@ -246,4 +256,4 @@ proc newDiscordClient*(tkn: string): DiscordClient = var cac: Cache new(cac) - result = DiscordClient(token: tkn, cache: cac) \ No newline at end of file + result = DiscordClient(token: tkn, cache: cac) diff --git a/src/nimcord/discordobject.nim b/src/nimcord/discordobject.nim index e9659b4..d18fade 100644 --- a/src/nimcord/discordobject.nim +++ b/src/nimcord/discordobject.nim @@ -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 \ No newline at end of file + return obj1.id == obj2.id diff --git a/src/nimcord/embed.nim b/src/nimcord/embed.nim index 96cddc6..3d04515 100644 --- a/src/nimcord/embed.nim +++ b/src/nimcord/embed.nim @@ -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,12 +180,12 @@ 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: - embed.embedJson.add("fields", %*[field]) \ No newline at end of file + embed.embedJson.add("fields", %*[field]) diff --git a/src/nimcord/emoji.nim b/src/nimcord/emoji.nim index 99362e8..67491e6 100644 --- a/src/nimcord/emoji.nim +++ b/src/nimcord/emoji.nim @@ -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 = %* { @@ -95,4 +95,4 @@ proc modifyEmoji*(emoji: var Emoji, name: string, roles: seq[snowflake] = @[]): proc deleteEmoji*(emoji: Emoji) {.async.} = ## Delete the given emoji. Requires the `MANAGE_EMOJIS` permission. discard sendRequest(endpoint(fmt("/guilds/{emoji.guildID}/emojis/{emoji.id}")), HttpDelete, - defaultHeaders(), emoji.guildID, RateLimitBucketType.guild) \ No newline at end of file + defaultHeaders(), emoji.guildID, RateLimitBucketType.guild) diff --git a/src/nimcord/eventdispatcher.nim b/src/nimcord/eventdispatcher.nim index 81b5553..b63ddc5 100644 --- a/src/nimcord/eventdispatcher.nim +++ b/src/nimcord/eventdispatcher.nim @@ -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,9 +504,9 @@ 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: echo "Failed to find event: ", eventName - \ No newline at end of file + diff --git a/src/nimcord/eventhandler.nim b/src/nimcord/eventhandler.nim index 5dcfa89..10f927b 100644 --- a/src/nimcord/eventhandler.nim +++ b/src/nimcord/eventhandler.nim @@ -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,10 +264,10 @@ 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: eventListener(event) else: - echo "No event listeners for event: ", event.name \ No newline at end of file + echo "No event listeners for event: ", event.name diff --git a/src/nimcord/guild.nim b/src/nimcord/guild.nim index 9df5e26..1085427 100644 --- a/src/nimcord/guild.nim +++ b/src/nimcord/guild.nim @@ -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)): - result.add(role) \ No newline at end of file + if member.roles.contains(role.id): + result.add(role) diff --git a/src/nimcord/image.nim b/src/nimcord/image.nim index 53dc9b9..2f30eae 100644 --- a/src/nimcord/image.nim +++ b/src/nimcord/image.nim @@ -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 @@ -24,4 +24,4 @@ proc newImage*(filepath: string): Image = raise newException(IOError, "Failed to open file: " & filepath) proc imageToDataURI*(image: Image): string = - return fmt("data:image/{image.extension};base64,{image.base64Encoded}") \ No newline at end of file + return fmt("data:image/{image.extension};base64,{image.base64Encoded}") diff --git a/src/nimcord/log.nim b/src/nimcord/log.nim index 7a7ced5..3bac7ee 100644 --- a/src/nimcord/log.nim +++ b/src/nimcord/log.nim @@ -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() \ No newline at end of file + log.logFile.close() diff --git a/src/nimcord/member.nim b/src/nimcord/member.nim index 9f27077..8d376af 100644 --- a/src/nimcord/member.nim +++ b/src/nimcord/member.nim @@ -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) \ No newline at end of file + HttpDelete, defaultHeaders(), member.guildID, RateLimitBucketType.guild) diff --git a/src/nimcord/message.nim b/src/nimcord/message.nim index c94cd79..921aed1 100644 --- a/src/nimcord/message.nim +++ b/src/nimcord/message.nim @@ -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), @@ -291,4 +291,4 @@ proc deleteMessage*(message: Message) {.async.} = ## See also: ## * `deleteMessage<#deleteMessage,Message>`_ discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id), - HttpDelete, defaultHeaders(), message.channelID, RateLimitBucketType.channel) \ No newline at end of file + HttpDelete, defaultHeaders(), message.channelID, RateLimitBucketType.channel) diff --git a/src/nimcord/nimcordutils.nim b/src/nimcord/nimcordutils.nim index 6617374..a980f80 100644 --- a/src/nimcord/nimcordutils.nim +++ b/src/nimcord/nimcordutils.nim @@ -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 @@ -124,4 +125,4 @@ proc sendRequest*(endpoint: string, httpMethod: HttpMethod, headers: HttpHeaders waitForRateLimits(objectID, bucketType) let response = client.request(endpoint, httpMethod, strPayload) - return handleResponse(response, objectId, bucketType) \ No newline at end of file + return handleResponse(response, objectId, bucketType) diff --git a/src/nimcord/permission.nim b/src/nimcord/permission.nim index 12da17d..940047e 100644 --- a/src/nimcord/permission.nim +++ b/src/nimcord/permission.nim @@ -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") \ No newline at end of file + json.add("type", %"role") diff --git a/src/nimcord/presence.nim b/src/nimcord/presence.nim index 5772585..36bfd58 100644 --- a/src/nimcord/presence.nim +++ b/src/nimcord/presence.nim @@ -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) @@ -154,4 +154,4 @@ proc presenceToJson*(presence: Presence): JsonNode = "name": presence.game.name, "type": ord(presence.game.`type`) } - } \ No newline at end of file + } diff --git a/src/nimcord/role.nim b/src/nimcord/role.nim index 42277b5..abdbc90 100644 --- a/src/nimcord/role.nim +++ b/src/nimcord/role.nim @@ -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, @@ -61,4 +61,4 @@ proc modifyGuildRole*(role: var Role, name: Option[string] = none(string), permi proc deleteGuildRole*(role: Role) {.async.} = ## Delete a guild role. Requires the `MANAGE_ROLES` permission. discard sendRequest(endpoint(fmt("/guilds/{role.guildID}/roles/{role.id}")), HttpDelete, - defaultHeaders(), role.guildID, RateLimitBucketType.guild) \ No newline at end of file + defaultHeaders(), role.guildID, RateLimitBucketType.guild)