Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit f5cd079

Browse files
committed
Add support for sending/receiving events from widgets
Part of MSC2762: matrix-org/matrix-spec-proposals#2762 Requires: matrix-org/matrix-widget-api#9 This is the bare minimum required to send an event to a widget and receive events from widgets. Like the view_room action, this is controlled by a well-known permission key. **Danger**: This allows widgets to potentially modify room state. Use the permissions with care.
1 parent e15041b commit f5cd079

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

src/stores/widgets/StopGapWidget.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
5555
import {getCustomTheme} from "../../theme";
5656
import CountlyAnalytics from "../../CountlyAnalytics";
5757
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
58+
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
59+
import ActiveRoomObserver from "../../ActiveRoomObserver";
5860

5961
// TODO: Destroy all of this code
6062

@@ -329,6 +331,10 @@ export class StopGapWidget extends EventEmitter {
329331
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
330332
});
331333

334+
// Attach listeners for feeding events - the underlying widget classes handle permissions for us
335+
MatrixClientPeg.get().on('event', this.onEvent);
336+
MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted);
337+
332338
if (WidgetType.JITSI.matches(this.mockWidget.type)) {
333339
this.messaging.on("action:set_always_on_screen",
334340
(ev: CustomEvent<IStickyActionRequest>) => {
@@ -422,5 +428,31 @@ export class StopGapWidget extends EventEmitter {
422428
if (!this.started) return;
423429
WidgetMessagingStore.instance.stopMessaging(this.mockWidget);
424430
ActiveWidgetStore.delRoomId(this.mockWidget.id);
431+
432+
if (MatrixClientPeg.get()) {
433+
MatrixClientPeg.get().off('event', this.onEvent);
434+
MatrixClientPeg.get().off('Event.decrypted', this.onEventDecrypted);
435+
}
436+
}
437+
438+
private onEvent = (ev: MatrixEvent) => {
439+
if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) return;
440+
if (ev.getRoomId() !== ActiveRoomObserver.activeRoomId) return;
441+
this.feedEvent(ev);
442+
};
443+
444+
private onEventDecrypted = (ev: MatrixEvent) => {
445+
if (ev.isDecryptionFailure()) return;
446+
if (ev.getRoomId() !== ActiveRoomObserver.activeRoomId) return;
447+
this.feedEvent(ev);
448+
};
449+
450+
private feedEvent(ev: MatrixEvent) {
451+
if (!this.messaging) return;
452+
453+
const raw = ev.event;
454+
this.messaging.feedEvent(raw).catch(e => {
455+
console.error("Error sending event to widget: ", e);
456+
});
425457
}
426458
}

src/stores/widgets/StopGapWidgetDriver.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Capability, WidgetDriver, WidgetType } from "matrix-widget-api";
17+
import { Capability, ISendEventDetails, WidgetDriver, WidgetEventCapability, WidgetType } from "matrix-widget-api";
1818
import { iterableUnion } from "../../utils/iterables";
1919
import { MatrixClientPeg } from "../../MatrixClientPeg";
2020
import { arrayFastClone } from "../../utils/arrays";
2121
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
22+
import ActiveRoomObserver from "../../ActiveRoomObserver";
2223

2324
// TODO: Purge this from the universe
2425

@@ -47,7 +48,30 @@ export class StopGapWidgetDriver extends WidgetDriver {
4748
allowedCaps.push(ElementWidgetCapabilities.CanChangeViewedRoom);
4849
}
4950
}
51+
if (Array.isArray(wkPerms["event_actions"])) {
52+
if (wkPerms["event_actions"].includes(this.forType)) {
53+
allowedCaps.push(...WidgetEventCapability.findEventCapabilities(requested).map(c => c.raw));
54+
}
55+
}
5056
}
5157
return new Set(iterableUnion(requested, allowedCaps));
5258
}
59+
60+
public async sendEvent(eventType: string, content: any, stateKey: string = null): Promise<ISendEventDetails> {
61+
const client = MatrixClientPeg.get();
62+
const roomId = ActiveRoomObserver.activeRoomId;
63+
64+
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
65+
66+
let r: {event_id: string} = null;
67+
if (stateKey !== null) {
68+
// state event
69+
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
70+
} else {
71+
// message event
72+
r = await client.sendEvent(roomId, eventType, content);
73+
}
74+
75+
return {roomId, eventId: r.event_id};
76+
}
5377
}

0 commit comments

Comments
 (0)