From 73e0216f78f109b784aaea137e0fd0a840befe37 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 4 Dec 2015 17:27:16 +0000 Subject: [PATCH] Scrollback improvements Add a 3s delay between scrollback requests if the previous scrollback request failed. Return the same promise if scrollback() is called multiple times whilst a scrollback request is ongoing. --- lib/client.js | 33 ++++++++++++++++++++++++++++++++- spec/mock-request.js | 7 +++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index cfdeb4b2a..264b14cce 100644 --- a/lib/client.js +++ b/lib/client.js @@ -19,6 +19,7 @@ var webRtcCall = require("./webrtc/call"); var utils = require("./utils"); var contentRepo = require("./content-repo"); +var SCROLLBACK_DELAY_MS = 3000; var CRYPTO_ENABLED = false; try { @@ -155,6 +156,7 @@ function MatrixClient(opts) { this._syncingRetry = null; this._guestRooms = null; this._isGuest = false; + this._ongoingScrollbacks = {}; } utils.inherits(MatrixClient, EventEmitter); @@ -1767,6 +1769,12 @@ MatrixClient.prototype.roomState = function(roomId, callback) { /** * Retrieve older messages from the given room and put them in the timeline. + * + * If this is called multiple times whilst a request is ongoing, the same + * Promise will be returned. If there was a problem requesting scrollback, there + * will be a small delay before another request can be made (to prevent tight-looping + * when there is no connection). + * * @param {Room} room The room to get older messages in. * @param {Integer} limit Optional. The maximum number of previous events to * pull in. Default: 30. @@ -1779,6 +1787,16 @@ MatrixClient.prototype.roomState = function(roomId, callback) { MatrixClient.prototype.scrollback = function(room, limit, callback) { if (utils.isFunction(limit)) { callback = limit; limit = undefined; } limit = limit || 30; + var timeToWaitMs = 0; + + var info = this._ongoingScrollbacks[room.roomId] || {}; + if (info.promise) { + return info.promise; + } + else if (info.errorTs) { + var timeWaitedMs = Date.now() - info.errorTs; + timeToWaitMs = Math.max(SCROLLBACK_DELAY_MS - timeWaitedMs, 0); + } if (room.oldState.paginationToken === null) { return q(room); // already at the start. @@ -1801,8 +1819,16 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) { dir: 'b' }; var defer = q.defer(); + info = { + promise: defer.promise, + errorTs: null + }; var self = this; - this._http.authedRequest(callback, "GET", path, params).done(function(res) { + // wait for a time before doing this request + // (which may be 0 in order not to special case the code paths) + q.delay(timeToWaitMs).then(function() { + return self._http.authedRequest(callback, "GET", path, params); + }).done(function(res) { var matrixEvents = utils.map(res.chunk, _PojoToMatrixEventMapper(self)); room.addEventsToTimeline(matrixEvents, true); room.oldState.paginationToken = res.end; @@ -1810,10 +1836,15 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) { room.oldState.paginationToken = null; } self.store.storeEvents(room, matrixEvents, res.end, true); + self._ongoingScrollbacks[room.roomId] = null; _resolve(callback, defer, room); }, function(err) { + self._ongoingScrollbacks[room.roomId] = { + errorTs: Date.now() + }; _reject(callback, defer, err); }); + this._ongoingScrollbacks[room.roomId] = info; return defer.promise; }; diff --git a/spec/mock-request.js b/spec/mock-request.js index 9a541b757..867e4eb1c 100644 --- a/spec/mock-request.js +++ b/spec/mock-request.js @@ -28,6 +28,7 @@ HttpBackend.prototype = { var defer = q.defer(); var self = this; var flushed = 0; + var triedWaiting = false; console.log( "HTTP backend flushing... (path=%s numToFlush=%s)", path, numToFlush ); @@ -49,6 +50,12 @@ HttpBackend.prototype = { setTimeout(tryFlush, 0); } } + else if (flushed === 0 && !triedWaiting) { + // we may not have made the request yet, wait a generous amount of + // time before giving up. + setTimeout(tryFlush, 5); + triedWaiting = true; + } else { console.log(" no more flushes. [%s]", path); defer.resolve();