diff --git a/CHANGELOG.md b/CHANGELOG.md index 070f1faec..c2eac122a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ +Changes in [10.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v10.0.0) (2021-04-26) +================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v10.0.0-rc.1...v10.0.0) + + * No changes since rc.1 + +Changes in [10.0.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v10.0.0-rc.1) (2021-04-21) +============================================================================================================ +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.11.0...v10.0.0-rc.1) + +BREAKING CHANGES +--- + + * The `RoomState.members` event is now only emitted when the room member's power level or the room's normal power level actually changes + +All changes +--- + + * Restrict event emit for room members that had power levels changed + [\#1675](https://github.com/matrix-org/matrix-js-sdk/pull/1675) + * Fix sync with misconfigured push rules + [\#1669](https://github.com/matrix-org/matrix-js-sdk/pull/1669) + * Add missing await + [\#1665](https://github.com/matrix-org/matrix-js-sdk/pull/1665) + * Migrate to `eslint-plugin-matrix-org` + [\#1642](https://github.com/matrix-org/matrix-js-sdk/pull/1642) + * Add missing event type enum for key verification done + [\#1664](https://github.com/matrix-org/matrix-js-sdk/pull/1664) + * Fix timeline jumpiness by setting correct txnId + [\#1663](https://github.com/matrix-org/matrix-js-sdk/pull/1663) + * Fix calling addEventListener if it does not exist + [\#1661](https://github.com/matrix-org/matrix-js-sdk/pull/1661) + * Persist unsent messages for subsequent sessions + [\#1655](https://github.com/matrix-org/matrix-js-sdk/pull/1655) + Changes in [9.11.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.11.0) (2021-04-12) ================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.11.0-rc.1...v9.11.0) diff --git a/package.json b/package.json index 56cae38de..0bb9aa532 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "9.11.0", + "version": "10.0.0", "description": "Matrix Client-Server SDK for Javascript", "scripts": { "prepublishOnly": "yarn build", diff --git a/spec/unit/webrtc/call.spec.ts b/spec/unit/webrtc/call.spec.ts index 0e7b67547..e5ef6de87 100644 --- a/spec/unit/webrtc/call.spec.ts +++ b/spec/unit/webrtc/call.spec.ts @@ -15,7 +15,7 @@ limitations under the License. */ import {TestClient} from '../../TestClient'; -import {MatrixCall, CallErrorCode} from '../../../src/webrtc/call'; +import {MatrixCall, CallErrorCode, CallEvent} from '../../../src/webrtc/call'; const DUMMY_SDP = ( "v=0\r\n" + @@ -254,4 +254,48 @@ describe('Call', function() { sdpMid: '', }); }); + + it('should map asserted identity messages to remoteAssertedIdentity', async function() { + const callPromise = call.placeVoiceCall(); + await client.httpBackend.flush(); + await callPromise; + await call.onAnswerReceived({ + getContent: () => { + return { + version: 1, + call_id: call.callId, + party_id: 'party_id', + answer: { + sdp: DUMMY_SDP, + }, + }; + }, + }); + + const identChangedCallback = jest.fn(); + call.on(CallEvent.AssertedIdentityChanged, identChangedCallback); + + await call.onAssertedIdentityReceived({ + getContent: () => { + return { + version: 1, + call_id: call.callId, + party_id: 'party_id', + asserted_identity: { + id: "@steve:example.com", + display_name: "Steve Gibbons", + }, + }; + }, + }); + + expect(identChangedCallback).toHaveBeenCalled(); + + const ident = call.getRemoteAssertedIdentity(); + expect(ident.id).toEqual("@steve:example.com"); + expect(ident.displayName).toEqual("Steve Gibbons"); + + // Hangup to stop timers + call.hangup(CallErrorCode.UserHangup, true); + }); }); diff --git a/src/@types/event.ts b/src/@types/event.ts index 92f90ea62..a908088d7 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -53,6 +53,8 @@ export enum EventType { CallSelectAnswer = "m.call.select_answer", CallNegotiate = "m.call.negotiate", CallReplaces = "m.call.replaces", + CallAssertedIdentity = "m.call.asserted_identity", + CallAssertedIdentityPrefix = "org.matrix.call.asserted_identity", KeyVerificationRequest = "m.key.verification.request", KeyVerificationStart = "m.key.verification.start", KeyVerificationCancel = "m.key.verification.cancel", diff --git a/src/client.js b/src/client.js index f845a5a08..63514c2e5 100644 --- a/src/client.js +++ b/src/client.js @@ -500,7 +500,7 @@ MatrixClient.prototype.rehydrateDevice = async function() { return; } - const getDeviceResult = this.getDehydratedDevice(); + const getDeviceResult = await this.getDehydratedDevice(); if (!getDeviceResult) { return; } @@ -729,6 +729,17 @@ MatrixClient.prototype.setSupportsCallTransfer = function(supportsCallTransfer) this._supportsCallTransfer = supportsCallTransfer; }; +/** + * Creates a new call. + * The place*Call methods on the returned call can be used to actually place a call + * + * @param {string} roomId The room the call is to be placed in. + * @return {MatrixCall} the call or null if the browser doesn't support calling. + */ +MatrixClient.prototype.createCall = function(roomId) { + return createNewMatrixCall(this, roomId); +}; + /** * Get the current sync state. * @return {?string} the sync state, which may be null. @@ -4799,7 +4810,8 @@ MatrixClient.prototype._processRoomEventsSearch = function(searchResults, respon searchResults.highlights = Object.keys(highlights); // append the new results to our existing results - for (let i = 0; i < room_events.results.length; i++) { + const resultsLength = room_events.results ? room_events.results.length : 0; + for (let i = 0; i < resultsLength; i++) { const sr = SearchResult.fromJson(room_events.results[i], this.getEventMapper()); searchResults.results.push(sr); } diff --git a/src/models/room-state.js b/src/models/room-state.js index 67d63faec..9be252f2c 100644 --- a/src/models/room-state.js +++ b/src/models/room-state.js @@ -351,8 +351,14 @@ RoomState.prototype.setStateEvents = function(stateEvents) { } else if (event.getType() === "m.room.power_levels") { const members = utils.values(self.members); utils.forEach(members, function(member) { + // We only propagate `RoomState.members` event if the + // power levels has been changed + // large room suffer from large re-rendering especially when not needed + const oldLastModified = member.getLastModifiedTime(); member.setPowerLevelEvent(event); - self.emit("RoomState.members", event, self, member); + if (oldLastModified !== member.getLastModifiedTime()) { + self.emit("RoomState.members", event, self, member); + } }); // assume all our sentinels are now out-of-date diff --git a/src/models/room.js b/src/models/room.js index d6b6a8d9d..7bb263320 100644 --- a/src/models/room.js +++ b/src/models/room.js @@ -982,6 +982,15 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline, return this.currentState.getMember(userId); }; +/** + * Get all currently loaded members from the current + * room state. + * @returns {RoomMember[]} Room members + */ +Room.prototype.getMembers = function() { + return this.currentState.getMembers(); +}; + /** * Get a list of members whose membership state is "join". * @return {RoomMember[]} A list of currently joined members. diff --git a/src/pushprocessor.js b/src/pushprocessor.js index 57ab74317..0e8958b09 100644 --- a/src/pushprocessor.js +++ b/src/pushprocessor.js @@ -268,6 +268,10 @@ export function PushProcessor(client) { return cond.value === val; } + if (typeof cond.pattern !== 'string') { + return false; + } + let regex; if (cond.key == 'content.body') { diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index c966e5738..d84be56b7 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -70,6 +70,11 @@ interface TurnServer { ttl?: number, } +interface AssertedIdentity { + id: string, + displayName: string, +} + export enum CallState { Fledgling = 'fledgling', InviteSent = 'invite_sent', @@ -111,6 +116,8 @@ export enum CallEvent { HoldUnhold = 'hold_unhold', // Feeds have changed FeedsChanged = 'feeds_changed', + + AssertedIdentityChanged = 'asserted_identity_changed', } export enum CallErrorCode { @@ -299,6 +306,8 @@ export class MatrixCall extends EventEmitter { // the call) we buffer them up here so we can then add the ones from the party we pick private remoteCandidateBuffer = new Map(); + private remoteAssertedIdentity: AssertedIdentity; + constructor(opts: CallOpts) { super(); this.roomId = opts.roomId; @@ -411,6 +420,10 @@ export class MatrixCall extends EventEmitter { return Boolean(this.opponentCaps && this.opponentCaps["m.call.transferee"]); } + public getRemoteAssertedIdentity(): AssertedIdentity { + return this.remoteAssertedIdentity; + } + /** * Returns an array of all CallFeeds * @returns {Array} CallFeeds @@ -1121,6 +1134,16 @@ export class MatrixCall extends EventEmitter { } } + async onAssertedIdentityReceived(event: MatrixEvent) { + if (!event.getContent().asserted_identity) return; + + this.remoteAssertedIdentity = { + id: event.getContent().asserted_identity.id, + displayName: event.getContent().asserted_identity.display_name, + }; + this.emit(CallEvent.AssertedIdentityChanged); + } + private callHasEnded(): boolean { // This exists as workaround to typescript trying to be clever and erroring // when putting if (this.state === CallState.Ended) return; twice in the same @@ -1750,6 +1773,9 @@ export function setAudioInput(deviceId: string) { audioInput = deviceId; } export function setVideoInput(deviceId: string) { videoInput = deviceId; } /** + * DEPRECATED + * Use client.createCall() + * * Create a new Matrix call for the browser. * @param {MatrixClient} client The client instance to use. * @param {string} roomId The room the call is in. diff --git a/src/webrtc/callEventHandler.ts b/src/webrtc/callEventHandler.ts index c45bf62b3..9c4c38b26 100644 --- a/src/webrtc/callEventHandler.ts +++ b/src/webrtc/callEventHandler.ts @@ -87,7 +87,11 @@ export class CallEventHandler { private onEvent = (event: MatrixEvent) => { // any call events or ones that might be once they're decrypted - if (event.getType().indexOf("m.call.") === 0 || event.isBeingDecrypted()) { + if ( + event.getType().indexOf("m.call.") === 0 || + event.getType().indexOf("org.matrix.call.") === 0 + || event.isBeingDecrypted() + ) { // queue up for processing once all events from this sync have been // processed (see above). this.callEventBuffer.push(event); @@ -271,6 +275,18 @@ export class CallEventHandler { } call.onNegotiateReceived(event); + } else if ( + event.getType() === EventType.CallAssertedIdentity || + event.getType() === EventType.CallAssertedIdentityPrefix + ) { + if (!call) return; + + if (event.getContent().party_id === call.ourPartyId) { + // Ignore remote echo (not that we send asserted identity, but still...) + return; + } + + call.onAssertedIdentityReceived(event); } } }