You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Polls: count undecryptable poll relations (#3163)
This commit is contained in:
@ -132,7 +132,7 @@ describe("Poll", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("filters relations for relevent response events", async () => {
|
it("filters relations for relevent response events", async () => {
|
||||||
const replyEvent = new MatrixEvent({ type: "m.room.message" });
|
const replyEvent = makeRelatedEvent({ type: "m.room.message" });
|
||||||
const stableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.stable! });
|
const stableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.stable! });
|
||||||
const unstableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.unstable });
|
const unstableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.unstable });
|
||||||
|
|
||||||
@ -188,6 +188,47 @@ describe("Poll", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("undecryptable relations", () => {
|
||||||
|
it("counts undecryptable relation events when getting responses", async () => {
|
||||||
|
const replyEvent = makeRelatedEvent({ type: "m.room.message" });
|
||||||
|
const stableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.stable! });
|
||||||
|
const undecryptableEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.unstable });
|
||||||
|
jest.spyOn(undecryptableEvent, "isDecryptionFailure").mockReturnValue(true);
|
||||||
|
|
||||||
|
mockClient.relations.mockResolvedValue({
|
||||||
|
events: [replyEvent, stableResponseEvent, undecryptableEvent],
|
||||||
|
});
|
||||||
|
const poll = new Poll(basePollStartEvent, mockClient, room);
|
||||||
|
jest.spyOn(poll, "emit");
|
||||||
|
await poll.getResponses();
|
||||||
|
expect(poll.undecryptableRelationsCount).toBe(1);
|
||||||
|
expect(poll.emit).toHaveBeenCalledWith(PollEvent.UndecryptableRelations, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds to undercryptable event count when new relation is undecryptable", async () => {
|
||||||
|
const replyEvent = makeRelatedEvent({ type: "m.room.message" });
|
||||||
|
const stableResponseEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.stable! });
|
||||||
|
const undecryptableEvent = makeRelatedEvent({ type: M_POLL_RESPONSE.unstable });
|
||||||
|
const undecryptableEvent2 = makeRelatedEvent({ type: M_POLL_RESPONSE.unstable });
|
||||||
|
jest.spyOn(undecryptableEvent, "isDecryptionFailure").mockReturnValue(true);
|
||||||
|
jest.spyOn(undecryptableEvent2, "isDecryptionFailure").mockReturnValue(true);
|
||||||
|
|
||||||
|
mockClient.relations.mockResolvedValue({
|
||||||
|
events: [replyEvent, stableResponseEvent, undecryptableEvent],
|
||||||
|
});
|
||||||
|
const poll = new Poll(basePollStartEvent, mockClient, room);
|
||||||
|
jest.spyOn(poll, "emit");
|
||||||
|
await poll.getResponses();
|
||||||
|
expect(poll.undecryptableRelationsCount).toBe(1);
|
||||||
|
|
||||||
|
await poll.onNewRelation(undecryptableEvent2);
|
||||||
|
|
||||||
|
expect(poll.undecryptableRelationsCount).toBe(2);
|
||||||
|
|
||||||
|
expect(poll.emit).toHaveBeenCalledWith(PollEvent.UndecryptableRelations, 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("with poll end event", () => {
|
describe("with poll end event", () => {
|
||||||
const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: "@bob@server.org" });
|
const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: "@bob@server.org" });
|
||||||
const unstablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.unstable!, sender: "@bob@server.org" });
|
const unstablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.unstable!, sender: "@bob@server.org" });
|
||||||
|
@ -28,6 +28,7 @@ export enum PollEvent {
|
|||||||
Update = "Poll.update",
|
Update = "Poll.update",
|
||||||
Responses = "Poll.Responses",
|
Responses = "Poll.Responses",
|
||||||
Destroy = "Poll.Destroy",
|
Destroy = "Poll.Destroy",
|
||||||
|
UndecryptableRelations = "Poll.UndecryptableRelations",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PollEventHandlerMap = {
|
export type PollEventHandlerMap = {
|
||||||
@ -35,6 +36,7 @@ export type PollEventHandlerMap = {
|
|||||||
[PollEvent.Destroy]: (pollIdentifier: string) => void;
|
[PollEvent.Destroy]: (pollIdentifier: string) => void;
|
||||||
[PollEvent.End]: () => void;
|
[PollEvent.End]: () => void;
|
||||||
[PollEvent.Responses]: (responses: Relations) => void;
|
[PollEvent.Responses]: (responses: Relations) => void;
|
||||||
|
[PollEvent.UndecryptableRelations]: (count: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterResponseRelations = (
|
const filterResponseRelations = (
|
||||||
@ -45,7 +47,6 @@ const filterResponseRelations = (
|
|||||||
} => {
|
} => {
|
||||||
const responseEvents = relationEvents.filter((event) => {
|
const responseEvents = relationEvents.filter((event) => {
|
||||||
if (event.isDecryptionFailure()) {
|
if (event.isDecryptionFailure()) {
|
||||||
// @TODO(kerrya) PSG-1023 track and return these
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@ -66,6 +67,11 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
private relationsNextBatch: string | undefined;
|
private relationsNextBatch: string | undefined;
|
||||||
private responses: null | Relations = null;
|
private responses: null | Relations = null;
|
||||||
private endEvent: MatrixEvent | undefined;
|
private endEvent: MatrixEvent | undefined;
|
||||||
|
/**
|
||||||
|
* Keep track of undecryptable relations
|
||||||
|
* As incomplete result sets affect poll results
|
||||||
|
*/
|
||||||
|
private undecryptableRelationEventIds = new Set<string>();
|
||||||
|
|
||||||
public constructor(public readonly rootEvent: MatrixEvent, private matrixClient: MatrixClient, private room: Room) {
|
public constructor(public readonly rootEvent: MatrixEvent, private matrixClient: MatrixClient, private room: Room) {
|
||||||
super();
|
super();
|
||||||
@ -80,6 +86,10 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
return this.rootEvent.getId()!;
|
return this.rootEvent.getId()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get endEventId(): string | undefined {
|
||||||
|
return this.endEvent?.getId();
|
||||||
|
}
|
||||||
|
|
||||||
public get isEnded(): boolean {
|
public get isEnded(): boolean {
|
||||||
return !!this.endEvent;
|
return !!this.endEvent;
|
||||||
}
|
}
|
||||||
@ -88,6 +98,10 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
return this._isFetchingResponses;
|
return this._isFetchingResponses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get undecryptableRelationsCount(): number {
|
||||||
|
return this.undecryptableRelationEventIds.size;
|
||||||
|
}
|
||||||
|
|
||||||
public async getResponses(): Promise<Relations> {
|
public async getResponses(): Promise<Relations> {
|
||||||
// if we have already fetched some responses
|
// if we have already fetched some responses
|
||||||
// just return them
|
// just return them
|
||||||
@ -124,10 +138,13 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
const pollEndTimestamp = this.endEvent?.getTs() || Number.MAX_SAFE_INTEGER;
|
const pollEndTimestamp = this.endEvent?.getTs() || Number.MAX_SAFE_INTEGER;
|
||||||
const { responseEvents } = filterResponseRelations([event], pollEndTimestamp);
|
const { responseEvents } = filterResponseRelations([event], pollEndTimestamp);
|
||||||
|
|
||||||
|
this.countUndecryptableEvents([event]);
|
||||||
|
|
||||||
if (responseEvents.length) {
|
if (responseEvents.length) {
|
||||||
responseEvents.forEach((event) => {
|
responseEvents.forEach((event) => {
|
||||||
this.responses!.addEvent(event);
|
this.responses!.addEvent(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit(PollEvent.Responses, this.responses);
|
this.emit(PollEvent.Responses, this.responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,6 +190,7 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
|
|
||||||
this.relationsNextBatch = allRelations.nextBatch ?? undefined;
|
this.relationsNextBatch = allRelations.nextBatch ?? undefined;
|
||||||
this.responses = responses;
|
this.responses = responses;
|
||||||
|
this.countUndecryptableEvents(allRelations.events);
|
||||||
|
|
||||||
// while there are more pages of relations
|
// while there are more pages of relations
|
||||||
// fetch them
|
// fetch them
|
||||||
@ -209,6 +227,19 @@ export class Poll extends TypedEventEmitter<Exclude<PollEvent, PollEvent.New>, P
|
|||||||
this.emit(PollEvent.Responses, this.responses);
|
this.emit(PollEvent.Responses, this.responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private countUndecryptableEvents = (events: MatrixEvent[]): void => {
|
||||||
|
const undecryptableEventIds = events
|
||||||
|
.filter((event) => event.isDecryptionFailure())
|
||||||
|
.map((event) => event.getId()!);
|
||||||
|
|
||||||
|
const previousCount = this.undecryptableRelationsCount;
|
||||||
|
this.undecryptableRelationEventIds = new Set([...this.undecryptableRelationEventIds, ...undecryptableEventIds]);
|
||||||
|
|
||||||
|
if (this.undecryptableRelationsCount !== previousCount) {
|
||||||
|
this.emit(PollEvent.UndecryptableRelations, this.undecryptableRelationsCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private validateEndEvent(endEvent?: MatrixEvent): boolean {
|
private validateEndEvent(endEvent?: MatrixEvent): boolean {
|
||||||
if (!endEvent) {
|
if (!endEvent) {
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user