This repository has been archived on 2023-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
nimcord/src/nimcordutils.nim

127 lines
4.9 KiB
Nim
Raw Normal View History

2020-06-17 05:34:23 +00:00
import parseutils, json, httpClient, strformat, tables, times, asyncdispatch
2020-05-31 05:10:18 +00:00
from discordobject import snowflake
proc getIDFromJson*(str: string): uint64 =
var num: uint64
2020-06-18 03:16:58 +00:00
discard parseBiggestUInt(str, num)
2020-05-31 05:10:18 +00:00
return num
proc parseIntEasy*(str: string): int =
var num: int
discard parseInt(str, num)
return num
2020-06-17 05:34:23 +00:00
proc endpoint*(url: string): string =
return fmt("https://discord.com/api/v6{url}")
2020-05-31 05:10:18 +00:00
var globalToken*: string
proc defaultHeaders*(added: HttpHeaders = newHttpHeaders()): HttpHeaders =
added.add("Authorization", fmt("Bot {globalToken}"))
added.add("User-Agent", "NimCord (https://github.com/SeanOMik/nimcord, v0.0.0)")
added.add("X-RateLimit-Precision", "millisecond")
return added;
2020-06-17 05:34:23 +00:00
type
RateLimitBucketType* = enum
channel,
guild,
webhook,
global
RateLimit = ref object {.requiresInit.}
limit: int
remainingLimit: int
ratelimitReset: float
proc newRateLimit(lmt: int = 500, remLmnt: int = 500, ratelmtReset: float = 0): RateLimit =
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]()
var globalRateLimit: RateLimit = newRateLimit()
proc handleRateLimits*(headers: HttpHeaders, objectID: snowflake, bucketType: RateLimitBucketType) =
var obj: RateLimit
if (headers.hasKey("x-ratelimit-global")):
obj = globalRateLimit
elif (headers.hasKey("x-ratelimit-limit")):
case bucketType:
of RateLimitBucketType.channel:
obj = channelRatelimitBucket[objectID]
discard
of RateLimitBucketType.guild:
obj = guildRatelimitBucket[objectID]
discard
of RateLimitBucketType.webhook:
obj = webhookRatelimitBucket[objectID]
discard
of RateLimitBucketType.global:
obj = globalRateLimit
discard
else:
return
discard parseInt(headers["x-ratelimit-limit"], obj.limit)
discard parseInt(headers["x-ratelimit-remaining"], obj.remainingLimit)
discard parseFloat(headers["x-ratelimit-reset"], obj.ratelimitReset)
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) =
var rlmt: RateLimit
if (globalRateLimit.remainingLimit == 0):
rlmt = globalRateLimit
else:
case bucketType:
of RateLimitBucketType.channel:
2020-06-18 03:17:46 +00:00
if (channelRatelimitBucket.hasKey(objectID)):
rlmt = channelRatelimitBucket[objectID]
else:
channelRatelimitBucket.add(objectID, newRateLimit())
rlmt = channelRatelimitBucket[objectID]
2020-06-17 05:34:23 +00:00
of RateLimitBucketType.guild:
2020-06-18 03:17:46 +00:00
if (guildRatelimitBucket.hasKey(objectID)):
rlmt = guildRatelimitBucket[objectID]
else:
guildRatelimitBucket.add(objectID, newRateLimit())
rlmt = guildRatelimitBucket[objectID]
2020-06-17 05:34:23 +00:00
of RateLimitBucketType.webhook:
2020-06-18 03:17:46 +00:00
if (webhookRatelimitBucket.hasKey(objectID)):
rlmt = webhookRatelimitBucket[objectID]
else:
webhookRatelimitBucket.add(objectID, newRateLimit())
rlmt = webhookRatelimitBucket[objectID]
2020-06-17 05:34:23 +00:00
of RateLimitBucketType.global:
rlmt = globalRateLimit
2020-06-18 03:17:46 +00:00
if (rlmt != nil and rlmt.remainingLimit == 0):
2020-06-17 05:34:23 +00:00
let millisecondTime: float = rlmt.ratelimitReset * 1000 - epochTime() * 1000
if (millisecondTime > 0):
echo fmt("Rate limit wait time: {millisecondTime} miliseconds")
2020-06-18 20:31:38 +00:00
waitFor sleepAsync(millisecondTime)
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):
strPayload = ""
else:
strPayload = $jsonBody
echo "Sending ", httpMethod, " request, URL: ", endpoint, ", headers: ", $headers, " body: ", strPayload
waitForRateLimits(objectID, bucketType)
let response = client.request(endpoint, httpMethod, strPayload)
return handleResponse(response, objectId, bucketType)