我正在开发一个 R 代码,它使用网络套接字在消息从 Discord 到达时发送消息到 R(不要与 R 使用 httr::GET 不断查询 Discord 来获取新消息相混淆)。
R 不是每隔一定时间就向 Discord 询问新消息(所以你知道,Discord 不允许这样做;Discord 对请求消息的次数有限制),websocket 允许 Discord 向 R 发送消息仅当到达时。
在 R 中,有两个库(websocket 和 httpuv)可以执行此操作,但是我在工作时开发的代码会在几分钟到几小时的随机时间后关闭连接(我认为 Python 有一个安全重新连接代码,但在 R 中实现,但不确定)。这些错误有不同的名称,例如:“未处理的承诺错误:无效状态”等。
我想知道这段代码出了什么问题,我是否缺少一行代码来在连接关闭或崩溃时重新启动连接?
library(websocket)
library(jsonlite)
library(async)
Heartbeat =10 #container for heartbite
DiscordSignals <- function(DiscordToken){
#payloads or messages that R has to send to Discord.
Rpayload = list(
op= 2,
d= list(
token= DiscordToken,
intents= 513,
properties=list(
os= "windows",
browser= "firefox",
device= "firefox")
)
)
KeepAlive = list(op= 1, d= "null" )
Jsonpayload = toJSON(Rpayload, auto_unbox = TRUE, pretty = TRUE)
JsonKeepAlive = toJSON(KeepAlive, auto_unbox = TRUE, pretty = TRUE)
ws <<- WebSocket$new("wss://gateway.discord.gg/?v=9&encording=json", errorLogChannels ="warn")
ws$onOpen(function(event) {ws$send(Jsonpayload)}) #Handshake
ws$onMessage(function(event) {
d <- event$data
json = fromJSON(d)
Alert= json$d$content
OP<<-as.numeric(json$op) #Type of message sent from Discord
#https://discord.com/developers/docs/topics/gateway#resuming
#Discord may request additional heartbeats from your app by sending a Heartbeat (opcode OP1) event. Upon receiving the event, .. immediately send back .. Heartbeat ...
#reset heartbeat rate to whatever asked by Discord. Heartbite rate requested from Discord is sent in OPs 1 or 10.
if (OP %in% c(1,10)){Heartbeat <<-round(abs(((json$d$heartbeat_interval )/1000)-runif(1)-3),0)}
print (Alert)
})
#send heartbeat every given interval
async({
p=1
while (p==1){
await(delay(Heartbeat))
ws$send(JsonKeepAlive)
}
})
}
DiscordSignals (BotToken)
Discord.py 有一组广泛的函数关于这种连接性,但我无法理解它。
我找到了一个解决方案......可能不是最优雅的,但仍然是一个解决方案,但请随时发布任何替代解决方案作为遗产。
我的解决方案是这样的:事实证明,Discord 和 R 之间的连接中断可能是由其中任何一个引起的,并且可能有多种原因。
所以我的解决方案是创建一个异步任务检查连接是否打开,如果没有则重置连接。我已经让这个连接运行了 24 小时并且仍然处于开启状态,而在该时间间隔内可能有 4 次崩溃。
DiscordSignals(BotToken) #Start connection
#Check in the background for the connection, if close open again.
async({
q=1
while (q==1){
await(delay(5))
Socket=ws$readyState()[1] #If opened, value should be 1
if (Socket!=1){
print("Restart");
ws$close();
DiscordSignals(BotToken);
await(delay(40))} #wait some time for next check, to prevent connecting too many times
}
})