You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-12-01 04:43:29 +03:00
Merge pull request #538 from matrix-org/dbkr/reemit_use_fewer_closures
Make re-emitting events much more memory efficient
This commit is contained in:
46
src/ReEmitter.js
Normal file
46
src/ReEmitter.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
Copyright 2017 Vector Creations Ltd
|
||||||
|
Copyright 2017 New Vector Ltd
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class Reemitter {
|
||||||
|
constructor(target) {
|
||||||
|
this.target = target;
|
||||||
|
|
||||||
|
// We keep one bound event handler for each event name so we know
|
||||||
|
// what event is arriving
|
||||||
|
this.boundHandlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleEvent(eventName, ...args) {
|
||||||
|
this.target.emit(eventName, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
reEmit(source, eventNames) {
|
||||||
|
for (const eventName of eventNames) {
|
||||||
|
if (this.boundHandlers[eventName] === undefined) {
|
||||||
|
this.boundHandlers[eventName] = this._handleEvent.bind(this, eventName);
|
||||||
|
}
|
||||||
|
const boundHandler = this.boundHandlers[eventName];
|
||||||
|
|
||||||
|
source.on(eventName, boundHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ const SyncApi = require("./sync");
|
|||||||
const MatrixBaseApis = require("./base-apis");
|
const MatrixBaseApis = require("./base-apis");
|
||||||
const MatrixError = httpApi.MatrixError;
|
const MatrixError = httpApi.MatrixError;
|
||||||
|
|
||||||
import reEmit from './reemit';
|
import ReEmitter from './ReEmitter';
|
||||||
|
|
||||||
const SCROLLBACK_DELAY_MS = 3000;
|
const SCROLLBACK_DELAY_MS = 3000;
|
||||||
let CRYPTO_ENABLED = false;
|
let CRYPTO_ENABLED = false;
|
||||||
@@ -115,6 +115,8 @@ try {
|
|||||||
function MatrixClient(opts) {
|
function MatrixClient(opts) {
|
||||||
MatrixBaseApis.call(this, opts);
|
MatrixBaseApis.call(this, opts);
|
||||||
|
|
||||||
|
this.reEmitter = new ReEmitter(this);
|
||||||
|
|
||||||
this.store = opts.store || new StubStore();
|
this.store = opts.store || new StubStore();
|
||||||
|
|
||||||
this.deviceId = opts.deviceId || null;
|
this.deviceId = opts.deviceId || null;
|
||||||
@@ -364,7 +366,7 @@ MatrixClient.prototype.initCrypto = async function() {
|
|||||||
this._cryptoStore,
|
this._cryptoStore,
|
||||||
);
|
);
|
||||||
|
|
||||||
reEmit(this, crypto, [
|
this.reEmitter.reEmit(crypto, [
|
||||||
"crypto.roomKeyRequest",
|
"crypto.roomKeyRequest",
|
||||||
"crypto.roomKeyRequestCancellation",
|
"crypto.roomKeyRequestCancellation",
|
||||||
]);
|
]);
|
||||||
@@ -3275,7 +3277,7 @@ function _PojoToMatrixEventMapper(client) {
|
|||||||
function mapper(plainOldJsObject) {
|
function mapper(plainOldJsObject) {
|
||||||
const event = new MatrixEvent(plainOldJsObject);
|
const event = new MatrixEvent(plainOldJsObject);
|
||||||
if (event.isEncrypted()) {
|
if (event.isEncrypted()) {
|
||||||
reEmit(client, event, [
|
client.reEmitter.reEmit(event, [
|
||||||
"Event.decrypted",
|
"Event.decrypted",
|
||||||
]);
|
]);
|
||||||
event.attemptDecryption(client._crypto);
|
event.attemptDecryption(client._crypto);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const ContentRepo = require("../content-repo");
|
|||||||
const EventTimeline = require("./event-timeline");
|
const EventTimeline = require("./event-timeline");
|
||||||
const EventTimelineSet = require("./event-timeline-set");
|
const EventTimelineSet = require("./event-timeline-set");
|
||||||
|
|
||||||
import reEmit from '../reemit';
|
import ReEmitter from '../ReEmitter';
|
||||||
|
|
||||||
function synthesizeReceipt(userId, event, receiptType) {
|
function synthesizeReceipt(userId, event, receiptType) {
|
||||||
// console.log("synthesizing receipt for "+event.getId());
|
// console.log("synthesizing receipt for "+event.getId());
|
||||||
@@ -106,6 +106,8 @@ function Room(roomId, opts) {
|
|||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";
|
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological";
|
||||||
|
|
||||||
|
this.reEmitter = new ReEmitter(this);
|
||||||
|
|
||||||
if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
|
if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"opts.pendingEventOrdering MUST be either 'chronological' or " +
|
"opts.pendingEventOrdering MUST be either 'chronological' or " +
|
||||||
@@ -153,7 +155,7 @@ function Room(roomId, opts) {
|
|||||||
// all our per-room timeline sets. the first one is the unfiltered ones;
|
// all our per-room timeline sets. the first one is the unfiltered ones;
|
||||||
// the subsequent ones are the filtered ones in no particular order.
|
// the subsequent ones are the filtered ones in no particular order.
|
||||||
this._timelineSets = [new EventTimelineSet(this, opts)];
|
this._timelineSets = [new EventTimelineSet(this, opts)];
|
||||||
reEmit(this, this.getUnfilteredTimelineSet(),
|
this.reEmitter.reEmit(this.getUnfilteredTimelineSet(),
|
||||||
["Room.timeline", "Room.timelineReset"]);
|
["Room.timeline", "Room.timelineReset"]);
|
||||||
|
|
||||||
this._fixUpLegacyTimelineFields();
|
this._fixUpLegacyTimelineFields();
|
||||||
@@ -490,7 +492,7 @@ Room.prototype.getOrCreateFilteredTimelineSet = function(filter) {
|
|||||||
}
|
}
|
||||||
const opts = Object.assign({ filter: filter }, this._opts);
|
const opts = Object.assign({ filter: filter }, this._opts);
|
||||||
const timelineSet = new EventTimelineSet(this, opts);
|
const timelineSet = new EventTimelineSet(this, opts);
|
||||||
reEmit(this, timelineSet, ["Room.timeline", "Room.timelineReset"]);
|
this.reEmitter.reEmit(timelineSet, ["Room.timeline", "Room.timelineReset"]);
|
||||||
this._filteredTimelineSets[filter.filterId] = timelineSet;
|
this._filteredTimelineSets[filter.filterId] = timelineSet;
|
||||||
this._timelineSets.push(timelineSet);
|
this._timelineSets.push(timelineSet);
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* re-emit events raised by one EventEmitter from another
|
|
||||||
*
|
|
||||||
* @param {external:EventEmitter} reEmitEntity
|
|
||||||
* entity from which we want events to be emitted
|
|
||||||
* @param {external:EventEmitter} emittableEntity
|
|
||||||
* entity from which events are currently emitted
|
|
||||||
* @param {Array<string>} eventNames
|
|
||||||
* list of events to be reemitted
|
|
||||||
*/
|
|
||||||
export default function reEmit(reEmitEntity, emittableEntity, eventNames) {
|
|
||||||
for (const eventName of eventNames) {
|
|
||||||
// setup a listener on the entity (the Room, User, etc) for this event
|
|
||||||
emittableEntity.on(eventName, function(...args) {
|
|
||||||
// take the args from the listener and reuse them, adding the
|
|
||||||
// event name to the arg list so it works with .emit()
|
|
||||||
// Transformation Example:
|
|
||||||
// listener on "foo" => function(a,b) { ... }
|
|
||||||
// Re-emit on "thing" => thing.emit("foo", a, b)
|
|
||||||
reEmitEntity.emit(eventName, ...args);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
16
src/sync.js
16
src/sync.js
@@ -32,8 +32,6 @@ const utils = require("./utils");
|
|||||||
const Filter = require("./filter");
|
const Filter = require("./filter");
|
||||||
const EventTimeline = require("./models/event-timeline");
|
const EventTimeline = require("./models/event-timeline");
|
||||||
|
|
||||||
import reEmit from './reemit';
|
|
||||||
|
|
||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
|
|
||||||
// /sync requests allow you to set a timeout= but the request may continue
|
// /sync requests allow you to set a timeout= but the request may continue
|
||||||
@@ -100,7 +98,7 @@ function SyncApi(client, opts) {
|
|||||||
this._failedSyncCount = 0; // Number of consecutive failed /sync requests
|
this._failedSyncCount = 0; // Number of consecutive failed /sync requests
|
||||||
|
|
||||||
if (client.getNotifTimelineSet()) {
|
if (client.getNotifTimelineSet()) {
|
||||||
reEmit(client, client.getNotifTimelineSet(),
|
client.reEmitter.reEmit(client.getNotifTimelineSet(),
|
||||||
["Room.timeline", "Room.timelineReset"]);
|
["Room.timeline", "Room.timelineReset"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +113,7 @@ SyncApi.prototype.createRoom = function(roomId) {
|
|||||||
pendingEventOrdering: this.opts.pendingEventOrdering,
|
pendingEventOrdering: this.opts.pendingEventOrdering,
|
||||||
timelineSupport: client.timelineSupport,
|
timelineSupport: client.timelineSupport,
|
||||||
});
|
});
|
||||||
reEmit(client, room, ["Room.name", "Room.timeline", "Room.redaction",
|
client.reEmitter.reEmit(room, ["Room.name", "Room.timeline", "Room.redaction",
|
||||||
"Room.receipt", "Room.tags",
|
"Room.receipt", "Room.tags",
|
||||||
"Room.timelineReset",
|
"Room.timelineReset",
|
||||||
"Room.localEchoUpdated",
|
"Room.localEchoUpdated",
|
||||||
@@ -132,7 +130,7 @@ SyncApi.prototype.createRoom = function(roomId) {
|
|||||||
SyncApi.prototype.createGroup = function(groupId) {
|
SyncApi.prototype.createGroup = function(groupId) {
|
||||||
const client = this.client;
|
const client = this.client;
|
||||||
const group = new Group(groupId);
|
const group = new Group(groupId);
|
||||||
reEmit(client, group, ["Group.profile", "Group.myMembership"]);
|
client.reEmitter.reEmit(group, ["Group.profile", "Group.myMembership"]);
|
||||||
return group;
|
return group;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -145,13 +143,13 @@ SyncApi.prototype._registerStateListeners = function(room) {
|
|||||||
// we need to also re-emit room state and room member events, so hook it up
|
// we need to also re-emit room state and room member events, so hook it up
|
||||||
// to the client now. We need to add a listener for RoomState.members in
|
// to the client now. We need to add a listener for RoomState.members in
|
||||||
// order to hook them correctly. (TODO: find a better way?)
|
// order to hook them correctly. (TODO: find a better way?)
|
||||||
reEmit(client, room.currentState, [
|
client.reEmitter.reEmit(room.currentState, [
|
||||||
"RoomState.events", "RoomState.members", "RoomState.newMember",
|
"RoomState.events", "RoomState.members", "RoomState.newMember",
|
||||||
]);
|
]);
|
||||||
room.currentState.on("RoomState.newMember", function(event, state, member) {
|
room.currentState.on("RoomState.newMember", function(event, state, member) {
|
||||||
member.user = client.getUser(member.userId);
|
member.user = client.getUser(member.userId);
|
||||||
reEmit(
|
client.reEmitter.reEmit(
|
||||||
client, member,
|
member,
|
||||||
[
|
[
|
||||||
"RoomMember.name", "RoomMember.typing", "RoomMember.powerLevel",
|
"RoomMember.name", "RoomMember.typing", "RoomMember.powerLevel",
|
||||||
"RoomMember.membership",
|
"RoomMember.membership",
|
||||||
@@ -1337,7 +1335,7 @@ SyncApi.prototype._onOnline = function() {
|
|||||||
|
|
||||||
function createNewUser(client, userId) {
|
function createNewUser(client, userId) {
|
||||||
const user = new User(userId);
|
const user = new User(userId);
|
||||||
reEmit(client, user, [
|
client.reEmitter.reEmit(user, [
|
||||||
"User.avatarUrl", "User.displayName", "User.presence",
|
"User.avatarUrl", "User.displayName", "User.presence",
|
||||||
"User.currentlyActive", "User.lastPresenceTs",
|
"User.currentlyActive", "User.lastPresenceTs",
|
||||||
]);
|
]);
|
||||||
|
|||||||
Reference in New Issue
Block a user