diff options
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-js-sdk/lib/embedded.js')
-rw-r--r-- | includes/external/matrix/node_modules/matrix-js-sdk/lib/embedded.js | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/lib/embedded.js b/includes/external/matrix/node_modules/matrix-js-sdk/lib/embedded.js new file mode 100644 index 0000000..f0baa16 --- /dev/null +++ b/includes/external/matrix/node_modules/matrix-js-sdk/lib/embedded.js @@ -0,0 +1,265 @@ +"use strict"; + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RoomWidgetClient = void 0; +var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); +var _matrixWidgetApi = require("matrix-widget-api"); +var _event = require("./models/event"); +var _event2 = require("./@types/event"); +var _logger = require("./logger"); +var _client = require("./client"); +var _sync = require("./sync"); +var _slidingSyncSdk = require("./sliding-sync-sdk"); +var _user = require("./models/user"); +var _utils = require("./utils"); +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * A MatrixClient that routes its requests through the widget API instead of the + * real CS API. + * @experimental This class is considered unstable! + */ +class RoomWidgetClient extends _client.MatrixClient { + constructor(widgetApi, capabilities, roomId, opts) { + var _capabilities$sendEve, _capabilities$receive, _capabilities$sendSta, _capabilities$receive2, _capabilities$sendEve2, _capabilities$receive3, _capabilities$sendSta2, _capabilities$receive4, _capabilities$sendToD, _capabilities$receive5; + super(opts); + + // Request capabilities for the functionality this client needs to support + this.widgetApi = widgetApi; + this.capabilities = capabilities; + this.roomId = roomId; + (0, _defineProperty2.default)(this, "room", void 0); + (0, _defineProperty2.default)(this, "widgetApiReady", new Promise(resolve => this.widgetApi.once("ready", resolve))); + (0, _defineProperty2.default)(this, "lifecycle", void 0); + (0, _defineProperty2.default)(this, "syncState", null); + (0, _defineProperty2.default)(this, "onEvent", async ev => { + ev.preventDefault(); + + // Verify the room ID matches, since it's possible for the client to + // send us events from other rooms if this widget is always on screen + if (ev.detail.data.room_id === this.roomId) { + const event = new _event.MatrixEvent(ev.detail.data); + await this.syncApi.injectRoomEvents(this.room, [], [event]); + this.emit(_client.ClientEvent.Event, event); + this.setSyncState(_sync.SyncState.Syncing); + _logger.logger.info(`Received event ${event.getId()} ${event.getType()} ${event.getStateKey()}`); + } else { + const { + event_id: eventId, + room_id: roomId + } = ev.detail.data; + _logger.logger.info(`Received event ${eventId} for a different room ${roomId}; discarding`); + } + await this.ack(ev); + }); + (0, _defineProperty2.default)(this, "onToDevice", async ev => { + ev.preventDefault(); + const event = new _event.MatrixEvent({ + type: ev.detail.data.type, + sender: ev.detail.data.sender, + content: ev.detail.data.content + }); + // Mark the event as encrypted if it was, using fake contents and keys since those are unknown to us + if (ev.detail.data.encrypted) event.makeEncrypted(_event2.EventType.RoomMessageEncrypted, {}, "", ""); + this.emit(_client.ClientEvent.ToDeviceEvent, event); + this.setSyncState(_sync.SyncState.Syncing); + await this.ack(ev); + }); + if ((_capabilities$sendEve = capabilities.sendEvent) !== null && _capabilities$sendEve !== void 0 && _capabilities$sendEve.length || (_capabilities$receive = capabilities.receiveEvent) !== null && _capabilities$receive !== void 0 && _capabilities$receive.length || capabilities.sendMessage === true || Array.isArray(capabilities.sendMessage) && capabilities.sendMessage.length || capabilities.receiveMessage === true || Array.isArray(capabilities.receiveMessage) && capabilities.receiveMessage.length || (_capabilities$sendSta = capabilities.sendState) !== null && _capabilities$sendSta !== void 0 && _capabilities$sendSta.length || (_capabilities$receive2 = capabilities.receiveState) !== null && _capabilities$receive2 !== void 0 && _capabilities$receive2.length) { + widgetApi.requestCapabilityForRoomTimeline(roomId); + } + (_capabilities$sendEve2 = capabilities.sendEvent) === null || _capabilities$sendEve2 === void 0 ? void 0 : _capabilities$sendEve2.forEach(eventType => widgetApi.requestCapabilityToSendEvent(eventType)); + (_capabilities$receive3 = capabilities.receiveEvent) === null || _capabilities$receive3 === void 0 ? void 0 : _capabilities$receive3.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$sendSta2 = capabilities.sendState) === null || _capabilities$sendSta2 === void 0 ? void 0 : _capabilities$sendSta2.forEach(({ + eventType, + stateKey + }) => widgetApi.requestCapabilityToSendState(eventType, stateKey)); + (_capabilities$receive4 = capabilities.receiveState) === null || _capabilities$receive4 === void 0 ? void 0 : _capabilities$receive4.forEach(({ + eventType, + stateKey + }) => widgetApi.requestCapabilityToReceiveState(eventType, stateKey)); + (_capabilities$sendToD = capabilities.sendToDevice) === null || _capabilities$sendToD === void 0 ? void 0 : _capabilities$sendToD.forEach(eventType => widgetApi.requestCapabilityToSendToDevice(eventType)); + (_capabilities$receive5 = capabilities.receiveToDevice) === null || _capabilities$receive5 === void 0 ? void 0 : _capabilities$receive5.forEach(eventType => widgetApi.requestCapabilityToReceiveToDevice(eventType)); + if (capabilities.turnServers) { + widgetApi.requestCapability(_matrixWidgetApi.MatrixCapabilities.MSC3846TurnServers); + } + widgetApi.on(`action:${_matrixWidgetApi.WidgetApiToWidgetAction.SendEvent}`, this.onEvent); + widgetApi.on(`action:${_matrixWidgetApi.WidgetApiToWidgetAction.SendToDevice}`, this.onToDevice); + + // Open communication with the host + widgetApi.start(); + } + async startClient(opts = {}) { + var _this$capabilities$re, _this$capabilities$re2; + this.lifecycle = new AbortController(); + + // Create our own user object artificially (instead of waiting for sync) + // so it's always available, even if the user is not in any rooms etc. + const userId = this.getUserId(); + if (userId) { + this.store.storeUser(new _user.User(userId)); + } + + // Even though we have no access token and cannot sync, the sync class + // still has some valuable helper methods that we make use of, so we + // instantiate it anyways + if (opts.slidingSync) { + this.syncApi = new _slidingSyncSdk.SlidingSyncSdk(opts.slidingSync, this, opts, this.buildSyncApiOptions()); + } else { + this.syncApi = new _sync.SyncApi(this, opts, this.buildSyncApiOptions()); + } + this.room = this.syncApi.createRoom(this.roomId); + this.store.storeRoom(this.room); + await this.widgetApiReady; + + // Backfill the requested events + // We only get the most recent event for every type + state key combo, + // so it doesn't really matter what order we inject them in + await Promise.all((_this$capabilities$re = (_this$capabilities$re2 = this.capabilities.receiveState) === null || _this$capabilities$re2 === void 0 ? void 0 : _this$capabilities$re2.map(async ({ + eventType, + stateKey + }) => { + const rawEvents = await this.widgetApi.readStateEvents(eventType, undefined, stateKey, [this.roomId]); + const events = rawEvents.map(rawEvent => new _event.MatrixEvent(rawEvent)); + await this.syncApi.injectRoomEvents(this.room, [], events); + events.forEach(event => { + this.emit(_client.ClientEvent.Event, event); + _logger.logger.info(`Backfilled event ${event.getId()} ${event.getType()} ${event.getStateKey()}`); + }); + })) !== null && _this$capabilities$re !== void 0 ? _this$capabilities$re : []); + this.setSyncState(_sync.SyncState.Syncing); + _logger.logger.info("Finished backfilling events"); + + // Watch for TURN servers, if requested + if (this.capabilities.turnServers) this.watchTurnServers(); + } + stopClient() { + this.widgetApi.off(`action:${_matrixWidgetApi.WidgetApiToWidgetAction.SendEvent}`, this.onEvent); + this.widgetApi.off(`action:${_matrixWidgetApi.WidgetApiToWidgetAction.SendToDevice}`, this.onToDevice); + super.stopClient(); + this.lifecycle.abort(); // Signal to other async tasks that the client has stopped + } + + async joinRoom(roomIdOrAlias) { + if (roomIdOrAlias === this.roomId) return this.room; + throw new Error(`Unknown room: ${roomIdOrAlias}`); + } + async encryptAndSendEvent(room, event) { + let response; + try { + response = await this.widgetApi.sendRoomEvent(event.getType(), event.getContent(), room.roomId); + } catch (e) { + this.updatePendingEventStatus(room, event, _event.EventStatus.NOT_SENT); + throw e; + } + room.updatePendingEvent(event, _event.EventStatus.SENT, response.event_id); + return { + event_id: response.event_id + }; + } + async sendStateEvent(roomId, eventType, content, stateKey = "") { + return await this.widgetApi.sendStateEvent(eventType, stateKey, content, roomId); + } + async sendToDevice(eventType, contentMap) { + await this.widgetApi.sendToDevice(eventType, false, (0, _utils.recursiveMapToObject)(contentMap)); + return {}; + } + async queueToDevice({ + eventType, + batch + }) { + // map: user Id → device Id → payload + const contentMap = new _utils.MapWithDefault(() => new Map()); + for (const { + userId, + deviceId, + payload + } of batch) { + contentMap.getOrCreate(userId).set(deviceId, payload); + } + await this.widgetApi.sendToDevice(eventType, false, (0, _utils.recursiveMapToObject)(contentMap)); + } + async encryptAndSendToDevices(userDeviceInfoArr, payload) { + // map: user Id → device Id → payload + const contentMap = new _utils.MapWithDefault(() => new Map()); + for (const { + userId, + deviceInfo: { + deviceId + } + } of userDeviceInfoArr) { + contentMap.getOrCreate(userId).set(deviceId, payload); + } + await this.widgetApi.sendToDevice(payload.type, true, (0, _utils.recursiveMapToObject)(contentMap)); + } + + // Overridden since we get TURN servers automatically over the widget API, + // and this method would otherwise complain about missing an access token + async checkTurnServers() { + return this.turnServers.length > 0; + } + + // Overridden since we 'sync' manually without the sync API + getSyncState() { + return this.syncState; + } + setSyncState(state) { + const oldState = this.syncState; + this.syncState = state; + this.emit(_client.ClientEvent.Sync, state, oldState); + } + async ack(ev) { + await this.widgetApi.transport.reply(ev.detail, {}); + } + async watchTurnServers() { + const servers = this.widgetApi.getTurnServers(); + const onClientStopped = () => { + servers.return(undefined); + }; + this.lifecycle.signal.addEventListener("abort", onClientStopped); + try { + for await (const server of servers) { + this.turnServers = [{ + urls: server.uris, + username: server.username, + credential: server.password + }]; + this.emit(_client.ClientEvent.TurnServers, this.turnServers); + _logger.logger.log(`Received TURN server: ${server.uris}`); + } + } catch (e) { + _logger.logger.warn("Error watching TURN servers", e); + } finally { + this.lifecycle.signal.removeEventListener("abort", onClientStopped); + } + } +} +exports.RoomWidgetClient = RoomWidgetClient; +//# sourceMappingURL=embedded.js.map
\ No newline at end of file |