fix(web): show the author of incoming messages right away [CI]
Messages from other members or devices used to render as an unknown member until the space structure refreshed. Use the author account the server records for the object, together with the loaded profiles, when the item arrives.
This commit is contained in:
1 parent
12980ba6fe
commit
fb5800f81d
3 files changed
+23
-4
No files matched your search
@@ -14,6 +14,10 @@ const states = new Map<string, CryptoState>();
|
||||
const domainId = (channelId: string, domain: string, epoch: number) => `${channelId}:${domain}:${epoch}`;
|
||||
const contextId = (spaceId: string, channelId: string, domain: string, epoch: number) => `${spaceId}:${channelId}:${domain}:${epoch}`;
|
||||
const loaded = new Map<string, DataKeys>();
|
||||
/** 服务端登记的对象作者(账号)。收到别人的消息时据此先显示名字,不必等结构刷新 */
|
||||
export function objectAuthorAccount(resourceId: string, itemId: string): string | undefined {
|
||||
return states.get(resourceId)?.objects.find(o => o.itemId === itemId)?.authorAccount ?? undefined;
|
||||
}
|
||||
export function clearDataKeys(): void { objectKeys.clear(); states.clear(); loaded.clear(); }
|
||||
export function attachDataKeys(session: ChannelSession, resource: SavedResource): void {
|
||||
if (resource.kind !== 'channel') return;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { parseLogRecords, parseEnvelope, toBase64Url, type ChannelSession, type LogRecord, type ReceivedItem } from '@webdrop/core';
|
||||
import { canDecryptRecord, objectEventProjection, readDataKeys, verifyObjectDeletion, verifyObjectEvent } from './channelDataKeys';
|
||||
import { canDecryptRecord, objectAuthorAccount, objectEventProjection, readDataKeys, verifyObjectDeletion, verifyObjectEvent } from './channelDataKeys';
|
||||
import { getResource, cacheResource, type SavedResource } from '../database';
|
||||
import { channelCache } from './resourceMetadata';
|
||||
import { loadWorkspace } from './workspaceStructure';
|
||||
import type { FileItem, Item, Snapshot } from '../types';
|
||||
import { cachedPerson, loadWorkspace } from './workspaceStructure';
|
||||
import { avatarThumbnail } from './senderSnapshot';
|
||||
import type { FileItem, Item, SenderInfo, Snapshot } from '../types';
|
||||
import { previewKindOf } from '@/lib/fileKind';
|
||||
import { blobs, readers } from './sessions';
|
||||
import { showRejected, publishWorkspace } from './presentation';
|
||||
@@ -31,6 +32,15 @@ export function mapReceived(item: ReceivedItem): Item {
|
||||
text: new TextDecoder().decode(item.content) };
|
||||
}
|
||||
|
||||
/** 别人发的消息:服务端登记了作者账号,先用它(和已加载的资料)显示名字,避免「未知成员」闪一下 */
|
||||
async function authorOf(resourceId: string, itemId: string): Promise<SenderInfo | undefined> {
|
||||
const username = objectAuthorAccount(resourceId, itemId);
|
||||
if (!username) return undefined;
|
||||
const person = cachedPerson(resourceId, username);
|
||||
const avatar = person?.avatar ? await avatarThumbnail(person.avatar) : undefined;
|
||||
return { username, displayName: person?.displayName || username, ...(avatar ? { avatar } : {}) };
|
||||
}
|
||||
|
||||
export async function applyChannelRecord(resource: SavedResource, session: ChannelSession, input: Uint8Array | LogRecord): Promise<void> {
|
||||
if (!(input instanceof Uint8Array)) {
|
||||
const itemId = input.kind === 'frame' ? toBase64Url(parseEnvelope(input.envelope).itemId) : input.itemId;
|
||||
@@ -80,7 +90,8 @@ export async function applyChannelRecord(resource: SavedResource, session: Chann
|
||||
} else {
|
||||
const blob = item.kind === 'file' && event.item.complete ? new Blob([event.item.content], { type: item.mime }) : undefined;
|
||||
if (blob) blobs.set(`${resource.id}:${item.id}`, blob);
|
||||
publishWorkspace(resource.id, { t: 'item', item });
|
||||
const author = await authorOf(resource.id, item.id);
|
||||
publishWorkspace(resource.id, { t: 'item', item: author ? { ...item, author } : item });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ async function publish(id: string, body: WorkspaceBody): Promise<WorkspaceBody>
|
||||
export async function cachedWorkspace(id: string): Promise<WorkspaceBody> {
|
||||
return current.get(id) ?? loadWorkspace(id);
|
||||
}
|
||||
/** 已加载的成员资料(没有时返回 undefined) */
|
||||
export function cachedPerson(id: string, username: string): WorkspaceBody['people'][number] | undefined {
|
||||
return current.get(id)?.people.find(person => person.username === username);
|
||||
}
|
||||
export async function loadWorkspace(id: string): Promise<WorkspaceBody> {
|
||||
const { session } = await getSession(id);
|
||||
const body = await apiFetch(`/spaces/${id}/structure`, { headers: session.authHeaders('read') }).then(r => r.json() as Promise<WorkspaceBody>);
|
||||
|
||||
Reference in new issue
Block a user