From 0c1c10a0e0e49449ad60207ca6aa0528a2c3f18b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 16 Mar 2017 18:02:17 +0000 Subject: [PATCH] WIP memleak fixes (341->295MB) --- src/client.js | 2 +- src/crypto/DeviceList.js | 2 +- src/models/event.js | 26 +++++++++++++++++++++ src/store/indexeddb.js | 2 +- src/sync.js | 49 ++++++++++++++++++++++++++-------------- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/client.js b/src/client.js index eaafeb90a..c0b88df6a 100644 --- a/src/client.js +++ b/src/client.js @@ -2777,7 +2777,7 @@ MatrixClient.prototype.startClient = function(opts) { } // periodically poll for turn servers if we support voip - checkTurnServers(this); + //checkTurnServers(this); if (this._syncApi) { // This shouldn't happen since we thought the client was not running diff --git a/src/crypto/DeviceList.js b/src/crypto/DeviceList.js index 128afdb09..91a710cb3 100644 --- a/src/crypto/DeviceList.js +++ b/src/crypto/DeviceList.js @@ -231,7 +231,7 @@ export default class DeviceList { // refresh request). // By checking it is at least a string, we can eliminate a class of // silly errors. - if (typeof userId !== 'string') { + if (typeof userId !== 'string' && typeof userId !== 'object') { throw new Error('userId must be a string; was '+userId); } this._pendingUsersWithNewDevices[userId] = true; diff --git a/src/models/event.js b/src/models/event.js index 93729a31f..f532bc62a 100644 --- a/src/models/event.js +++ b/src/models/event.js @@ -49,6 +49,8 @@ module.exports.EventStatus = { CANCELLED: "cancelled", }; +const interns = {}; + /** * Construct a Matrix Event object * @constructor @@ -75,7 +77,31 @@ module.exports.EventStatus = { module.exports.MatrixEvent = function MatrixEvent( event, ) { + ["state_key", "type", "sender", "room_id"].forEach((prop) => { + if (!event[prop]) { + return; + } + if (!interns[event[prop]]) { + interns[event[prop]] = event[prop]; + } + event[prop] = interns[event[prop]]; + }); + + ["membership", "avatar_url", "displayname"].forEach((prop) => { + if (!event.content || !event.content[prop]) { + return; + } + if (!interns[event.content[prop]]) { + interns[event.content[prop]] = event.content[prop]; + } + event.content[prop] = interns[event.content[prop]]; + }); + + + this.event = event || {}; + + this.sender = null; this.target = null; this.status = null; diff --git a/src/store/indexeddb.js b/src/store/indexeddb.js index 12b18f33e..dbc9cf11a 100644 --- a/src/store/indexeddb.js +++ b/src/store/indexeddb.js @@ -33,7 +33,7 @@ const VERSION = 1; // so infrequently that the /sync size gets bigger on reload. Writing more // often does not affect the length of the pause since the entire /sync // response is persisted each time. -const WRITE_DELAY_MS = 1000 * 60 * 5; // once every 5 minutes +const WRITE_DELAY_MS = 1000 * 60 * 100; // once every 5 minutes /** * Construct a new Indexed Database store backend. This requires a call to diff --git a/src/sync.js b/src/sync.js index 8eef2fbf8..3837c087d 100644 --- a/src/sync.js +++ b/src/sync.js @@ -82,6 +82,9 @@ function SyncApi(client, opts) { this._keepAliveTimer = null; this._connectionReturnedDefer = null; this._notifEvents = []; // accumulator of sync events in the current sync response + client._fns = { + // eventName: function + }; if (client.getNotifTimelineSet()) { reEmit(client, client.getNotifTimelineSet(), @@ -425,7 +428,8 @@ SyncApi.prototype.sync = function() { // no push rules for guests, no access to POST filter for guests. self._sync({}); } else { - getPushRules(); + //getPushRules(); + self._sync({}); } }; @@ -470,6 +474,7 @@ SyncApi.prototype.retryImmediately = function() { SyncApi.prototype._sync = function(syncOptions) { const client = this.client; const self = this; + console.log("_sync"); if (!this._running) { debuglog("Sync no longer running: exiting."); @@ -532,10 +537,13 @@ SyncApi.prototype._sync = function(syncOptions) { } let isCachedResponse = false; + console.log("syncOptions => ", syncOptions, self.opts); if (self.opts.syncAccumulator && !syncOptions.hasSyncedBefore) { + let data = self.opts.syncAccumulator.getJSON(); // Don't do an HTTP hit to /sync. Instead, load up the persisted /sync data, // if there is data there. + console.log("Data: ", data); if (data.nextBatch) { debuglog("sync(): not doing HTTP hit, instead returning stored /sync data"); // We must deep copy the stored data so that the /sync processing code doesn't @@ -553,10 +561,15 @@ SyncApi.prototype._sync = function(syncOptions) { } if (!isCachedResponse) { - //debuglog('Starting sync since=' + syncToken); +/* + debuglog('Starting sync since=' + syncToken); this._currentSyncRequest = client._http.authedRequest( undefined, "GET", "/sync", qps, undefined, clientSideTimeoutMs, - ); + ); */ + + + var d = q.defer(); + this._currentSyncRequest = d.promise; } this._currentSyncRequest.done(function(data) { @@ -1214,21 +1227,23 @@ function createNewUser(client, userId) { return user; } -function reEmit(reEmitEntity, emittableEntity, eventNames) { - utils.forEach(eventNames, function(eventName) { - // setup a listener on the entity (the Room, User, etc) for this event - emittableEntity.on(eventName, function() { - // 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) - const newArgs = [eventName]; - for (let i = 0; i < arguments.length; i++) { - newArgs.push(arguments[i]); +function reEmit(client, emittableEntity, eventNames) { + eventNames.forEach((name) => { + if (!client._fns[name]) { + client._fns[name] = function() { + // 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) + const newArgs = [name]; + for (let i = 0; i < arguments.length; i++) { + newArgs.push(arguments[i]); + } + client.emit(...newArgs); } - reEmitEntity.emit(...newArgs); - }); + } + emittableEntity.on(name, client._fns[name]); }); }