resolve live data on initial load

This commit is contained in:
2026-08-31 01:15:32 +08:00
parent c68f8f0bf7
commit 25eb21755f
10 changed files with 293 additions and 50 deletions
+4
View File
@@ -50,6 +50,9 @@ async listFriendStatuses() : Promise<string[]> {
async resolveFriendDisplayName(userId: string) : Promise<string | null> {
return await TAURI_INVOKE("resolve_friend_display_name", { userId });
},
async listLiveData() : Promise<LiveDataSnapshot> {
return await TAURI_INVOKE("list_live_data");
},
async resolveSkin(userId: string, skinHash: string) : Promise<string | null> {
return await TAURI_INVOKE("resolve_skin", { userId, skinHash });
},
@@ -142,6 +145,7 @@ export type FriendInteractionReceived = { interactionId: string; friendId: strin
export type FriendStatusesChanged = { friendIds: string[] }
export type FriendsChanged = { friends: Friend[] }
export type InteractionContent = { type: "text"; text: string } | { type: "wave" } | { type: "image"; mediaType: string; data: string }
export type LiveDataSnapshot = { cursorPositions: Partial<{ [key in string]: CursorPositions }>; foregroundApps: Partial<{ [key in string]: AppMeta }> }
export type NetworkStatusChanged = { statuses: ConnectionStatus[] }
export type ProfileChanged = { profile: User }
export type PuppetMovementMode = "free" | "bottom"
+2 -7
View File
@@ -1,20 +1,15 @@
import { writable } from "svelte/store";
import { commands, events } from "$lib/bindings";
import { removeFriendForegroundApps } from "./live-metadata";
import { retainOnlineForegroundApps } from "./live-metadata";
export const onlineFriendIds = writable<Set<string>>(new Set());
export const friendStatusesListenerError = writable("");
export async function initFriendStatusesListener() {
let current = new Set<string>();
const apply = (friendIds: string[]) => {
const next = new Set(friendIds);
const wentOffline = [...current].filter((friendId) => !next.has(friendId));
current = next;
onlineFriendIds.set(next);
removeFriendForegroundApps(wentOffline);
retainOnlineForegroundApps(next);
};
const unlisten = await events.friendStatusesChanged.listen((event) => {
+15 -3
View File
@@ -10,17 +10,29 @@ import { initSceneConfigurationListener } from "./scene-configuration";
type Unlisten = () => void;
async function initPresenceListeners(): Promise<Unlisten> {
const unlistenLiveMetadata = await initLiveMetadataListeners();
try {
const unlistenFriendStatuses = await initFriendStatusesListener();
return () => {
unlistenFriendStatuses();
unlistenLiveMetadata();
};
} catch (error) {
unlistenLiveMetadata();
throw error;
}
}
export function initAppListeners(): Unlisten {
let disposed = false;
let unlisteners: Unlisten[] = [];
Promise.allSettled([
initFriendsListener(),
initRemotesListener(),
initProfileListener(),
initConnectionStatusesListener(),
initFriendStatusesListener(),
initLiveMetadataListeners(),
initPresenceListeners(),
initInteractionListener(),
initPuppetStatesListener(),
initSceneConfigurationListener(),
+59 -13
View File
@@ -19,20 +19,24 @@ export const liveMetadata = writable<LiveMetadata>({
});
export const liveMetadataListenerError = writable("");
export function removeFriendForegroundApps(friendIds: string[]) {
if (friendIds.length === 0) return;
const removed = new Set(friendIds);
export function retainOnlineForegroundApps(onlineFriendIds: Set<string>) {
liveMetadata.update((metadata) => ({
...metadata,
foregroundApps: new Map(
[...metadata.foregroundApps].filter(([userId]) => !removed.has(userId)),
[...metadata.foregroundApps].filter(
([userId]) =>
userId === metadata.localId || onlineFriendIds.has(userId),
),
),
}));
}
export async function initLiveMetadataListeners() {
let localId = "";
let initializing = true;
let pendingCursorPositions: LiveMetadata["cursorPositions"] | null = null;
let pendingLocalForegroundApp: AppMeta | null = null;
const pendingFriendForegroundApps = new Map<string, AppMeta>();
const updateForegroundApp = (userId: string, meta: AppMeta) => {
liveMetadata.update((current) => ({
@@ -41,34 +45,76 @@ export async function initLiveMetadataListeners() {
}));
};
const applyPendingUpdates = () => {
const cursorPositions = pendingCursorPositions;
if (cursorPositions) {
liveMetadata.update((current) => ({ ...current, cursorPositions }));
pendingCursorPositions = null;
}
if (localId && pendingLocalForegroundApp) {
updateForegroundApp(localId, pendingLocalForegroundApp);
pendingLocalForegroundApp = null;
}
pendingFriendForegroundApps.forEach((meta, friendId) => {
updateForegroundApp(friendId, meta);
});
pendingFriendForegroundApps.clear();
};
const unlisteners = await Promise.all([
events.cursorPositionChanged.listen((event) => {
if (initializing) {
pendingCursorPositions = event.payload.positions;
return;
}
liveMetadata.update((current) => ({
...current,
cursorPositions: event.payload.positions,
}));
}),
events.foregroundAppChanged.listen((event) => {
if (localId) {
if (!initializing && localId) {
updateForegroundApp(localId, event.payload.meta);
} else {
pendingLocalForegroundApp = event.payload.meta;
}
}),
events.friendForegroundAppChanged.listen((event) => {
updateForegroundApp(event.payload.friendId, event.payload.meta);
if (initializing) {
pendingFriendForegroundApps.set(
event.payload.friendId,
event.payload.meta,
);
} else {
updateForegroundApp(event.payload.friendId, event.payload.meta);
}
}),
]);
try {
localId = await commands.getPublicKey();
liveMetadata.update((current) => ({ ...current, localId }));
if (pendingLocalForegroundApp) {
updateForegroundApp(localId, pendingLocalForegroundApp);
pendingLocalForegroundApp = null;
}
const [snapshot] = await Promise.all([
commands.listLiveData(),
commands.getPublicKey().then((resolvedLocalId) => {
localId = resolvedLocalId;
}),
]);
const foregroundApps = new Map<string, AppMeta>();
Object.entries(snapshot.foregroundApps).forEach(([userId, meta]) => {
if (meta) foregroundApps.set(userId, meta);
});
liveMetadata.set({
localId,
cursorPositions: snapshot.cursorPositions,
foregroundApps,
});
initializing = false;
applyPendingUpdates();
} catch (error) {
initializing = false;
if (localId) {
liveMetadata.update((current) => ({ ...current, localId }));
}
applyPendingUpdates();
liveMetadataListenerError.set(String(error));
}