Merge pull request #139 from matrix-org/dbkr/rate_limit_funcs

Make the function call-rate limiting a generic thing and use it in more places.
This commit is contained in:
David Baker 2016-02-05 10:15:55 +00:00
commit 0ae548cf5d
4 changed files with 50 additions and 34 deletions

View File

@ -41,6 +41,7 @@ var Resend = require("../../Resend");
var SlashCommands = require("../../SlashCommands"); var SlashCommands = require("../../SlashCommands");
var dis = require("../../dispatcher"); var dis = require("../../dispatcher");
var Tinter = require("../../Tinter"); var Tinter = require("../../Tinter");
var rate_limited_func = require('../../ratelimitedfunc');
var PAGINATE_SIZE = 20; var PAGINATE_SIZE = 20;
var INITIAL_SIZE = 20; var INITIAL_SIZE = 20;
@ -619,7 +620,7 @@ module.exports = React.createClass({
} }
}, },
_updateTabCompleteList: function(room) { _updateTabCompleteList: new rate_limited_func(function(room) {
if (!room || !this.tabComplete) { if (!room || !this.tabComplete) {
return; return;
} }
@ -628,7 +629,7 @@ module.exports = React.createClass({
CommandEntry.fromCommands(SlashCommands.getCommandList()) CommandEntry.fromCommands(SlashCommands.getCommandList())
) )
); );
}, }, 500),
_initialiseMessagePanel: function() { _initialiseMessagePanel: function() {
var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel);

View File

@ -22,6 +22,7 @@ var Modal = require("../../../Modal");
var Entities = require("../../../Entities"); var Entities = require("../../../Entities");
var sdk = require('../../../index'); var sdk = require('../../../index');
var GeminiScrollbar = require('react-gemini-scrollbar'); var GeminiScrollbar = require('react-gemini-scrollbar');
var rate_limited_func = require('../../../ratelimitedfunc');
var INITIAL_LOAD_NUM_MEMBERS = 30; var INITIAL_LOAD_NUM_MEMBERS = 30;
var SHARE_HISTORY_WARNING = "Newly invited users will see the history of this room. "+ var SHARE_HISTORY_WARNING = "Newly invited users will see the history of this room. "+
@ -147,14 +148,14 @@ module.exports = React.createClass({
} }
}, },
_updateList: function() { _updateList: new rate_limited_func(function() {
this.memberDict = this.getMemberDict(); this.memberDict = this.getMemberDict();
var self = this; var self = this;
this.setState({ this.setState({
members: self.roomMembers() members: self.roomMembers()
}); });
}, }, 500),
onInvite: function(inputText) { onInvite: function(inputText) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");

View File

@ -24,6 +24,7 @@ var RoomListSorter = require("../../../RoomListSorter");
var Unread = require('../../../Unread'); var Unread = require('../../../Unread');
var dis = require("../../../dispatcher"); var dis = require("../../../dispatcher");
var sdk = require('../../../index'); var sdk = require('../../../index');
var rate_limited_func = require('../../../ratelimitedfunc');
var HIDE_CONFERENCE_CHANS = true; var HIDE_CONFERENCE_CHANS = true;
@ -155,36 +156,9 @@ module.exports = React.createClass({
this._delayedRefreshRoomList(); this._delayedRefreshRoomList();
}, },
_delayedRefreshRoomList: function() { _delayedRefreshRoomList: new rate_limited_func(function() {
// There can be 1000s of JS SDK events when rooms are initially synced; this.refreshRoomList();
// we don't want to do lots of work rendering until things have settled. }, 500),
// Therefore, keep a 1s refresh buffer which will refresh the room list
// at MOST once every 1s to prevent thrashing.
var MAX_REFRESH_INTERVAL_MS = 1000;
var self = this;
if (!self._lastRefreshRoomListTs) {
self.refreshRoomList(); // first refresh evar
}
else {
var timeWaitedMs = Date.now() - self._lastRefreshRoomListTs;
if (timeWaitedMs > MAX_REFRESH_INTERVAL_MS) {
clearTimeout(self._refreshRoomListTimerId);
self._refreshRoomListTimerId = null;
self.refreshRoomList(); // refreshed more than MAX_REFRESH_INTERVAL_MS ago
}
else {
// refreshed less than MAX_REFRESH_INTERVAL_MS ago, wait the difference
// if we aren't already waiting. If we are waiting then NOP, it will
// fire soon, promise!
if (!self._refreshRoomListTimerId) {
self._refreshRoomListTimerId = setTimeout(function() {
self.refreshRoomList();
}, 10 + MAX_REFRESH_INTERVAL_MS - timeWaitedMs); // 10 is a buffer amount
}
}
}
},
refreshRoomList: function() { refreshRoomList: function() {
// console.log("DEBUG: Refresh room list delta=%s ms", // console.log("DEBUG: Refresh room list delta=%s ms",

40
src/ratelimitedfunc.js Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright 2016 OpenMarket 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.exports = function(f, minIntervalMs) {
this.lastCall = 0;
this.scheduledCall = undefined;
var self = this;
return function() {
var now = Date.now();
if (self.lastCall < now - minIntervalMs) {
f.apply(this);
self.lastCall = now;
} else if (self.scheduledCall === undefined) {
self.scheduledCall = setTimeout(
() => {
self.scheduledCall = undefined;
f.apply(this);
self.lastCall = now;
},
(self.lastCall + minIntervalMs) - now
);
}
};
};