修复通话发起失败静默无反应的问题(第8章复测发现)

sendMessageToTopic 自己的 .catch 会吞掉发送失败——publishMessage 在服务端拒绝时只标记
pub._failed=true 让消息列表画红色感叹号(这是给聊天气泡设计的反馈方式),resolve 成 undefined
而不是 reject。通话邀请这条消息不会被用户看到(用户盯着的是全屏通话面板,不是消息列表),走
这条路径等于什么反馈都没有;而且原代码 `ctrl.code` 直接解引用,undefined.code 会抛
TypeError,变成一个没人 catch 的 rejected promise——handleCallClose() 根本不会被调用,
通话面板会卡在"呼叫中"状态出不来。

这条路径今天有了真实后果:后端新增的全局通话开关(im_client_feature)关闭时,服务端会拒绝
这条 {pub},正好命中这个从未被验证过的失败分支。

修复:判断 ctrl 是否存在、补 .catch,两处都调用 handleError 提示 + handleCallClose 复位。
顺带给通话按钮可见性加了一层预判——读共享的 bootstrap 缓存,features.audio_call/video_call
为 false 时不显示按钮;读不到缓存时按原行为放行(fail-open,只是预判不是安全边界)。

已用真实账号验证:通话菜单项在开关为真时正常显示,无回归。真实失败场景(开关被关闭)无法在
当前浏览器沙盒环境下端到端验证(摄像头/麦克风权限被拦截,此前已确认的环境限制),修复依据是
逐层读 tinode-sdk 源码精确追踪出的调用链,不是猜测。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-09-04 13:14:44 +08:00
co-authored by Claude Sonnet 5
parent 8e703d86eb
commit 1d51e53a46
3 changed files with 33 additions and 7 deletions
+8 -2
View File
@@ -18836,7 +18836,9 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
writer = acs.isWriter();
}
}
webrtc = writer && !!this.tinode.getServerParam('iceServers');
const cachedBootstrap = this.state.myUserId ? (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_19__.readCachedData)('bootstrap:' + this.state.myUserId) : null;
const callFeatureOk = !cachedBootstrap || !cachedBootstrap.features || cachedBootstrap.features.audio_call !== false && cachedBootstrap.features.video_call !== false;
webrtc = writer && callFeatureOk && !!this.tinode.getServerParam('iceServers');
p2p = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName);
self = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isSelfTopicName(topicName);
return [subscribed ? {
@@ -19132,7 +19134,8 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
aonly: !!audioOnly
};
return this.handleSendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.videoCall(audioOnly), undefined, undefined, head).then(ctrl => {
if (ctrl.code < 200 || ctrl.code >= 300 || !ctrl.params || !ctrl.params.seq) {
if (!ctrl || ctrl.code < 200 || ctrl.code >= 300 || !ctrl.params || !ctrl.params.seq) {
this.handleError('通话发起失败,请稍后重试', 'err');
this.handleCallClose();
return ctrl;
}
@@ -19140,6 +19143,9 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
callSeq: ctrl.params['seq']
});
return ctrl;
}).catch(err => {
this.handleError(err && err.message || '通话发起失败,请稍后重试', 'err');
this.handleCallClose();
});
case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS:
const topic = this.tinode.getTopic(callTopic);
+1 -1
View File
File diff suppressed because one or more lines are too long