Merge branch 'dev' of https://git.118im.com/im_team/im_webapp into dev
This commit is contained in:
@@ -172,10 +172,13 @@ export function GroupDetailColumn({ topicId, peerName, onClose, onOpenHistory }:
|
|||||||
queryClient.setQueryData(['group', topicId], (prev: GroupProfile | undefined) => (prev ? { ...prev, ...data } : data));
|
queryClient.setQueryData(['group', topicId], (prev: GroupProfile | undefined) => (prev ? { ...prev, ...data } : data));
|
||||||
setNameEditing(false);
|
setNameEditing(false);
|
||||||
// The renamer's OWN sidebar/header (`contact.public?.fn`, native SDK state) doesn't update from
|
// The renamer's OWN sidebar/header (`contact.public?.fn`, native SDK state) doesn't update from
|
||||||
// this REST call either -- only from the `group.profile.updated` push topics.ts now listens for,
|
// this REST call either -- only from the `group.settings.updated` push topics.ts listens for,
|
||||||
// which this account won't receive for its own action. Trigger the same SDK-sanctioned refresh
|
// which this account won't receive for its own action. `data` here is already the fresh REST
|
||||||
// directly instead of waiting on an unconfirmed self-echo of that push.
|
// response, so apply it locally via `_processMetaDesc` (live-confirmed to reach `me.contacts()`,
|
||||||
tinode.getTopic(topicId).getMeta(tinode.getTopic(topicId).startMetaQuery().withDesc().build()).catch(() => {});
|
// see topics.ts's comment on the same call) instead of an extra `getMeta(...withDesc())` round
|
||||||
|
// trip -- that SDK-sanctioned path was live-instrumented and found to reliably time out (504) or
|
||||||
|
// return stale data against this backend, so it's not used anywhere in this fix anymore.
|
||||||
|
tinode.getTopic(topicId)._processMetaDesc({ public: { fn: data.name, name: data.name } });
|
||||||
},
|
},
|
||||||
onError: (err) => showError(err, '群名保存失败'),
|
onError: (err) => showError(err, '群名保存失败'),
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+18
@@ -183,6 +183,24 @@ declare module 'tinode-sdk' {
|
|||||||
getMeta(query: unknown): Promise<unknown>;
|
getMeta(query: unknown): Promise<unknown>;
|
||||||
startMetaQuery(): MetaGetBuilder;
|
startMetaQuery(): MetaGetBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private/internal SDK method (underscore prefix, not part of the documented API) -- normally only
|
||||||
|
* ever called by the SDK itself when a real `{meta desc}` server response arrives. Declared here
|
||||||
|
* and used deliberately, NOT as a first choice: `getMeta(startMetaQuery().withDesc().build())` (the
|
||||||
|
* sanctioned public API for exactly this "re-pull desc from server" need) was live-instrumented
|
||||||
|
* against this backend and found to be genuinely unreliable for group topics -- consistently a
|
||||||
|
* 504 timeout (~5.4s, every attempt, including 10+s after the write) on a brand-new topic, and on
|
||||||
|
* an established topic a fast-but-STALE response whose `public.fn` still reflected the pre-rename
|
||||||
|
* name (confirmed by round-tripping a real REST rename immediately followed by this call). Calling
|
||||||
|
* this directly with data already known-fresh (from a REST response we trust) sidesteps that
|
||||||
|
* broken path entirely -- confirmed by reading the SDK's own source that it merges `e.public` onto
|
||||||
|
* the topic's existing `public` object (other fields like `version` survive) and, for a non-`me`
|
||||||
|
* topic, forwards the update to the `me` topic's own subscription cache via `onMetaSub`/
|
||||||
|
* `onSubsUpdated` -- i.e. the exact same fan-out a genuine server push would trigger. Live-confirmed
|
||||||
|
* this reaches `me.contacts()` (same object reference as `topic.public`, verified live).
|
||||||
|
*/
|
||||||
|
_processMetaDesc(desc: { public?: Partial<TopicDescPublic> }): void;
|
||||||
|
|
||||||
/** Builds the `{pub}` packet shape but does not send it -- pair with `publishDraft`/`publishMessage`. */
|
/** Builds the `{pub}` packet shape but does not send it -- pair with `publishDraft`/`publishMessage`. */
|
||||||
createMessage(content: DraftyContent | string, noEcho?: boolean): StoredMessage;
|
createMessage(content: DraftyContent | string, noEcho?: boolean): StoredMessage;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
// getParams -- so this always leaves first when already subscribed, then resubscribes.
|
// getParams -- so this always leaves first when already subscribed, then resubscribes.
|
||||||
import type { Contact, StoredMessage, Topic } from 'tinode-sdk';
|
import type { Contact, StoredMessage, Topic } from 'tinode-sdk';
|
||||||
|
|
||||||
|
import { getGroup } from '@/lib/api/groups';
|
||||||
import { MESSAGES_PAGE } from '@/lib/config';
|
import { MESSAGES_PAGE } from '@/lib/config';
|
||||||
|
|
||||||
import { getTinode, onReauthenticated } from './connection';
|
import { getTinode, onReauthenticated } from './connection';
|
||||||
@@ -128,7 +129,22 @@ function notifyTopic(topicName: string) {
|
|||||||
pendingAnyNotification = true;
|
pendingAnyNotification = true;
|
||||||
if (!notifyFrameScheduled) {
|
if (!notifyFrameScheduled) {
|
||||||
notifyFrameScheduled = true;
|
notifyFrameScheduled = true;
|
||||||
requestAnimationFrame(flushTopicNotifications);
|
// Live-confirmed real bug (surfaced while testing an unrelated group-rename fix, in a webview whose
|
||||||
|
// frame compositing was paused, i.e. genuinely not painting -- not just an ordinary backgrounded
|
||||||
|
// browser tab): a `requestAnimationFrame` scheduled while the page isn't compositing frames can go
|
||||||
|
// uncalled indefinitely rather than merely deferred-until-visible. Since `notifyFrameScheduled` only
|
||||||
|
// resets to false inside the callback, one dropped frame permanently wedges this guard, silently
|
||||||
|
// freezing EVERY future topic-list update (not just the group name) until a full page reload -- data
|
||||||
|
// kept arriving and updating correctly underneath (confirmed live: `me.contacts()` had the right
|
||||||
|
// data the whole time), only the UI never found out. `document.hidden` costs nothing to check and
|
||||||
|
// `setTimeout` is never silently dropped the way this rAF was, so route through it whenever the page
|
||||||
|
// isn't visible; keep `requestAnimationFrame` for the visible case since that's what actually gives
|
||||||
|
// the intended one-flush-per-paint batching this function exists for.
|
||||||
|
if (typeof document !== 'undefined' && document.hidden) {
|
||||||
|
setTimeout(flushTopicNotifications, 0);
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(flushTopicNotifications);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,19 +343,24 @@ function wireTopicCallbacks(topic: Topic) {
|
|||||||
topic.getMeta(topic.startMetaQuery().withData(seq, seq + 1, 1).build()).catch(() => {});
|
topic.getMeta(topic.startMetaQuery().withData(seq, seq + 1, 1).build()).catch(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// docs/IM-前后端对接文档.md:1542: `PATCH .../groups/{topic}` (rename/avatar/description) pushes a
|
// docs/IM-前后端对接文档.md:1542 documents this push as `group.profile.updated`, but a real rename,
|
||||||
// custom `{info what:"group", event:"group.profile.updated"}` to every other online member -- same
|
// live-instrumented (logging the raw `info` object as it arrived), showed the actual wire event is
|
||||||
// undocumented-to-the-SDK shape as `group.dissolved` above, so nothing here ever refreshed the
|
// `{what:"group", event:"group.settings.updated"}` -- same doc-vs-wire drift already seen elsewhere
|
||||||
// topic's native `public` fields on receipt. Live-confirmed the actual gap: the sidebar/header name
|
// in this backend. Matching the real event name fixes only half the bug: the sidebar/header name
|
||||||
// comes from `contact.public?.fn` (native SDK state, see ChatListColumn.tsx), which a REST-only
|
// comes from `contact.public?.fn` (native SDK state, see ChatListColumn.tsx), which a REST-only
|
||||||
// mutation never touches for ANYONE -- not just other members, but the renamer's own other tabs/
|
// mutation never touches for anyone, and the "obvious" fix -- `getMeta(startMetaQuery().withDesc()
|
||||||
// views too -- and only ever got refreshed as a side effect of the unrelated focus-triggered
|
// .build())`, the SDK's own sanctioned way to re-pull desc from the server -- was live-instrumented
|
||||||
// `reconcileMeSubs()`, which is why refocus "fixed" it for everyone. `withDesc()` is the SDK's own
|
// too and found to be genuinely broken against this backend: a consistent 504 timeout (~5.4s, every
|
||||||
// sanctioned way to re-pull `public`/description from the server (contrast the abandoned approach
|
// attempt, still failing 10+s after the write) on a brand-new topic, and on an established topic a
|
||||||
// of manually patching `Topic._processMetaDesc` tried earlier for a different bug -- that one was
|
// fast-but-stale response whose `public.fn` still held the pre-rename name. Using the already-
|
||||||
// reverted for inconclusive verification; this one goes through a real server round-trip instead).
|
// reliable REST `getGroup()` instead (confirmed live to return the fresh name immediately after a
|
||||||
if (groupEvent?.what === 'group' && groupEvent.event === 'group.profile.updated') {
|
// rename, every time) and applying it locally via `_processMetaDesc` -- the same internal method the
|
||||||
topic.getMeta(topic.startMetaQuery().withDesc().build()).catch(() => {});
|
// SDK itself calls when a real `{meta desc}` response arrives, live-confirmed to correctly reach
|
||||||
|
// `me.contacts()` -- sidesteps the broken path entirely instead of routing through it.
|
||||||
|
if (groupEvent?.what === 'group' && groupEvent.event === 'group.settings.updated') {
|
||||||
|
getGroup(topic.name)
|
||||||
|
.then((data) => topic._processMetaDesc({ public: { fn: data.name, name: data.name } }))
|
||||||
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
topic.onMetaDesc = notify;
|
topic.onMetaDesc = notify;
|
||||||
|
|||||||
Reference in New Issue
Block a user