From 429e83bd23c20f3f2eb55ca871a9dc55f144bbd4 Mon Sep 17 00:00:00 2001 From: Shakker Date: Fri, 31 Jul 2026 12:04:48 +0100 Subject: [PATCH] fix: exclude archived Buzz rooms from peer snapshots --- extensions/buzz/src/directory-state.test.ts | 2 + extensions/buzz/src/directory-state.ts | 6 ++- extensions/buzz/src/directory.test.ts | 38 +++++++++++++++++- extensions/buzz/src/directory.ts | 43 +++++++++++---------- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/extensions/buzz/src/directory-state.test.ts b/extensions/buzz/src/directory-state.test.ts index 5c1d73ae40db..743e7bd5dd46 100644 --- a/extensions/buzz/src/directory-state.test.ts +++ b/extensions/buzz/src/directory-state.test.ts @@ -194,6 +194,7 @@ describe("Buzz directory state", () => { expect(state.activeRoomIds()).toEqual([]); expect(state.isRoomArchived(ROOM_ID)).toBe(true); + expect(state.listPeers({})).toEqual([]); expect(state.listGroups({})).toEqual([]); expect(state.listGroupMembers({ groupId: ROOM_ID })).toEqual([]); @@ -213,6 +214,7 @@ describe("Buzz directory state", () => { expect(state.activeRoomIds()).toEqual([ROOM_ID]); expect(state.isRoomArchived(ROOM_ID)).toBe(false); + expect(state.listPeers({})).not.toEqual([]); expect(state.listGroups({})).toEqual([ expect.objectContaining({ id: `buzz:${ROOM_ID}`, name: "Restored room" }), ]); diff --git a/extensions/buzz/src/directory-state.ts b/extensions/buzz/src/directory-state.ts index 64a3ea3a5458..d09a39f833dd 100644 --- a/extensions/buzz/src/directory-state.ts +++ b/extensions/buzz/src/directory-state.ts @@ -278,7 +278,11 @@ export class BuzzDirectoryState { listPeers(params: { query?: string | null; limit?: number | null }): ChannelDirectoryEntry[] { const peers = new Set(); - for (const membership of this.#memberships.values()) { + for (const roomId of this.activeRoomIds()) { + const membership = this.#memberships.get(roomId); + if (!membership) { + continue; + } for (const publicKey of membership.members) { if (publicKey !== this.#publicKey) { peers.add(publicKey); diff --git a/extensions/buzz/src/directory.test.ts b/extensions/buzz/src/directory.test.ts index 1c6c1bef1527..4f99840e838b 100644 --- a/extensions/buzz/src/directory.test.ts +++ b/extensions/buzz/src/directory.test.ts @@ -7,6 +7,7 @@ const relayMocks = vi.hoisted(() => ({ close: vi.fn(), connect: vi.fn(async () => {}), filters: [] as Filter[], + roomArchived: false, send: vi.fn(async () => {}), subscribe: vi.fn(), })); @@ -83,6 +84,7 @@ describe("Buzz live directory", () => { beforeEach(() => { vi.clearAllMocks(); relayMocks.filters.length = 0; + relayMocks.roomArchived = false; gatewayMocks.activeBus = undefined; vi.stubGlobal( "fetch", @@ -122,6 +124,7 @@ describe("Buzz live directory", () => { tags: [ ["d", ROOM_ID], ["name", "Engineering"], + ...(relayMocks.roomArchived ? [["archived", "true"]] : []), ], }), ); @@ -173,13 +176,13 @@ describe("Buzz live directory", () => { expect(relayMocks.filters).toEqual([ { - kinds: [39_002], + kinds: [39_000], authors: [RELAY_PUBLIC_KEY], "#d": [ROOM_ID], limit: 1, }, { - kinds: [39_000], + kinds: [39_002], authors: [RELAY_PUBLIC_KEY], "#d": [ROOM_ID], limit: 1, @@ -190,6 +193,37 @@ describe("Buzz live directory", () => { expect(relayMocks.close).toHaveBeenCalledOnce(); }); + it("does not load peers or memberships from archived rooms", async () => { + relayMocks.roomArchived = true; + const { listBuzzDirectoryPeersLive } = await import("./directory.js"); + const cfg = { + channels: { + buzz: { + relayUrl: "wss://buzz.example.com", + privateKey: PRIVATE_KEY, + groups: { [ROOM_ID]: {} }, + }, + }, + } as unknown as OpenClawConfig; + + await expect( + listBuzzDirectoryPeersLive({ + cfg, + accountId: "default", + }), + ).resolves.toEqual([]); + + expect(relayMocks.filters).toEqual([ + { + kinds: [39_000], + authors: [RELAY_PUBLIC_KEY], + "#d": [ROOM_ID], + limit: 1, + }, + { kinds: [0], authors: [BOT_PUBLIC_KEY], limit: 1 }, + ]); + }); + it("refreshes only room listings when an active bus already owns directory state", async () => { const refreshDirectory = vi.fn(async () => {}); const self = vi.fn(() => ({ kind: "user", id: BOT_PUBLIC_KEY, name: "OpenClaw" })); diff --git a/extensions/buzz/src/directory.ts b/extensions/buzz/src/directory.ts index 7644cbae60b0..d1376af9e764 100644 --- a/extensions/buzz/src/directory.ts +++ b/extensions/buzz/src/directory.ts @@ -68,29 +68,30 @@ async function loadBuzzDirectoryState( signal: timeoutSignal, }); try { + await queryBuzzDirectoryRooms({ + relay, + relayPublicKey, + state: configured.state, + channelIds: configured.channelIds, + signal: timeoutSignal, + }); + const activeChannelIds = configured.state.activeRoomIds(); configured.state.replaceMemberships( - await queryBuzzRoomMemberships({ - relay, - relayPublicKey, - channelIds: configured.channelIds, - signal: timeoutSignal, - }), + activeChannelIds.length > 0 + ? await queryBuzzRoomMemberships({ + relay, + relayPublicKey, + channelIds: activeChannelIds, + signal: timeoutSignal, + }) + : new Map(), ); - await Promise.all([ - queryBuzzDirectoryRooms({ - relay, - relayPublicKey, - state: configured.state, - channelIds: configured.channelIds, - signal: timeoutSignal, - }), - queryBuzzDirectoryProfiles({ - relay, - state: configured.state, - publicKeys: configured.state.profilePublicKeys(), - signal: timeoutSignal, - }), - ]); + await queryBuzzDirectoryProfiles({ + relay, + state: configured.state, + publicKeys: configured.state.profilePublicKeys(), + signal: timeoutSignal, + }); return configured.state; } finally { relay.close();