修复消息首页会话预览恒为"暂无消息",即使会话有真实历史消息
message-center-view.jsx 的预览文字读 topic.latestMessage(),这个方法
只会从话题自己的本地消息缓存里取值——而这个缓存只有在话题真正被
subscribe 过一次数据拉取后才会填充。me.contacts()(resetContactList)
给出的是每个联系人真实的、已缓存的Topic实例,包括用户这次会话里
从未打开过的——这些话题的latestMessage()恒为undefined,即使同一个
对象自己的touched/seq字段能证明服务端真实存在历史消息。
新增prefetchLatestMessagePreviews():对chatList里seq>0但本地缓存为空
的话题,一次性拉取最新1条消息填充预览。用一个Set跟踪已尝试过的话题,
避免resetContactList()(几乎每个{meta}/{pres}事件都会触发一次)反复
重新拉取同一个话题。
调试过程中发现并修正了自己犯的两个错误:(1) resetContactList()在
websocket握手完成前就会被本地持久化缓存恢复触发一次,此时的subscribe
必然503失败,加了isConnected()判断跳过,避免过早失败把话题永久标记
为"已尝试";(2) Topic.subscribe(getParams, setParams)的参数顺序搞反,
把查询对象传成了第二个参数(setParams),导致subscribe成功但发出的
{sub}包完全没有get子句,从未真正请求过消息数据。
已用真实浏览器验证:好友kcg051307会话(真实71条历史消息)刷新页面
后预览从"暂无消息"变为真实的最新消息内容,未读角标数字不受影响
(确认没有误将未读消息标记为已读)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ca71667975
commit
2ee8bac6a0
@@ -216,6 +216,17 @@ class TinodeWeb extends React.Component {
|
|||||||
|
|
||||||
this.selfRef = React.createRef();
|
this.selfRef = React.createRef();
|
||||||
|
|
||||||
|
// message-center-view.jsx's conversation-list preview reads topic.latestMessage(), which the
|
||||||
|
// vendored SDK only ever populates from a topic's own local message cache -- itself only filled
|
||||||
|
// in once that specific topic has actually been subscribed with a data fetch. me.contacts()
|
||||||
|
// (resetContactList below) yields the real, already-cached Topic instances for every contact --
|
||||||
|
// including ones the user has never opened this session -- so most rows fall straight through to
|
||||||
|
// the '暂无消息' fallback despite `touched`/`seq` on the same object proving real history exists
|
||||||
|
// server-side. This tracks which topics we've already kicked off a one-shot "just the last
|
||||||
|
// message" fetch for, so repeated resetContactList() calls (it fires on nearly every {meta}/{pres}
|
||||||
|
// event, not just once at boot) don't re-subscribe the same topic over and over.
|
||||||
|
this.previewPrefetchAttempted = new Set();
|
||||||
|
|
||||||
this.state = this.getBlankState();
|
this.state = this.getBlankState();
|
||||||
|
|
||||||
this.handleResize = this.handleResize.bind(this);
|
this.handleResize = this.handleResize.bind(this);
|
||||||
@@ -1284,6 +1295,8 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.prefetchLatestMessagePreviews(newState.chatList);
|
||||||
|
|
||||||
const past = new Date(0);
|
const past = new Date(0);
|
||||||
newState.chatList.sort((a, b) => {
|
newState.chatList.sort((a, b) => {
|
||||||
// Pinned topics take precedence.
|
// Pinned topics take precedence.
|
||||||
@@ -1297,6 +1310,41 @@ class TinodeWeb extends React.Component {
|
|||||||
this.setState(newState);
|
this.setState(newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See the comment on this.previewPrefetchAttempted in the constructor for why this exists.
|
||||||
|
// seq > 0 is the same 'does this topic actually have any messages at all' signal
|
||||||
|
// message-center-view.jsx would otherwise have no way to distinguish from 'genuinely empty' --
|
||||||
|
// skip topics with no history instead of firing a subscribe that would just come back empty.
|
||||||
|
//
|
||||||
|
// !this.tinode.isConnected() live repro: resetContactList() fires as soon as the persisted local
|
||||||
|
// cache restores 'me's last-known contact list (log line "Persistent cache initialized"), which is
|
||||||
|
// *before* the websocket has even sent {hi} -- every subscribe() call made at that point instantly
|
||||||
|
// rejects with a 503 "Websocket is not connected". Skip attempting entirely while disconnected
|
||||||
|
// (rather than catching the failure) so these topics *aren't* added to previewPrefetchAttempted yet
|
||||||
|
// -- resetContactList() runs again moments later once the real {meta topic:'me'} response arrives
|
||||||
|
// over the now-live connection, and this gets a genuine second try then.
|
||||||
|
prefetchLatestMessagePreviews(chatList) {
|
||||||
|
if (!this.tinode.isConnected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const c of chatList) {
|
||||||
|
if (!c.topic || c.seq <= 0 || c.latestMessage() || this.previewPrefetchAttempted.has(c.topic)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.previewPrefetchAttempted.add(c.topic);
|
||||||
|
// Topic.subscribe(getParams, setParams) -- the query is the *first* argument. Passing it
|
||||||
|
// second (as setParams) was silently swallowed: the resulting {sub} packet had no `get`
|
||||||
|
// clause at all (confirmed live: `out: {"sub":{"id":...,"topic":"..."}}`, no `get` key), so
|
||||||
|
// subscribe succeeded but never actually requested -- let alone received -- any message data.
|
||||||
|
c.subscribe(c.startMetaQuery().withLaterData(1).build()).catch(err => {
|
||||||
|
// Leave it in previewPrefetchAttempted either way -- a topic that fails once we're
|
||||||
|
// definitely connected (e.g. a stale contact the user no longer has access to) isn't going
|
||||||
|
// to succeed on the next resetContactList() a moment later either, and would otherwise retry
|
||||||
|
// on every single {meta}/{pres} event for the rest of the session.
|
||||||
|
console.warn(`Failed to prefetch latest message for '${c.topic}'`, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static checkIfPinsUpdated(me, chatList) {
|
static checkIfPinsUpdated(me, chatList) {
|
||||||
for (let i = 0; i < chatList.length; i++) {
|
for (let i = 0; i < chatList.length; i++) {
|
||||||
const c = chatList[i];
|
const c = chatList[i];
|
||||||
|
|||||||
Reference in New Issue
Block a user