mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-20 14:30:57 +00:00
Matrix: invalidate DM cache on membership changes
This commit is contained in:
@@ -8,14 +8,14 @@ function createMockClient(params: {
|
||||
selfDirect?: boolean;
|
||||
members?: string[];
|
||||
}) {
|
||||
const members = params.members ?? ["@alice:example.org", "@bot:example.org"];
|
||||
let members = params.members ?? ["@alice:example.org", "@bot:example.org"];
|
||||
return {
|
||||
dms: {
|
||||
update: vi.fn().mockResolvedValue(undefined),
|
||||
isDm: vi.fn().mockReturnValue(params.isDm === true),
|
||||
},
|
||||
getUserId: vi.fn().mockResolvedValue("@bot:example.org"),
|
||||
getJoinedRoomMembers: vi.fn().mockResolvedValue(members),
|
||||
getJoinedRoomMembers: vi.fn().mockImplementation(async () => members),
|
||||
getRoomStateEvent: vi
|
||||
.fn()
|
||||
.mockImplementation(async (_roomId: string, eventType: string, stateKey: string) => {
|
||||
@@ -27,6 +27,9 @@ function createMockClient(params: {
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
__setMembers(next: string[]) {
|
||||
members = next;
|
||||
},
|
||||
} as unknown as MatrixClient;
|
||||
}
|
||||
|
||||
@@ -98,6 +101,33 @@ describe("createDirectRoomTracker", () => {
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("re-checks room membership after invalidation when a DM gains extra members", async () => {
|
||||
const client = createMockClient({ isDm: true });
|
||||
const tracker = createDirectRoomTracker(client);
|
||||
|
||||
await expect(
|
||||
tracker.isDirectMessage({
|
||||
roomId: "!room:example.org",
|
||||
senderId: "@alice:example.org",
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
|
||||
(client as MatrixClient & { __setMembers: (members: string[]) => void }).__setMembers([
|
||||
"@alice:example.org",
|
||||
"@bot:example.org",
|
||||
"@mallory:example.org",
|
||||
]);
|
||||
|
||||
tracker.invalidateRoom("!room:example.org");
|
||||
|
||||
await expect(
|
||||
tracker.isDirectMessage({
|
||||
roomId: "!room:example.org",
|
||||
senderId: "@alice:example.org",
|
||||
}),
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("still recognizes exact 2-member rooms when member state also claims is_direct", async () => {
|
||||
const tracker = createDirectRoomTracker(createMockClient({ senderDirect: true }));
|
||||
await expect(
|
||||
|
||||
@@ -64,6 +64,11 @@ export function createDirectRoomTracker(client: MatrixClient, opts: DirectRoomTr
|
||||
};
|
||||
|
||||
return {
|
||||
invalidateRoom: (roomId: string): void => {
|
||||
joinedMembersCache.delete(roomId);
|
||||
lastDmUpdateMs = 0;
|
||||
log(`matrix: invalidated dm cache room=${roomId}`);
|
||||
},
|
||||
isDirectMessage: async (params: DirectMessageCheck): Promise<boolean> => {
|
||||
const { roomId, senderId } = params;
|
||||
await refreshDmCache();
|
||||
|
||||
@@ -37,6 +37,7 @@ function createHarness(params?: {
|
||||
const onRoomMessage = vi.fn(async () => {});
|
||||
const listVerifications = vi.fn(async () => params?.verifications ?? []);
|
||||
const sendMessage = vi.fn(async () => "$notice");
|
||||
const invalidateRoom = vi.fn();
|
||||
const logger = { info: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
||||
const formatNativeDependencyHint = vi.fn(() => "install hint");
|
||||
const client = {
|
||||
@@ -66,6 +67,9 @@ function createHarness(params?: {
|
||||
accountId: params?.accountId ?? "default",
|
||||
encryption: params?.authEncryption ?? true,
|
||||
} as MatrixAuth,
|
||||
directTracker: {
|
||||
invalidateRoom,
|
||||
},
|
||||
logVerboseMessage: vi.fn(),
|
||||
warnedEncryptedRooms: new Set<string>(),
|
||||
warnedCryptoMissingRooms: new Set<string>(),
|
||||
@@ -82,6 +86,7 @@ function createHarness(params?: {
|
||||
return {
|
||||
onRoomMessage,
|
||||
sendMessage,
|
||||
invalidateRoom,
|
||||
roomEventListener,
|
||||
listVerifications,
|
||||
logger,
|
||||
@@ -117,6 +122,23 @@ describe("registerMatrixMonitorEvents verification routing", () => {
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("invalidates direct-room membership cache on room member events", async () => {
|
||||
const { invalidateRoom, roomEventListener } = createHarness();
|
||||
|
||||
roomEventListener("!room:example.org", {
|
||||
event_id: "$member1",
|
||||
sender: "@alice:example.org",
|
||||
state_key: "@mallory:example.org",
|
||||
type: EventType.RoomMember,
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
membership: "join",
|
||||
},
|
||||
});
|
||||
|
||||
expect(invalidateRoom).toHaveBeenCalledWith("!room:example.org");
|
||||
});
|
||||
|
||||
it("posts verification request notices directly into the room", async () => {
|
||||
const { onRoomMessage, sendMessage, roomMessageListener } = createHarness();
|
||||
if (!roomMessageListener) {
|
||||
|
||||
@@ -11,6 +11,9 @@ export function registerMatrixMonitorEvents(params: {
|
||||
cfg: CoreConfig;
|
||||
client: MatrixClient;
|
||||
auth: MatrixAuth;
|
||||
directTracker?: {
|
||||
invalidateRoom: (roomId: string) => void;
|
||||
};
|
||||
logVerboseMessage: (message: string) => void;
|
||||
warnedEncryptedRooms: Set<string>;
|
||||
warnedCryptoMissingRooms: Set<string>;
|
||||
@@ -22,6 +25,7 @@ export function registerMatrixMonitorEvents(params: {
|
||||
cfg,
|
||||
client,
|
||||
auth,
|
||||
directTracker,
|
||||
logVerboseMessage,
|
||||
warnedEncryptedRooms,
|
||||
warnedCryptoMissingRooms,
|
||||
@@ -68,6 +72,7 @@ export function registerMatrixMonitorEvents(params: {
|
||||
);
|
||||
|
||||
client.on("room.invite", (roomId: string, event: MatrixRawEvent) => {
|
||||
directTracker?.invalidateRoom(roomId);
|
||||
const eventId = event?.event_id ?? "unknown";
|
||||
const sender = event?.sender ?? "unknown";
|
||||
const isDirect = (event?.content as { is_direct?: boolean } | undefined)?.is_direct === true;
|
||||
@@ -77,6 +82,7 @@ export function registerMatrixMonitorEvents(params: {
|
||||
});
|
||||
|
||||
client.on("room.join", (roomId: string, event: MatrixRawEvent) => {
|
||||
directTracker?.invalidateRoom(roomId);
|
||||
const eventId = event?.event_id ?? "unknown";
|
||||
logVerboseMessage(`matrix: join room=${roomId} id=${eventId}`);
|
||||
});
|
||||
@@ -105,6 +111,7 @@ export function registerMatrixMonitorEvents(params: {
|
||||
return;
|
||||
}
|
||||
if (eventType === EventType.RoomMember) {
|
||||
directTracker?.invalidateRoom(roomId);
|
||||
const membership = (event?.content as { membership?: string } | undefined)?.membership;
|
||||
const stateKey = (event as { state_key?: string }).state_key ?? "";
|
||||
logVerboseMessage(
|
||||
|
||||
@@ -212,6 +212,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
||||
cfg,
|
||||
client,
|
||||
auth,
|
||||
directTracker,
|
||||
logVerboseMessage,
|
||||
warnedEncryptedRooms,
|
||||
warnedCryptoMissingRooms,
|
||||
|
||||
Reference in New Issue
Block a user