如何实现R远程实时监听Discord消息(无需本地Discord客户端)
解决R远程实时监听Discord消息的问题
核心问题修复
你的代码存在两个关键问题,对应解决方案如下:
1. 心跳机制错误(连接40秒失效)
错误点:
- 心跳包的op码应为
1而非2(op=2是身份验证包) - 心跳逻辑放在主流程只会执行一次,无法定时发送
- 未正确使用Discord返回的心跳间隔和消息序列号(seq)
- 心跳包的op码应为
修复方案:
在收到Discord的Hello消息(op=10)后,用异步定时任务发送心跳包,同时记录每次消息的seq值用于心跳验证。
2. 无需打开Discord客户端
Discord Gateway的WebSocket连接完全独立于本地客户端,只要使用合法的Bot Token(建议用机器人账号Token而非个人账号Token,降低账号风险),无需打开任何Discord客户端即可远程连接。
完整可运行代码
library(websocket) library(jsonlite) library(later) # 替换为你的Bot Token token <- "YOUR_BOT_TOKEN" ws <- NULL heartbeat_interval <- NULL last_seq <- NULL heartbeat_timer <- NULL # 初始化WebSocket连接 init_websocket <- function() { ws <<- WebSocket$new("wss://gateway.discord.gg/?v=9&encoding=json") # 身份验证 payload auth_payload <- toJSON( list( op = 2, d = list( token = token, intents = 513, # 包含GUILDS和GUILD_MESSAGES权限 properties = list( os = "linux", browser = "R-websocket", device = "R-websocket" ) ) ), auto_unbox = TRUE ) # 连接打开时发送身份验证 ws$onOpen(function(event) { cat("连接已打开,发送身份验证...\n") ws$send(auth_payload) }) # 处理收到的消息 ws$onMessage(function(event) { message <- fromJSON(event$data) last_seq <<- message$s # 记录消息序列号 # 处理Hello消息,启动心跳 if (message$op == 10) { heartbeat_interval <<- message$d$heartbeat_interval / 1000 cat("收到Hello消息,心跳间隔:", heartbeat_interval, "秒\n") send_heartbeat() } # 处理消息创建事件(MESSAGE_CREATE) if (message$t == "MESSAGE_CREATE") { content <- message$d$content author <- message$d$author$username cat("[", author, "] ", content, "\n", sep = "") } # 处理心跳确认(仅日志) if (message$op == 11) { cat("心跳确认收到\n") } }) # 处理连接关闭,自动重连 ws$onClose(function(event) { cat("连接关闭,错误码:", event$code, ",原因:", event$reason, "\n") cat("正在尝试重连...\n") later(init_websocket, delay = 5) # 5秒后重连 }) # 处理连接错误 ws$onError(function(event) { cat("连接错误:", event$message, "\n") }) } # 发送心跳包 send_heartbeat <- function() { heartbeat_payload <- toJSON( list( op = 1, d = last_seq # 使用最后收到的序列号,首次为NULL ), auto_unbox = TRUE ) cat("发送心跳...\n") ws$send(heartbeat_payload) # 定时发送下一次心跳(间隔减1秒避免超时) heartbeat_timer <<- later(send_heartbeat, delay = heartbeat_interval - 1) } # 启动连接 init_websocket() # 保持R会话运行(避免脚本结束) while (TRUE) { later::run_now(timeout = 1) Sys.sleep(1) }
关键说明
- 依赖包:用
later包实现异步定时任务,替代原代码中无效的轮询逻辑,确保心跳包按时发送 - Intents权限:
intents=513是GUILDS(1)和GUILD_MESSAGES(512)的权限总和,需在Discord开发者门户的Bot设置中开启对应Privileged Gateway Intents - Token安全:不要将Token硬编码在公开代码中,建议用环境变量加载(如
token <- Sys.getenv("DISCORD_BOT_TOKEN")) - 重连机制:代码包含自动重连逻辑,连接意外断开时会尝试重新连接
内容的提问来源于stack exchange,提问作者Camilo
相关产品推荐
相关产品推荐

