Get the gateway heartbeating.

This commit is contained in:
SeanOMik 2020-05-29 01:20:39 -05:00
parent e87241d7a6
commit 0b11d2f5e0
No known key found for this signature in database
GPG Key ID: FA4D55AC05268A88
1 changed files with 63 additions and 18 deletions

View File

@ -1,53 +1,98 @@
import websocket, asyncnet, asyncdispatch, json, httpClient, strformat import websocket, asyncnet, asyncdispatch, json, httpClient, strformat
type type
DiscordOpCode = enum
opDispatch = 0,
opHeartbeat = 1,
opIdentify = 2,
opPresenceUpdate = 3,
opVoiceStateUpdate = 4,
opResume = 6,
opReconnect = 7,
opRequestGuildMembers = 8,
opInvalidSession = 9,
opHello = 10,
opHeartbeatAck = 11
DiscordClient* = ref object ## Discord Client DiscordClient* = ref object ## Discord Client
token*: string token*: string
#user*: User #user*: User
#cache: Cache #cache: Cache
ws: AsyncWebSocket ws: AsyncWebSocket
httpClient: AsyncHttpClient httpClient: AsyncHttpClient
heartbeatInterval: int
heartbeatAcked: bool
lastSequence: int
#[ proc heartbeat() {.async.} = proc sendGatewayRequest*(client: DiscordClient, request: JsonNode, msg: string = "") {.async.} =
if (msg.len == 0):
echo "Sending gateway payload: ", request
else:
echo msg
discard client.ws.sendText($request)
proc handleHeartbeat(client: DiscordClient) {.async.} =
while true: while true:
await sleepAsync(35000) var heartbeatPayload: JsonNode
echo "heartbeat now" ]# if (client.lastSequence == 0):
heartbeatPayload = %* { "d": nil, "op": ord(DiscordOpCode.opHeartbeat) }
else:
heartbeatPayload = %* { "d": client.lastSequence, "op": ord(DiscordOpCode.opHeartbeat) }
proc read(client: DiscordClient) {.async.} = await client.sendGatewayRequest(heartbeatPayload, fmt("Sending heartbeat payload: {$heartbeatPayload}"))
client.heartbeatAcked = true
echo "Waiting ", client.heartbeatInterval, " ms until next heartbeat..."
await sleepAsync(client.heartbeatInterval)
proc getIdentifyPacket(client: DiscordClient): JsonNode =
return %* { "op": ord(DiscordOpCode.opIdentify), "d": { "token": client.token, "properties": { "$os": system.hostOS, "$browser": "NimCord", "$device": "NimCord" } } }
proc handleWebsocketPacket(client: DiscordClient) {.async.} =
while true: while true:
var packet: tuple[opcode: Opcode, data: string] var packet: tuple[opcode: Opcode, data: string]
packet = await client.ws.readData(); packet = await client.ws.readData();
echo "(opcode: ", packet.opcode, ", data: ", packet.data, ")" echo "Received gateway payload: ", packet.data
var json: JsonNode = parseJson(packet.data); var json: JsonNode = parseJson(packet.data);
case json["op"].num if (json.contains("s")):
of 10: client.lastSequence = json["s"].getInt()
echo "Received 'HELLO' from the gateway."
# Start heartbeat here! case json["op"].getInt()
of ord(DiscordOpCode.opHello):
client.heartbeatInterval = json["d"]["heartbeat_interval"].getInt()
discard client.sendGatewayRequest(client.getIdentifyPacket())
asyncCheck client.handleHeartbeat()
client.heartbeatAcked = true
of ord(DiscordOpCode.opHeartbeatAck):
client.heartbeatAcked = true
else: else:
discard discard
proc Endpoint(url: string): string = proc endpoint*(url: string): string =
return fmt("https://discord.com/api/v6{url}") return fmt("https://discord.com/api/v6{url}")
proc startConnection(client: DiscordClient) {.async.} = proc startConnection*(client: DiscordClient) {.async.} =
client.httpClient = newAsyncHttpClient() client.httpClient = newAsyncHttpClient()
client.httpClient.headers = newHttpHeaders({"Authorization": fmt("Bot {client.token}")}) client.httpClient.headers = newHttpHeaders({"Authorization": fmt("Bot {client.token}")})
let result = parseJson(await client.httpClient.getContent(Endpoint("/gateway/bot"))) let urlResult = parseJson(await client.httpClient.getContent(endpoint("/gateway/bot")))
echo "Got result: ", $result echo "Got result: ", $urlResult
if (result.contains("url")): if (urlResult.contains("url")):
let url = result["url"].getStr() let url = urlResult["url"].getStr()
client.ws = await newAsyncWebsocketClient(url[6..url.high], Port 443 , client.ws = await newAsyncWebsocketClient(url[6..url.high], Port 443 ,
path = "/v=6&encoding=json", true) path = "/v=6&encoding=json", true)
echo "Connected!" echo "Connected!"
asyncCheck client.read() asyncCheck client.handleWebsocketPacket()
#asyncCheck heartbeat()
runForever() runForever()
else: else:
var e: ref IOError var e: ref IOError
@ -56,5 +101,5 @@ proc startConnection(client: DiscordClient) {.async.} =
raise e raise e
var bot = DiscordClient(token: var bot = DiscordClient(token:
"TOKEN") "NjQ4NjcwNDA4NDg4MjU1NTAw.XtCGDw.ZNaRT6kNIMyO1wlcZbbaUGSsm7g")
waitFor bot.startConnection() waitFor bot.startConnection()