fix: 打通登录门禁死锁,失败信息区分未连接/登录被拒/未通过验证
继续修复部署时暴露的门禁设计问题: - 登录门禁死锁:/login、/register、简幻通的 /auth 本身就是登录流程的一部分, 原先门禁把它们一并拦下,形成「要先登录才能发登录指令」,账号永远卡在未验证状态。 新增 server.preLoginCommands 白名单(默认 login,l,register,reg,auth), 这些前缀在未验证时也放行,其余指令仍要求已完成验证。 - 离线时指令被静默丢弃却回报「已发送」:bot.chat() 在未连接时无处可发。 canSendCommand() 现在要求已连接并进入世界,失败信息区分 「未连接」「登录被服务器拒绝」「未通过登录验证」三种情况并给出对应建议。 - 前端配置表单支持 list 类型字段(逗号分隔的字符串数组)。 测试从 252 增至 263,全部通过。
这个提交包含在:
+38
-7
@@ -301,16 +301,22 @@ class BotPool extends EventEmitter {
|
||||
|
||||
/**
|
||||
* 向某机器人发送游戏指令。
|
||||
*
|
||||
* 登录门禁由 BotManager 判定:验证类指令(login / register / auth 等)即使在
|
||||
* 未通过验证时也放行,否则会出现「要先登录才能发登录指令」的死锁。
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string} command 不带斜杠的指令
|
||||
* @returns {{ok: boolean, message: string}}
|
||||
*/
|
||||
sendCommand(id, command) {
|
||||
const entry = this.require(id);
|
||||
if (!entry.manager.canOperate()) {
|
||||
return { ok: false, message: `${entry.connection.username} 未完成登录验证,已拒绝发送指令` };
|
||||
const text = String(command || '').replace(/^\//, '').trim();
|
||||
if (!text) return { ok: false, message: '指令为空' };
|
||||
if (!entry.manager.canSendCommand(text)) {
|
||||
return { ok: false, message: describeSendFailure(entry.manager, text) };
|
||||
}
|
||||
const ok = entry.manager.sendCommand(command.replace(/^\//, ''));
|
||||
const ok = entry.manager.sendCommand(text);
|
||||
return { ok, message: ok ? '已发送:' + command : '发送失败' };
|
||||
}
|
||||
|
||||
@@ -322,11 +328,14 @@ class BotPool extends EventEmitter {
|
||||
*/
|
||||
sendChat(id, message) {
|
||||
const entry = this.require(id);
|
||||
if (!entry.manager.canOperate()) {
|
||||
return { ok: false, message: `${entry.connection.username} 未完成登录验证,已拒绝发送消息` };
|
||||
}
|
||||
const text = String(message || '').trim();
|
||||
if (!text) return { ok: false, message: '消息为空' };
|
||||
if (!entry.manager.canOperate()) {
|
||||
if (entry.manager.state !== 'online' || !entry.manager.bot) {
|
||||
return { ok: false, message: `${entry.connection.username} 当前未连接(状态:${entry.manager.state}),消息未发送` };
|
||||
}
|
||||
return { ok: false, message: `${entry.connection.username} 未完成登录验证,已拒绝发送公屏消息` };
|
||||
}
|
||||
const ok = entry.manager.sendChat(text);
|
||||
return { ok, message: ok ? '已发送' : '发送失败' };
|
||||
}
|
||||
@@ -377,4 +386,26 @@ class BotPool extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { BotPool };
|
||||
/**
|
||||
* 生成「为什么这条指令发不出去」的可操作说明。
|
||||
*
|
||||
* 区分「没连上」与「连上了但没过登录验证」——两者的处理方式完全不同,
|
||||
* 笼统报一句「发送失败」会让用户无从下手。
|
||||
*
|
||||
* @param {import('./botManager').BotManager} manager
|
||||
* @param {string} command 不带斜杠的指令
|
||||
* @returns {string}
|
||||
*/
|
||||
function describeSendFailure(manager, command) {
|
||||
const name = manager.connection.username;
|
||||
if (manager.state !== 'online' || !manager.bot) {
|
||||
return `${name} 当前未连接(状态:${manager.state}),指令未发送;请先重连或等待自动重连`;
|
||||
}
|
||||
if (manager.loginFailed) {
|
||||
return `${name} 登录被服务器拒绝,请检查 .env 中的账号密码`;
|
||||
}
|
||||
return `${name} 未完成登录验证,已拒绝发送 /${command};`
|
||||
+ '若是验证类指令(login / register / auth),可在配置的「允许免登录发送的指令前缀」中放行';
|
||||
}
|
||||
|
||||
module.exports = { BotPool, describeSendFailure };
|
||||
|
||||
在新工单中引用
屏蔽一个用户