Get the gateway heartbeating.
This commit is contained in:
parent
e87241d7a6
commit
0b11d2f5e0
|
@ -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()
|
Reference in New Issue