From 1233d6a4726cd07393882c71128c462733cb36ac Mon Sep 17 00:00:00 2001
From: Hugh Nimmo-Smith <hughns@matrix.org>
Date: Wed, 11 Sep 2024 16:55:03 +0100
Subject: [PATCH] Use new crypto api to send to-device messages from widgets

---
 src/stores/widgets/StopGapWidgetDriver.ts | 49 ++++++++++-------------
 1 file changed, 22 insertions(+), 27 deletions(-)

diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts
index b61fafbd52..d12fe5f9f1 100644
--- a/src/stores/widgets/StopGapWidgetDriver.ts
+++ b/src/stores/widgets/StopGapWidgetDriver.ts
@@ -430,33 +430,28 @@ export class StopGapWidgetDriver extends WidgetDriver {
         const client = MatrixClientPeg.safeGet();
 
         if (encrypted) {
-            const deviceInfoMap = await client.crypto!.deviceList.downloadKeys(Object.keys(contentMap), false);
-
-            await Promise.all(
-                Object.entries(contentMap).flatMap(([userId, userContentMap]) =>
-                    Object.entries(userContentMap).map(async ([deviceId, content]): Promise<void> => {
-                        const devices = deviceInfoMap.get(userId);
-                        if (!devices) return;
-
-                        if (deviceId === "*") {
-                            // Send the message to all devices we have keys for
-                            await client.encryptAndSendToDevices(
-                                Array.from(devices.values()).map((deviceInfo) => ({
-                                    userId,
-                                    deviceInfo,
-                                })),
-                                content,
-                            );
-                        } else if (devices.has(deviceId)) {
-                            // Send the message to a specific device
-                            await client.encryptAndSendToDevices(
-                                [{ userId, deviceInfo: devices.get(deviceId)! }],
-                                content,
-                            );
-                        }
-                    }),
-                ),
-            );
+            const crypto = client.getCrypto();
+            if (!crypto) throw new Error("E2EE not enabled");
+
+            // attempt to re-batch these up into a single request
+            const invertedContentMap: { [content: string]: { userId: string; deviceId: string }[] } = {};
+
+            Object.entries(contentMap).forEach(([userId, userContentMap]) =>
+                Object.entries(userContentMap).forEach(([deviceId, content]) => {
+                    const stringifiedContent = JSON.stringify(content);
+                    invertedContentMap[stringifiedContent] = invertedContentMap[stringifiedContent] || [];
+
+                    invertedContentMap[stringifiedContent].push({ userId, deviceId });
+                }),
+            ),
+
+            await Promise.all(Object.entries(invertedContentMap).map(
+                async ([stringifiedContent, recipients]) => {
+                    const batch = await crypto.encryptToDeviceMessages(eventType, recipients, JSON.parse(stringifiedContent));
+
+                    await client.queueToDevice(batch);
+                },
+            ));
         } else {
             await client.queueToDevice({
                 eventType,
-- 
GitLab