Skip to content

Commit 075543a

Browse files
committed
Check for MSC2762_UPDATE_STATE version to decide if read_event (state events) reads from the state or the timeline
1 parent c7275d0 commit 075543a

File tree

2 files changed

+80
-16
lines changed

2 files changed

+80
-16
lines changed

src/ClientWidgetApi.ts

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ export class ClientWidgetApi extends EventEmitter {
349349
});
350350
}
351351

352+
private async supportsUpdateState(): Promise<boolean> {
353+
return (await this.getWidgetVersions()).includes(UnstableApiVersion.MSC2762_UPDATE_STATE);
354+
}
355+
352356
private handleCapabilitiesRenegotiate(request: IRenegotiateCapabilitiesActionRequest): void {
353357
// acknowledge first
354358
this.transport.reply<IWidgetApiAcknowledgeResponseData>(request, {});
@@ -514,28 +518,38 @@ export class ClientWidgetApi extends EventEmitter {
514518
});
515519
}
516520
}
517-
518-
// For backwards compatibility we still call the deprecated
519-
// readRoomEvents and readStateEvents methods in case the client isn't
520-
// letting us know the currently viewed room via setViewedRoomId
521-
const events = request.data.room_ids === undefined && askRoomIds.length === 0
522-
? await (
521+
522+
let events: IRoomEvent[];
523+
524+
if(request.data.room_ids === undefined && askRoomIds.length === 0){
525+
// For backwards compatibility we still call the deprecated
526+
// readRoomEvents and readStateEvents methods in case the client isn't
527+
// letting us know the currently viewed room via setViewedRoomId
528+
events = await (
523529
// This returns [] with the current driver of Element Web.
524530
// Add default implementations of the `readRoomEvents` and `readStateEvents`
525531
// methods to use `readRoomTimeline` and `readRoomState` if they are not overwritten.
526532
request.data.state_key === undefined
527533
? this.driver.readRoomEvents(request.data.type, msgtype, limit, null, since)
528534
: this.driver.readStateEvents(request.data.type, stateKey, limit, null)
529-
)
530-
: (
531-
request.data.state_key === undefined
532-
? await Promise.all(askRoomIds.map(roomId =>
533-
this.driver.readRoomTimeline(roomId, request.data.type, msgtype, stateKey, limit, since),
534-
))
535-
: await Promise.all(askRoomIds.map(roomId =>
536-
this.driver.readRoomState(roomId, request.data.type, stateKey),
537-
))
538-
).flat(1);
535+
);
536+
}else if(await this.supportsUpdateState()){
537+
// Calling read_events with a stateKey still reads from the rooms timeline (not the room state).
538+
events = (await Promise.all(askRoomIds.map(roomId =>
539+
this.driver.readRoomTimeline(roomId, request.data.type, msgtype, stateKey, limit, since),
540+
))).flat(1) ;
541+
}else{
542+
// TODO: remove this once `UnstableApiVersion.MSC2762_UPDATE_STATE` becomes stable.
543+
// Before version `MSC2762_UPDATE_STATE` we used readRoomState for read_events actions.
544+
events = (request.data.state_key === undefined
545+
? await Promise.all(askRoomIds.map(roomId =>
546+
this.driver.readRoomTimeline(roomId, request.data.type, msgtype, stateKey, limit, since),
547+
))
548+
: await Promise.all(askRoomIds.map(roomId =>
549+
this.driver.readRoomState(roomId, request.data.type, stateKey),
550+
))).flat(1) ;
551+
}
552+
539553
this.transport.reply<IReadEventFromWidgetResponseData>(request, { events });
540554
}
541555

test/ClientWidgetApi-test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,7 @@ describe('ClientWidgetApi', () => {
14891489
describe('org.matrix.msc2876.read_events action', () => {
14901490
it('reads events from a specific room', async () => {
14911491
const roomId = '!room:example.org';
1492+
jest.spyOn(clientWidgetApi,"getWidgetVersions").mockReturnValue(new Promise(r=>r([])));
14921493
const event = createRoomEvent({ room_id: roomId, type: 'net.example.test', content: 'test' });
14931494
driver.readRoomTimeline.mockImplementation(async (rId) => {
14941495
if (rId === roomId) return [event];
@@ -1528,6 +1529,7 @@ describe('ClientWidgetApi', () => {
15281529
it('reads events from all rooms', async () => {
15291530
const roomId = '!room:example.org';
15301531
const otherRoomId = '!other-room:example.org';
1532+
jest.spyOn(clientWidgetApi,"getWidgetVersions").mockReturnValue(new Promise(r=>r([])));
15311533
const event = createRoomEvent({ room_id: roomId, type: 'net.example.test', content: 'test' });
15321534
const otherRoomEvent = createRoomEvent({ room_id: otherRoomId, type: 'net.example.test', content: 'hi' });
15331535
driver.getKnownRooms.mockReturnValue([roomId, otherRoomId]);
@@ -1571,6 +1573,7 @@ describe('ClientWidgetApi', () => {
15711573
});
15721574

15731575
it('reads state events with any state key', async () => {
1576+
jest.spyOn(clientWidgetApi, "getWidgetVersions").mockReturnValue(new Promise(r=>r([])));
15741577
driver.readRoomState.mockResolvedValue([
15751578
createRoomEvent({ type: 'net.example.test', state_key: 'A' }),
15761579
createRoomEvent({ type: 'net.example.test', state_key: 'B' }),
@@ -1632,6 +1635,7 @@ describe('ClientWidgetApi', () => {
16321635
});
16331636

16341637
it('reads state events with a specific state key', async () => {
1638+
jest.spyOn(clientWidgetApi, "getWidgetVersions").mockReturnValue(new Promise(r=>r([])));
16351639
driver.readRoomState.mockResolvedValue([
16361640
createRoomEvent({ type: 'net.example.test', state_key: 'B' }),
16371641
]);
@@ -1665,6 +1669,52 @@ describe('ClientWidgetApi', () => {
16651669
);
16661670
});
16671671

1672+
it('reads state events with a specific state key from the timeline when using UnstableApiVersion.MSC2762_UPDATE_STATE', async () => {
1673+
jest.spyOn(clientWidgetApi, "getWidgetVersions").mockReturnValue(new Promise(r=>r(CurrentApiVersions)));
1674+
// with version MSC2762_UPDATE_STATE we wan the read Events action to read state events from the timeline.
1675+
driver.readRoomTimeline.mockResolvedValue([
1676+
createRoomEvent({ type: 'net.example.test', state_key: 'B' }),
1677+
]);
1678+
1679+
const event: IReadEventFromWidgetActionRequest = {
1680+
api: WidgetApiDirection.FromWidget,
1681+
widgetId: 'test',
1682+
requestId: '0',
1683+
action: WidgetApiFromWidgetAction.MSC2876ReadEvents,
1684+
data: {
1685+
type: 'net.example.test',
1686+
state_key: 'B',
1687+
},
1688+
};
1689+
1690+
await loadIframe(['org.matrix.msc2762.receive.state_event:net.example.test#B']);
1691+
1692+
1693+
clientWidgetApi.setViewedRoomId('!room-id');
1694+
1695+
// we clear the mock here because setViewedRoomId will push the room state and therefore read it
1696+
// from the driver.
1697+
driver.readRoomState.mockClear();
1698+
// clearing this as well so it gets the same treatment as readRoomState for reference
1699+
driver.readRoomTimeline.mockClear();
1700+
1701+
emitEvent(new CustomEvent('', { detail: event }));
1702+
1703+
1704+
await waitFor(() => {
1705+
expect(transport.reply).toHaveBeenCalledWith(event, {
1706+
events: [
1707+
createRoomEvent({ type: 'net.example.test', state_key: 'B' }),
1708+
],
1709+
});
1710+
});
1711+
1712+
expect(driver.readRoomTimeline).toHaveBeenLastCalledWith(
1713+
"!room-id", "net.example.test", undefined, "B", 0, undefined
1714+
);
1715+
expect(driver.readRoomState).not.toHaveBeenCalled();
1716+
});
1717+
16681718
it('fails to read state events with a specific state key', async () => {
16691719
const event: IReadEventFromWidgetActionRequest = {
16701720
api: WidgetApiDirection.FromWidget,

0 commit comments

Comments
 (0)