1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-09 10:22:46 +03:00

Merge branch 'robertlong/group-call' into dbkr/gcmerge_oct22_3

This commit is contained in:
David Baker
2022-10-24 18:53:54 +01:00
committed by GitHub
3 changed files with 153 additions and 7 deletions

View File

@@ -30,7 +30,7 @@ import {
ITurnServer, ITurnServer,
} from "matrix-widget-api"; } from "matrix-widget-api";
import { createRoomWidgetClient } from "../../src/matrix"; import { createRoomWidgetClient, MsgType } from "../../src/matrix";
import { MatrixClient, ClientEvent, ITurnServer as IClientTurnServer } from "../../src/client"; import { MatrixClient, ClientEvent, ITurnServer as IClientTurnServer } from "../../src/client";
import { SyncState } from "../../src/sync"; import { SyncState } from "../../src/sync";
import { ICapabilities } from "../../src/embedded"; import { ICapabilities } from "../../src/embedded";
@@ -43,10 +43,15 @@ class MockWidgetApi extends EventEmitter {
public requestCapability = jest.fn(); public requestCapability = jest.fn();
public requestCapabilities = jest.fn(); public requestCapabilities = jest.fn();
public requestCapabilityForRoomTimeline = jest.fn(); public requestCapabilityForRoomTimeline = jest.fn();
public requestCapabilityToSendEvent = jest.fn();
public requestCapabilityToReceiveEvent = jest.fn();
public requestCapabilityToSendMessage = jest.fn();
public requestCapabilityToReceiveMessage = jest.fn();
public requestCapabilityToSendState = jest.fn(); public requestCapabilityToSendState = jest.fn();
public requestCapabilityToReceiveState = jest.fn(); public requestCapabilityToReceiveState = jest.fn();
public requestCapabilityToSendToDevice = jest.fn(); public requestCapabilityToSendToDevice = jest.fn();
public requestCapabilityToReceiveToDevice = jest.fn(); public requestCapabilityToReceiveToDevice = jest.fn();
public sendRoomEvent = jest.fn(() => ({ event_id: `$${Math.random()}` }));
public sendStateEvent = jest.fn(); public sendStateEvent = jest.fn();
public sendToDevice = jest.fn(); public sendToDevice = jest.fn();
public readStateEvents = jest.fn(() => []); public readStateEvents = jest.fn(() => []);
@@ -75,6 +80,66 @@ describe("RoomWidgetClient", () => {
await client.startClient(); await client.startClient();
}; };
describe("events", () => {
it("sends", async () => {
await makeClient({ sendEvent: ["org.matrix.rageshake_request"] });
expect(widgetApi.requestCapabilityForRoomTimeline).toHaveBeenCalledWith("!1:example.org");
expect(widgetApi.requestCapabilityToSendEvent).toHaveBeenCalledWith("org.matrix.rageshake_request");
await client.sendEvent("!1:example.org", "org.matrix.rageshake_request", { request_id: 123 });
expect(widgetApi.sendRoomEvent).toHaveBeenCalledWith(
"org.matrix.rageshake_request", { request_id: 123 }, "!1:example.org",
);
});
it("receives", async () => {
const event = new MatrixEvent({
type: "org.matrix.rageshake_request",
event_id: "$pduhfiidph",
room_id: "!1:example.org",
sender: "@alice:example.org",
content: { request_id: 123 },
}).getEffectiveEvent();
await makeClient({ receiveEvent: ["org.matrix.rageshake_request"] });
expect(widgetApi.requestCapabilityForRoomTimeline).toHaveBeenCalledWith("!1:example.org");
expect(widgetApi.requestCapabilityToReceiveEvent).toHaveBeenCalledWith("org.matrix.rageshake_request");
const emittedEvent = new Promise<MatrixEvent>(resolve => client.once(ClientEvent.Event, resolve));
const emittedSync = new Promise<SyncState>(resolve => client.once(ClientEvent.Sync, resolve));
widgetApi.emit(
`action:${WidgetApiToWidgetAction.SendEvent}`,
new CustomEvent(`action:${WidgetApiToWidgetAction.SendEvent}`, { detail: { data: event } }),
);
// The client should've emitted about the received event
expect((await emittedEvent).getEffectiveEvent()).toEqual(event);
expect(await emittedSync).toEqual(SyncState.Syncing);
// It should've also inserted the event into the room object
const room = client.getRoom("!1:example.org");
expect(room).not.toBeNull();
expect(room!.getLiveTimeline().getEvents().map(e => e.getEffectiveEvent())).toEqual([event]);
});
});
describe("messages", () => {
it("requests permissions for specific message types", async () => {
await makeClient({ sendMessage: [MsgType.Text], receiveMessage: [MsgType.Text] });
expect(widgetApi.requestCapabilityForRoomTimeline).toHaveBeenCalledWith("!1:example.org");
expect(widgetApi.requestCapabilityToSendMessage).toHaveBeenCalledWith(MsgType.Text);
expect(widgetApi.requestCapabilityToReceiveMessage).toHaveBeenCalledWith(MsgType.Text);
});
it("requests permissions for all message types", async () => {
await makeClient({ sendMessage: true, receiveMessage: true });
expect(widgetApi.requestCapabilityForRoomTimeline).toHaveBeenCalledWith("!1:example.org");
expect(widgetApi.requestCapabilityToSendMessage).toHaveBeenCalledWith();
expect(widgetApi.requestCapabilityToReceiveMessage).toHaveBeenCalledWith();
});
// No point in testing sending and receiving since it's done exactly the
// same way as non-message events
});
describe("state events", () => { describe("state events", () => {
const event = new MatrixEvent({ const event = new MatrixEvent({
type: "org.example.foo", type: "org.example.foo",

View File

@@ -3972,9 +3972,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* @param room * @param room
* @param event * @param event
* @returns {Promise} returns a promise which resolves with the result of the send request * @returns {Promise} returns a promise which resolves with the result of the send request
* @private
*/ */
private encryptAndSendEvent(room: Room | null, event: MatrixEvent): Promise<ISendEventResponse> { protected encryptAndSendEvent(room: Room | null, event: MatrixEvent): Promise<ISendEventResponse> {
let cancelled = false; let cancelled = false;
// Add an extra Promise.resolve() to turn synchronous exceptions into promise rejections, // Add an extra Promise.resolve() to turn synchronous exceptions into promise rejections,
// so that we can handle synchronous and asynchronous exceptions with the // so that we can handle synchronous and asynchronous exceptions with the
@@ -4099,7 +4098,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
return this.isRoomEncrypted(roomId) ? EventType.RoomMessageEncrypted : eventType; return this.isRoomEncrypted(roomId) ? EventType.RoomMessageEncrypted : eventType;
} }
private updatePendingEventStatus(room: Room | null, event: MatrixEvent, newStatus: EventStatus) { protected updatePendingEventStatus(room: Room | null, event: MatrixEvent, newStatus: EventStatus) {
if (room) { if (room) {
room.updatePendingEvent(event, newStatus); room.updatePendingEvent(event, newStatus);
} else { } else {

View File

@@ -22,9 +22,10 @@ import {
IWidgetApiAcknowledgeResponseData, IWidgetApiAcknowledgeResponseData,
ISendEventToWidgetActionRequest, ISendEventToWidgetActionRequest,
ISendToDeviceToWidgetActionRequest, ISendToDeviceToWidgetActionRequest,
ISendEventFromWidgetResponseData,
} from "matrix-widget-api"; } from "matrix-widget-api";
import type { IEvent, IContent } from "./models/event"; import { IEvent, IContent, EventStatus } from "./models/event";
import { ISendEventResponse } from "./@types/requests"; import { ISendEventResponse } from "./@types/requests";
import { EventType } from "./@types/event"; import { EventType } from "./@types/event";
import { logger } from "./logger"; import { logger } from "./logger";
@@ -44,17 +45,56 @@ interface IStateEventRequest {
} }
export interface ICapabilities { export interface ICapabilities {
// TODO: Add fields for messages and other non-state events /**
* Event types that this client expects to send.
*/
sendEvent?: string[];
/**
* Event types that this client expects to receive.
*/
receiveEvent?: string[];
/**
* Message types that this client expects to send, or true for all message
* types.
*/
sendMessage?: string[] | true;
/**
* Message types that this client expects to receive, or true for all
* message types.
*/
receiveMessage?: string[] | true;
/**
* Types of state events that this client expects to send.
*/
sendState?: IStateEventRequest[]; sendState?: IStateEventRequest[];
/**
* Types of state events that this client expects to receive.
*/
receiveState?: IStateEventRequest[]; receiveState?: IStateEventRequest[];
/**
* To-device event types that this client expects to send.
*/
sendToDevice?: string[]; sendToDevice?: string[];
/**
* To-device event types that this client expects to receive.
*/
receiveToDevice?: string[]; receiveToDevice?: string[];
/**
* Whether this client needs access to TURN servers.
* @default false
*/
turnServers?: boolean; turnServers?: boolean;
} }
/**
* A MatrixClient that routes its requests through the widget API instead of the
* real CS API.
* @experimental This class is considered unstable!
*/
export class RoomWidgetClient extends MatrixClient { export class RoomWidgetClient extends MatrixClient {
private room: Room; private room: Room;
private widgetApiReady = new Promise<void>(resolve => this.widgetApi.once("ready", resolve)); private widgetApiReady = new Promise<void>(resolve => this.widgetApi.once("ready", resolve));
@@ -70,9 +110,38 @@ export class RoomWidgetClient extends MatrixClient {
super(opts); super(opts);
// Request capabilities for the functionality this client needs to support // Request capabilities for the functionality this client needs to support
if (capabilities.sendState?.length || capabilities.receiveState?.length) { if (
capabilities.sendEvent?.length
|| capabilities.receiveEvent?.length
|| capabilities.sendMessage === true
|| (Array.isArray(capabilities.sendMessage) && capabilities.sendMessage.length)
|| capabilities.receiveMessage === true
|| (Array.isArray(capabilities.receiveMessage) && capabilities.receiveMessage.length)
|| capabilities.sendState?.length
|| capabilities.receiveState?.length
) {
widgetApi.requestCapabilityForRoomTimeline(roomId); widgetApi.requestCapabilityForRoomTimeline(roomId);
} }
capabilities.sendEvent?.forEach(eventType =>
widgetApi.requestCapabilityToSendEvent(eventType),
);
capabilities.receiveEvent?.forEach(eventType =>
widgetApi.requestCapabilityToReceiveEvent(eventType),
);
if (capabilities.sendMessage === true) {
widgetApi.requestCapabilityToSendMessage();
} else if (Array.isArray(capabilities.sendMessage)) {
capabilities.sendMessage.forEach(msgType =>
widgetApi.requestCapabilityToSendMessage(msgType),
);
}
if (capabilities.receiveMessage === true) {
widgetApi.requestCapabilityToReceiveMessage();
} else if (Array.isArray(capabilities.receiveMessage)) {
capabilities.receiveMessage.forEach(msgType =>
widgetApi.requestCapabilityToReceiveMessage(msgType),
);
}
capabilities.sendState?.forEach(({ eventType, stateKey }) => capabilities.sendState?.forEach(({ eventType, stateKey }) =>
widgetApi.requestCapabilityToSendState(eventType, stateKey), widgetApi.requestCapabilityToSendState(eventType, stateKey),
); );
@@ -155,6 +224,19 @@ export class RoomWidgetClient extends MatrixClient {
throw new Error(`Unknown room: ${roomIdOrAlias}`); throw new Error(`Unknown room: ${roomIdOrAlias}`);
} }
protected async encryptAndSendEvent(room: Room, event: MatrixEvent): Promise<ISendEventResponse> {
let response: ISendEventFromWidgetResponseData;
try {
response = await this.widgetApi.sendRoomEvent(event.getType(), event.getContent(), room.roomId);
} catch (e) {
this.updatePendingEventStatus(room, event, EventStatus.NOT_SENT);
throw e;
}
room.updatePendingEvent(event, EventStatus.SENT, response.event_id);
return { event_id: response.event_id };
}
public async sendStateEvent( public async sendStateEvent(
roomId: string, roomId: string,
eventType: string, eventType: string,