如何为 Discord 网关设置心跳功能

Posted

技术标签:

【中文标题】如何为 Discord 网关设置心跳功能【英文标题】:How to set up a heartbeat function for Discord gateway 【发布时间】:2020-11-13 21:37:31 【问题描述】:

这不会是一个关于解决一个问题的非常具体的问题,因此对此深表歉意。这是我之前询问的关于获取我的 Discord 机器人网站的实时服务器计数的问题的后续。在我看来,websocket 连接是获取此信息的最佳方式,因为通过 discord.js 获取此信息占用了太多内存,因为 discord.js 比我需要的要多得多。

我知道对于 websocket 连接,我需要获取连接 URL,连接,然后进行心跳和接收心跳确认。不过,实际上将这些想法转化为代码时,我遇到了很多麻烦。到目前为止,我可以请求一个 URL、连接并开始心跳,但我不知道如何 1)在接收信息的同时保持心跳,以及 2)如果连接中断(我没有收到确认)停止心跳。引起我问题的主要原因是无法与多个消息侦听器一起工作。如果有人能指出我正确的总体方向或解决我当前问题的方法,将不胜感激。

当前代码,如果有帮助的话(我知道它并没有真正起作用):

const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const WebSocket = require('ws')

let xhr = new XMLHttpRequest()
xhr.onload = (req, res) => 
    if (xhr.readyState === 4 && xhr.status === 200) 
        console.log(xhr.responseText)
        main(JSON.parse(xhr.responseText))
     else 
        console.error(`ReadyState: $xhr.readyState    Status: $xhr.status`)
    

xhr.open("GET", 'https://discord.com/api/gateway/bot', false)
xhr.setRequestHeader("Authorization", "MY_BOT_TOKEN_THIS_IS_A_PLACEHOLDER_DONT_TELL_ME_ITS_WRONG_IN_COMMENTS")
xhr.send()

function main(response) 
    let socket = new WebSocket(`$response.url/?v=6&encoding=json`)
    var hello
    socket.onopen = (event) => 
        console.log("Connection established")
    
    socket.onclose = (event) => 
        console.log(`Connection closed: code=$event.code reason=$event.reason`)
    
    socket.addEventListener('message', (event) => 
        console.log(`Data received: $event.data`)
        hello = JSON.parse(event.data)
        if (hello.op == 10) 
            let alive = true
            heartbeat(socket, hello.s, hello.d.heartbeat_interval, alive)
            socket.send(JSON.stringify(
                "op": 2,
                "d": 
                    "token": "MY_BOT_TOKEN_THIS_IS_A_PLACEHOLDER_DONT_TELL_ME_ITS_WRONG_IN_COMMENTS",
                    "properties": 
                        "$os": "windows",
                        "$device": "test",
                        "$browser": "test"
                    ,
                    "guild_subscriptions": false,
                    "intents": 1
                
            ))
            socket.removeEventListener('message')
            socket.addEventListener('message', (event) => 
                if (JSON.parse(event.data).op !== 11) 
                    console.log(`Message received: $event.data`)
                
            )
        
    )


function heartbeat(socket, s, interval, alive) 
    socket.send(JSON.stringify("op": 1, "d": s))
    console.log("Heartbeat sent")
    setTimeout(() => 
        alive = false
    , interval)


function listenForMessage(event) 
    if (JSON.parse(event.data).op === 11) 
        let data = JSON.parse(event.data)
        console.log(`Heartbeat received: $event.data`)
        if (data.hasOwnProperty("s")) 
            s = data.s
        
        socket.removeEventListener('message')
        if (alive) 
            heartbeat(socket, s, interval)
            socket.addEventListener('message', listenForMessage)
        
     else 

    

【问题讨论】:

【参考方案1】:

我尝试使用不同的代码,因为我找不到另一个代码,并且当我尝试发送 3 个心跳时出现问题,连接已断开 连接关闭:代码 = 1000 原因 =

【讨论】:

这并不能真正回答问题。如果您有其他问题,可以点击 提问。要在此问题有新答案时收到通知,您可以follow this question。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:

我有一些建议。

    let alert 放错地方了。它的范围应该在 let WebSocket 之下。 不要removeEventListener。最好有一个消息处理程序switch (message.op),然后根据message.op 的值调用其他方法(您将其命名为hello)。 如果你真的要removeEventListener,你不能只传递"message"的类型,你还需要传递一个对函数本身的引用。请参阅here 及以下内容。 如果您需要保存第一条消息(hello 的值),那么还要将其范围限定在文件的顶层。 你没有说当你停止心跳时你想做什么,但你已经有了它的位置,它就是你设置alive = false的位置。您可以在那里致电socket.close()alert 您的用户出现问题。取决于您的应用。
const myHandler = function (data)  /* do stuff with data */ ;
socket.addEventListener("message", myHandler);
socket.removeEventListener("message", myHandler);

【讨论】:

以上是关于如何为 Discord 网关设置心跳功能的主要内容,如果未能解决你的问题,请参考以下文章

我如何为 client = discord.Client() 使用 discordpy 冷却命令 [关闭]

discord.py - 如何为特定用户重置命令的冷却时间?

AWS Lambda:如何为具有 VPC 访问权限的 lambda 函数设置 NAT 网关

单元测试心跳功能

如何为加入 Discord 公会的新成员自动分配角色?

freeRTOS&LVGL|在使用freertos时如何为lvgl配置心跳和任务管理器