Compare commits

..

32 Commits

Author SHA1 Message Date
RiotRobot e3ba08fbbc v10.0.0-rc.1 2021-04-21 16:40:23 +01:00
RiotRobot dd84e51161 Prepare changelog for v10.0.0-rc.1 2021-04-21 16:40:22 +01:00
Germain b435b582bd Merge pull request #1675 from matrix-org/gsouquet-powerlevels-perf
Restrict event emit for room members that had power levels changed
2021-04-20 11:57:18 +01:00
Germain Souquet d46021a05e Restrict event emit for room members that had power levels changed 2021-04-20 11:22:16 +01:00
Michael Telatynski 68206a6e19 Merge pull request #1669 from hannojg/patch-3
Fix sync with misconfigured push rules
2021-04-20 08:57:16 +01:00
Hanno J. Gödecke b13f5aebfd lint 2021-04-17 09:42:44 +02:00
Hanno J. Gödecke 338301bb5d fix: failure during sync 2021-04-17 09:34:31 +02:00
Hubert Chathi cbe9b59222 Merge pull request #1665 from uhoreg/dehydrated_device_missing_await
Add missing await
2021-04-14 10:47:09 -04:00
Hubert Chathi 276b52f0fe add missing await 2021-04-14 10:29:39 -04:00
J. Ryan Stinnett 09fac77ce0 Merge pull request #1642 from matrix-org/jryans/rework-linting
Migrate to `eslint-plugin-matrix-org`
2021-04-13 11:12:39 +01:00
J. Ryan Stinnett 102704e91a Migrate to eslint-plugin-matrix-org
This migrates to the new plugin form of our custom ESLint configs. As part of
this, some packages are de-duplicated, configs streamlined, etc.
2021-04-13 11:00:41 +01:00
Michael Telatynski c5fb351baa Merge pull request #1664 from matrix-org/t3chguy/fix/8665
Add missing event type enum for key verification done
2021-04-13 10:05:00 +01:00
Michael Telatynski 98f8d4414d Add missing event type enum for key verification done 2021-04-13 09:41:53 +01:00
Germain 1dddcd4925 Merge pull request #1663 from matrix-org/gsouquet-timeline-jumpiness 2021-04-12 15:00:49 +01:00
Germain Souquet 2666a271a5 fix tests when pendingEventsList does not exist 2021-04-12 14:51:45 +01:00
RiotRobot e277de6e3d Resetting package fields for development 2021-04-12 14:42:29 +01:00
RiotRobot daa17b3287 Merge branch 'master' into develop 2021-04-12 14:42:29 +01:00
Germain Souquet 466f749b71 fix typo 2021-04-12 14:38:27 +01:00
Germain Souquet 4c2a83c470 Add explanation for events persistence 2021-04-12 14:29:10 +01:00
Germain Souquet d534ab18c7 fix event filtering logic 2021-04-12 13:07:57 +01:00
Germain Souquet 64aaed833b Only persist encrypted events for encrypted rooms 2021-04-12 12:53:27 +01:00
Germain Souquet 2f05be599c undo changes to event#toJSON and persist encrypted events 2021-04-12 12:26:27 +01:00
Germain Souquet 7371f8dd3a Persist txnId to ensure idempotency 2021-04-12 09:55:01 +01:00
Germain Souquet 79aefe9707 Fix timeline jumpiness by setting correct txnId 2021-04-12 09:37:19 +01:00
Michael Telatynski 6bc80577ee Merge pull request #1661 from janpawellek/janpawellek-fix-addEventListener
Fix calling addEventListener if it does not exist
2021-04-12 09:15:19 +01:00
Germain 837764190f Merge pull request #1655 from matrix-org/gsouquet-persist-unsent-messages 2021-04-09 17:48:01 +01:00
Germain Souquet 61948d70e3 Merge branch 'develop' into gsouquet-persist-unsent-messages 2021-04-09 17:05:19 +01:00
Jan Pawellek 9fb0385694 Fix calling addEventListener if it does not exist
Some platforms (e.g. React Native) register global.window, but do not have global.window.addEventListener. In this case, this function should not be called.
2021-04-09 10:18:47 +02:00
Germain Souquet 26ef33e4f3 No this assign 2021-04-01 17:29:21 +01:00
Germain Souquet 0534a4ed1b prevent removePendingEvent being called when not in detached mode 2021-04-01 17:23:55 +01:00
Germain Souquet f29a24a915 specify TestClient when testing room model 2021-04-01 15:22:13 +01:00
Germain Souquet cecbcd941e Persist unsent messages for subsequent sessions 2021-04-01 10:59:16 +01:00
17 changed files with 295 additions and 750 deletions
+3 -4
View File
@@ -1,13 +1,12 @@
module.exports = {
extends: ["matrix-org"],
plugins: [
"babel",
"matrix-org",
],
extends: ["plugin:matrix-org/javascript"],
env: {
browser: true,
node: true,
},
rules: {
"no-var": ["warn"],
"prefer-rest-params": ["warn"],
@@ -33,7 +32,7 @@ module.exports = {
},
overrides: [{
"files": ["src/**/*.ts"],
"extends": ["matrix-org/ts"],
"extends": ["plugin:matrix-org/typescript"],
"rules": {
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
+21
View File
@@ -1,3 +1,24 @@
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)
* 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)
+7 -4
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "9.11.0",
"version": "10.0.0-rc.1",
"description": "Matrix Client-Server SDK for Javascript",
"scripts": {
"prepublishOnly": "yarn build",
@@ -61,6 +61,8 @@
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.12.10",
"@babel/eslint-plugin": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
@@ -72,15 +74,16 @@
"@types/jest": "^26.0.20",
"@types/node": "12",
"@types/request": "^2.48.5",
"babel-eslint": "^10.1.0",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"babel-jest": "^26.6.3",
"babelify": "^10.0.0",
"better-docs": "^2.3.2",
"browserify": "^17.0.0",
"docdash": "^1.2.0",
"eslint": "7.18.0",
"eslint-config-matrix-org": "^0.2.0",
"eslint-plugin-babel": "^5.3.1",
"eslint-config-google": "^0.14.0",
"eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#main",
"exorcist": "^1.0.1",
"fake-indexeddb": "^3.1.2",
"jest": "^26.6.3",
+5 -5
View File
@@ -30,7 +30,7 @@ export async function makeTestClients(userInfos, options) {
for (const [deviceId, msg] of Object.entries(devMap)) {
if (deviceId in clientMap[userId]) {
const event = new MatrixEvent({
sender: this.getUserId(), // eslint-disable-line babel/no-invalid-this
sender: this.getUserId(), // eslint-disable-line @babel/no-invalid-this
type: type,
content: msg,
});
@@ -49,9 +49,9 @@ export async function makeTestClients(userInfos, options) {
};
const sendEvent = function(room, type, content) {
// make up a unique ID as the event ID
const eventId = "$" + this.makeTxnId(); // eslint-disable-line babel/no-invalid-this
const eventId = "$" + this.makeTxnId(); // eslint-disable-line @babel/no-invalid-this
const rawEvent = {
sender: this.getUserId(), // eslint-disable-line babel/no-invalid-this
sender: this.getUserId(), // eslint-disable-line @babel/no-invalid-this
type: type,
content: content,
room_id: room,
@@ -61,13 +61,13 @@ export async function makeTestClients(userInfos, options) {
const event = new MatrixEvent(rawEvent);
const remoteEcho = new MatrixEvent(Object.assign({}, rawEvent, {
unsigned: {
transaction_id: this.makeTxnId(), // eslint-disable-line babel/no-invalid-this
transaction_id: this.makeTxnId(), // eslint-disable-line @babel/no-invalid-this
},
}));
setImmediate(() => {
for (const tc of clients) {
if (tc.client === this) { // eslint-disable-line babel/no-invalid-this
if (tc.client === this) { // eslint-disable-line @babel/no-invalid-this
logger.log("sending remote echo!!");
tc.client.emit("Room.timeline", remoteEcho);
} else {
+2 -2
View File
@@ -46,8 +46,8 @@ describe("realtime-callbacks", function() {
it("should set 'this' to the global object", function() {
let passed = false;
const callback = function() {
expect(this).toBe(global); // eslint-disable-line babel/no-invalid-this
expect(this.console).toBeTruthy(); // eslint-disable-line babel/no-invalid-this
expect(this).toBe(global); // eslint-disable-line @babel/no-invalid-this
expect(this.console).toBeTruthy(); // eslint-disable-line @babel/no-invalid-this
passed = true;
};
callbacks.setTimeout(callback);
+9 -2
View File
@@ -3,6 +3,7 @@ import {EventStatus, MatrixEvent} from "../../src/models/event";
import {EventTimeline} from "../../src/models/event-timeline";
import {RoomState} from "../../src/models/room-state";
import {Room} from "../../src/models/room";
import {TestClient} from "../TestClient";
describe("Room", function() {
const roomId = "!foo:bar";
@@ -1176,7 +1177,10 @@ describe("Room", function() {
describe("addPendingEvent", function() {
it("should add pending events to the pendingEventList if " +
"pendingEventOrdering == 'detached'", function() {
const room = new Room(roomId, null, userA, {
const client = (new TestClient(
"@alice:example.com", "alicedevice",
)).client;
const room = new Room(roomId, client, userA, {
pendingEventOrdering: "detached",
});
const eventA = utils.mkMessage({
@@ -1226,7 +1230,10 @@ describe("Room", function() {
describe("updatePendingEvent", function() {
it("should remove cancelled events from the pending list", function() {
const room = new Room(roomId, null, userA, {
const client = (new TestClient(
"@alice:example.com", "alicedevice",
)).client;
const room = new Room(roomId, client, userA, {
pendingEventOrdering: "detached",
});
const eventA = utils.mkMessage({
+1
View File
@@ -57,6 +57,7 @@ export enum EventType {
KeyVerificationStart = "m.key.verification.start",
KeyVerificationCancel = "m.key.verification.cancel",
KeyVerificationMac = "m.key.verification.mac",
KeyVerificationDone = "m.key.verification.done",
// use of this is discouraged https://matrix.org/docs/spec/client_server/r0.6.1#m-room-message-feedback
RoomMessageFeedback = "m.room.message.feedback",
+1 -1
View File
@@ -500,7 +500,7 @@ MatrixClient.prototype.rehydrateDevice = async function() {
return;
}
const getDeviceResult = this.getDehydratedDevice();
const getDeviceResult = await this.getDehydratedDevice();
if (!getDeviceResult) {
return;
}
+2 -2
View File
@@ -36,11 +36,11 @@ const DEFAULT_NAMESPACE = "matrix";
// when logging so we always get the current value of console methods.
log.methodFactory = function(methodName, logLevel, loggerName) {
return function(...args) {
/* eslint-disable babel/no-invalid-this */
/* eslint-disable @babel/no-invalid-this */
if (this.prefix) {
args.unshift(this.prefix);
}
/* eslint-enable babel/no-invalid-this */
/* eslint-enable @babel/no-invalid-this */
const supportedByConsole = methodName === "error" ||
methodName === "warn" ||
methodName === "trace" ||
+1 -1
View File
@@ -168,7 +168,7 @@ export const MatrixEvent = function(
/* The txnId with which this event was sent if it was during this session,
allows for a unique ID which does not change when the event comes back down sync.
*/
this._txnId = null;
this._txnId = event.txn_id || null;
/* Set an approximate timestamp for the event relative the local clock.
* This will inherently be approximate because it doesn't take into account
+7 -1
View File
@@ -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
+91 -9
View File
@@ -123,6 +123,8 @@ export function Room(roomId, client, myUserId, opts) {
opts = opts || {};
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";
this._client = client;
// In some cases, we add listeners for every displayed Matrix event, so it's
// common to have quite a few more than the default limit.
this.setMaxListeners(100);
@@ -189,6 +191,18 @@ export function Room(roomId, client, myUserId, opts) {
if (this._opts.pendingEventOrdering == "detached") {
this._pendingEventList = [];
const serializedPendingEventList = client._sessionStore.store.getItem(pendingEventsKey(this.roomId));
if (serializedPendingEventList) {
JSON.parse(serializedPendingEventList)
.forEach(async serializedEvent => {
const event = new MatrixEvent(serializedEvent);
if (event.getType() === "m.room.encrypted") {
await event.attemptDecryption(this._client._crypto);
}
event.setStatus(EventStatus.NOT_SENT);
this.addPendingEvent(event, event.getTxnId());
});
}
}
// read by megolm; boolean value - null indicates "use global value"
@@ -197,7 +211,6 @@ export function Room(roomId, client, myUserId, opts) {
this._summaryHeroes = null;
// awaited by getEncryptionTargetMembers while room members are loading
this._client = client;
if (!this._opts.lazyLoadMembers) {
this._membersPromise = Promise.resolve();
} else {
@@ -205,6 +218,14 @@ export function Room(roomId, client, myUserId, opts) {
}
}
/**
* @param {string} roomId ID of the current room
* @returns {string} Storage key to retrieve pending events
*/
function pendingEventsKey(roomId) {
return `mx_pending_events_${roomId}`;
}
utils.inherits(Room, EventEmitter);
/**
@@ -357,6 +378,31 @@ Room.prototype.getPendingEvents = function() {
return this._pendingEventList;
};
/**
* Removes a pending event for this room
*
* @param {string} eventId
* @return {boolean} True if an element was removed.
*/
Room.prototype.removePendingEvent = function(eventId) {
if (this._opts.pendingEventOrdering !== "detached") {
throw new Error(
"Cannot call removePendingEvent with pendingEventOrdering == " +
this._opts.pendingEventOrdering);
}
const removed = utils.removeElement(
this._pendingEventList,
function(ev) {
return ev.getId() == eventId;
}, false,
);
this._savePendingEvents();
return removed;
};
/**
* Check whether the pending event list contains a given event by ID.
* If pending event ordering is not "detached" then this returns false.
@@ -1192,7 +1238,7 @@ Room.prototype._addLiveEvent = function(event, duplicateStrategy, fromCache) {
* unique transaction id.
*/
Room.prototype.addPendingEvent = function(event, txnId) {
if (event.status !== EventStatus.SENDING) {
if (event.status !== EventStatus.SENDING && event.status !== EventStatus.NOT_SENT) {
throw new Error("addPendingEvent called on an event with status " +
event.status);
}
@@ -1219,7 +1265,7 @@ Room.prototype.addPendingEvent = function(event, txnId) {
event.setStatus(EventStatus.NOT_SENT);
}
this._pendingEventList.push(event);
this._savePendingEvents();
if (event.isRelation()) {
// For pending events, add them to the relations collection immediately.
// (The alternate case below already covers this as part of adding to
@@ -1256,6 +1302,46 @@ Room.prototype.addPendingEvent = function(event, txnId) {
this.emit("Room.localEchoUpdated", event, this, null, null);
};
/**
* Persists all pending events to local storage
*
* If the current room is encrypted only encrypted events will be persisted
* all messages that are not yet encrypted will be discarded
*
* This is because the flow of EVENT_STATUS transition is
* queued => sending => encrypting => sending => sent
*
* Steps 3 and 4 are skipped for unencrypted room.
* It is better to discard an unencrypted message rather than persisting
* it locally for everyone to read
*/
Room.prototype._savePendingEvents = function() {
if (this._pendingEventList) {
const pendingEvents = this._pendingEventList.map(event => {
return {
...event.event,
txn_id: event.getTxnId(),
};
}).filter(event => {
// Filter out the unencrypted messages if the room is encrypted
const isEventEncrypted = event.type === "m.room.encrypted";
const isRoomEncrypted = this._client.isRoomEncrypted(this.roomId);
return isEventEncrypted || !isRoomEncrypted;
});
const { store } = this._client._sessionStore;
if (this._pendingEventList.length > 0) {
store.setItem(
pendingEventsKey(this.roomId),
JSON.stringify(pendingEvents),
);
} else {
store.removeItem(pendingEventsKey(this.roomId));
}
}
};
/**
* Used to aggregate the local echo for a relation, and also
* for re-applying a relation after it's redaction has been cancelled,
@@ -1310,12 +1396,7 @@ Room.prototype._handleRemoteEcho = function(remoteEvent, localEvent) {
// if it's in the pending list, remove it
if (this._pendingEventList) {
utils.removeElement(
this._pendingEventList,
function(ev) {
return ev.getId() == oldEventId;
}, false,
);
this.removePendingEvent(oldEventId);
}
// replace the event source (this will preserve the plaintext payload if
@@ -1434,6 +1515,7 @@ Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) {
}
this.removeEvent(oldEventId);
}
this._savePendingEvents();
this.emit("Room.localEchoUpdated", event, this, oldEventId, oldStatus);
};
+4
View File
@@ -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') {
+1 -1
View File
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
/* eslint-disable babel/no-invalid-this */
/* eslint-disable @babel/no-invalid-this */
import {MemoryStore} from "./memory";
import * as utils from "../utils";
+1 -1
View File
@@ -476,7 +476,7 @@ SyncApi.prototype.sync = function() {
this._running = true;
if (global.window) {
if (global.window && global.window.addEventListener) {
this._onOnlineBound = this._onOnline.bind(this);
global.window.addEventListener("online", this._onOnlineBound, false);
}
+5 -5
View File
@@ -206,9 +206,9 @@ export function getDesktopCapturerSources(): Promise<Array<DesktopCapturerSource
}
export class CallError extends Error {
code : string;
code: string;
constructor(code : CallErrorCode, msg: string, err: Error) {
constructor(code: CallErrorCode, msg: string, err: Error) {
// Stil ldon't think there's any way to have proper nested errors
super(msg + ": " + err);
@@ -450,7 +450,7 @@ export class MatrixCall extends EventEmitter {
* video will be rendered to it immediately.
* @param {Element} element The <code>&lt;video&gt;</code> DOM element.
*/
public async setLocalVideoElement(element : HTMLVideoElement) {
public async setLocalVideoElement(element: HTMLVideoElement) {
this.localVideoElement = element;
if (element && this.localAVStream && this.type === CallType.Video) {
@@ -471,7 +471,7 @@ export class MatrixCall extends EventEmitter {
* the first received video-capable stream will be rendered to it immediately.
* @param {Element} element The <code>&lt;video&gt;</code> DOM element.
*/
public setRemoteVideoElement(element : HTMLVideoElement) {
public setRemoteVideoElement(element: HTMLVideoElement) {
if (element === this.remoteVideoElement) return;
element.autoplay = true;
@@ -1199,7 +1199,7 @@ export class MatrixCall extends EventEmitter {
}
}
private callHasEnded() : boolean {
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
// function, even though that function is async.
+134 -712
View File
File diff suppressed because it is too large Load Diff