From f18efa2c235994e5a177d6748ef5220488a3f84b Mon Sep 17 00:00:00 2001 From: John Furrow Date: Sat, 10 Jun 2017 10:43:01 -0700 Subject: [PATCH] Close event stream after 30 seconds of inactivity --- CHANGELOG.md | 1 + client/javascript/actions/FloodActions.js | 41 ++++++++-- server/assets/app.js | 92 +++++++++++------------ 3 files changed, 82 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb476eb0..6b488fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ via an event-stream. This significantly reduces data usage on the Flood client * Stream covers torrent list, transfer rate summary & history, torrent taxonomy, and notification count. +* Close event stream after the window/tab has been inactive for 30 seconds ## [1.0.0] (April 21, 2017) * First "official" release diff --git a/client/javascript/actions/FloodActions.js b/client/javascript/actions/FloodActions.js index e47fa751..de7ab493 100644 --- a/client/javascript/actions/FloodActions.js +++ b/client/javascript/actions/FloodActions.js @@ -10,7 +10,33 @@ import serverEventTypes from '../../../shared/constants/serverEventTypes'; const baseURI = ConfigStore.getBaseURI(); let activityStreamEventSource = null; -let lastHistorySnapshot = null; +let lastActivityStreamOptions = undefined; +let visibilityChangeTimeout = null; + +const handleProlongedInactivity = () => { + FloodActions.closeActivityStream(); +}; + +const handleWindowVisibilityChange = () => { + if (global.document.hidden) { + // After 30 seconds of inactivity, we stop the event stream. + visibilityChangeTimeout = global.setTimeout( + handleProlongedInactivity, + 1000 * 30 + ); + } else { + global.clearTimeout(visibilityChangeTimeout); + + if (activityStreamEventSource == null) { + FloodActions.startActivityStream(lastActivityStreamOptions); + } + } +}; + +global.document.addEventListener( + 'visibilitychange', + handleWindowVisibilityChange +); const FloodActions = { clearNotifications: (options) => { @@ -216,16 +242,19 @@ const FloodActions = { }); }, - restartActivityStream(options) { + restartActivityStream() { this.closeActivityStream(); - this.startActivityStream(options); + this.startActivityStream(lastActivityStreamOptions); }, startActivityStream(options = {}) { const {historySnapshot = historySnapshotTypes.FIVE_MINUTE} = options; - const didHistorySnapshotChange = lastHistorySnapshot !== historySnapshot; + const didHistorySnapshotChange = ( + lastActivityStreamOptions + && lastActivityStreamOptions.historySnapshot !== historySnapshot + ); - lastHistorySnapshot = historySnapshot; + lastActivityStreamOptions = options; // When the user requests a new history snapshot during an open session, // we need to close and re-open the event stream. @@ -235,7 +264,7 @@ const FloodActions = { // If the user requested a new history snapshot, or the event source has not // alraedy been created, we open the event stream. - if (didHistorySnapshotChange || activityStreamEventSource == null) { + if (didHistorySnapshotChange || activityStreamEventSource === null) { activityStreamEventSource = new EventSource( `${baseURI}api/activity-stream?historySnapshot=${historySnapshot}` ); diff --git a/server/assets/app.js b/server/assets/app.js index 918ec057..6bebd5dc 100644 --- a/server/assets/app.js +++ b/server/assets/app.js @@ -1,46 +1,46 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){n(1),e.exports=n(298)},function(e,t,n){(function(e){"use strict";function t(e,t,n){e[t]||Object[r](e,t,{writable:!0,configurable:!0,value:n})}if(n(2),n(293),n(295),e._babelPolyfill)throw new Error("only one instance of babel-polyfill is allowed");e._babelPolyfill=!0;var r="defineProperty";t(String.prototype,"padLeft","".padStart),t(String.prototype,"padRight","".padEnd),"pop,reverse,shift,keys,values,entries,indexOf,every,some,forEach,map,filter,find,findIndex,includes,join,slice,concat,push,splice,unshift,sort,lastIndexOf,reduce,reduceRight,copyWithin,fill".split(",").forEach(function(e){[][e]&&t(Array,e,Function.call.bind([][e]))})}).call(t,function(){return this}())},function(e,t,n){n(3),n(52),n(53),n(54),n(55),n(57),n(60),n(61),n(62),n(63),n(64),n(65),n(66),n(67),n(68),n(70),n(72),n(74),n(76),n(79),n(80),n(81),n(85),n(87),n(89),n(92),n(93),n(94),n(95),n(97),n(98),n(99),n(100),n(101),n(102),n(103),n(105),n(106),n(107),n(109),n(110),n(111),n(113),n(114),n(115),n(116),n(117),n(118),n(119),n(120),n(121),n(122),n(123),n(124),n(125),n(126),n(131),n(132),n(136),n(137),n(138),n(139),n(141),n(142),n(143),n(144),n(145),n(146),n(147),n(148),n(149),n(150),n(151),n(152),n(153),n(154),n(155),n(156),n(157),n(159),n(160),n(166),n(167),n(169),n(170),n(171),n(175),n(176),n(177),n(178),n(179),n(181),n(182),n(183),n(184),n(187),n(189),n(190),n(191),n(193),n(195),n(197),n(198),n(199),n(201),n(202),n(203),n(204),n(211),n(214),n(215),n(217),n(218),n(221),n(222),n(224),n(225),n(226),n(227),n(228),n(229),n(230),n(231),n(232),n(233),n(234),n(235),n(236),n(237),n(238),n(239),n(240),n(241),n(242),n(244),n(245),n(246),n(247),n(248),n(249),n(251),n(252),n(253),n(254),n(255),n(256),n(257),n(258),n(260),n(261),n(263),n(264),n(265),n(266),n(269),n(270),n(271),n(272),n(273),n(274),n(275),n(276),n(278),n(279),n(280),n(281),n(282),n(283),n(284),n(285),n(286),n(287),n(288),n(291),n(292),e.exports=n(9)},function(e,t,n){"use strict";var r=n(4),a=n(5),i=n(6),o=n(8),s=n(18),u=n(22).KEY,l=n(7),c=n(23),d=n(24),f=n(19),h=n(25),p=n(26),m=n(27),_=n(29),v=n(42),g=n(45),y=n(12),M=n(32),b=n(16),E=n(17),T=n(46),S=n(49),k=n(51),L=n(11),w=n(30),D=k.f,C=L.f,x=S.f,O=r.Symbol,N=r.JSON,R=N&&N.stringify,A=h("_hidden"),Y=h("toPrimitive"),P={}.propertyIsEnumerable,I=c("symbol-registry"),F=c("symbols"),j=c("op-symbols"),H=Object.prototype,U="function"==typeof O,W=r.QObject,V=!W||!W.prototype||!W.prototype.findChild,z=i&&l(function(){return 7!=T(C({},"a",{get:function(){return C(this,"a",{value:7}).a}})).a})?function(e,t,n){var r=D(H,t);r&&delete H[t],C(e,t,n),r&&e!==H&&C(H,t,r)}:C,G=function(e){var t=F[e]=T(O.prototype);return t._k=e,t},B=U&&"symbol"==typeof O.iterator?function(e){return"symbol"==typeof e}:function(e){return e instanceof O},q=function(e,t,n){return e===H&&q(j,t,n),y(e),t=b(t,!0),y(n),a(F,t)?(n.enumerable?(a(e,A)&&e[A][t]&&(e[A][t]=!1),n=T(n,{enumerable:E(0,!1)})):(a(e,A)||C(e,A,E(1,{})),e[A][t]=!0),z(e,t,n)):C(e,t,n)},J=function(e,t){y(e);for(var n,r=v(t=M(t)),a=0,i=r.length;i>a;)q(e,n=r[a++],t[n]);return e},K=function(e,t){return void 0===t?T(e):J(T(e),t)},Z=function(e){var t=P.call(this,e=b(e,!0));return!(this===H&&a(F,e)&&!a(j,e))&&(!(t||!a(this,e)||!a(F,e)||a(this,A)&&this[A][e])||t)},X=function(e,t){if(e=M(e),t=b(t,!0),e!==H||!a(F,t)||a(j,t)){var n=D(e,t);return!n||!a(F,t)||a(e,A)&&e[A][t]||(n.enumerable=!0),n}},Q=function(e){for(var t,n=x(M(e)),r=[],i=0;n.length>i;)a(F,t=n[i++])||t==A||t==u||r.push(t);return r},$=function(e){for(var t,n=e===H,r=x(n?j:M(e)),i=[],o=0;r.length>o;)!a(F,t=r[o++])||n&&!a(H,t)||i.push(F[t]);return i};U||(O=function(){if(this instanceof O)throw TypeError("Symbol is not a constructor!");var e=f(arguments.length>0?arguments[0]:void 0),t=function(n){this===H&&t.call(j,n),a(this,A)&&a(this[A],e)&&(this[A][e]=!1),z(this,e,E(1,n))};return i&&V&&z(H,e,{configurable:!0,set:t}),G(e)},s(O.prototype,"toString",function(){return this._k}),k.f=X,L.f=q,n(50).f=S.f=Q,n(44).f=Z,n(43).f=$,i&&!n(28)&&s(H,"propertyIsEnumerable",Z,!0),p.f=function(e){return G(h(e))}),o(o.G+o.W+o.F*!U,{Symbol:O});for(var ee="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),te=0;ee.length>te;)h(ee[te++]);for(var ee=w(h.store),te=0;ee.length>te;)m(ee[te++]);o(o.S+o.F*!U,"Symbol",{for:function(e){return a(I,e+="")?I[e]:I[e]=O(e)},keyFor:function(e){if(B(e))return _(I,e);throw TypeError(e+" is not a symbol!")},useSetter:function(){V=!0},useSimple:function(){V=!1}}),o(o.S+o.F*!U,"Object",{create:K,defineProperty:q,defineProperties:J,getOwnPropertyDescriptor:X,getOwnPropertyNames:Q,getOwnPropertySymbols:$}),N&&o(o.S+o.F*(!U||l(function(){var e=O();return"[null]"!=R([e])||"{}"!=R({a:e})||"{}"!=R(Object(e))})),"JSON",{stringify:function(e){if(void 0!==e&&!B(e)){for(var t,n,r=[e],a=1;arguments.length>a;)r.push(arguments[a++]);return t=r[1],"function"==typeof t&&(n=t),!n&&g(t)||(t=function(e,t){if(n&&(t=n.call(this,e,t)),!B(t))return t}),r[1]=t,R.apply(N,r)}}}),O.prototype[Y]||n(10)(O.prototype,Y,O.prototype.valueOf),d(O,"Symbol"),d(Math,"Math",!0),d(r.JSON,"JSON",!0)},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){e.exports=!n(7)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,n){var r=n(4),a=n(9),i=n(10),o=n(18),s=n(20),u=function(e,t,n){var l,c,d,f,h=e&u.F,p=e&u.G,m=e&u.S,_=e&u.P,v=e&u.B,g=p?r:m?r[t]||(r[t]={}):(r[t]||{}).prototype,y=p?a:a[t]||(a[t]={}),M=y.prototype||(y.prototype={});p&&(n=t);for(l in n)c=!h&&g&&void 0!==g[l],d=(c?g:n)[l],f=v&&c?s(d,r):_&&"function"==typeof d?s(Function.call,d):d,g&&o(g,l,d,e&u.U),y[l]!=d&&i(y,l,f),_&&M[l]!=d&&(M[l]=d)};r.core=a,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t){var n=e.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n)},function(e,t,n){var r=n(11),a=n(17);e.exports=n(6)?function(e,t,n){return r.f(e,t,a(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){var r=n(12),a=n(14),i=n(16),o=Object.defineProperty;t.f=n(6)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),a)try{return o(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){var r=n(13);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){e.exports=!n(6)&&!n(7)(function(){return 7!=Object.defineProperty(n(15)("div"),"a",{get:function(){return 7}}).a})},function(e,t,n){var r=n(13),a=n(4).document,i=r(a)&&r(a.createElement);e.exports=function(e){return i?a.createElement(e):{}}},function(e,t,n){var r=n(13);e.exports=function(e,t){if(!r(e))return e;var n,a;if(t&&"function"==typeof(n=e.toString)&&!r(a=n.call(e)))return a;if("function"==typeof(n=e.valueOf)&&!r(a=n.call(e)))return a;if(!t&&"function"==typeof(n=e.toString)&&!r(a=n.call(e)))return a;throw TypeError("Can't convert object to primitive value")}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(4),a=n(10),i=n(5),o=n(19)("src"),s=Function.toString,u=(""+s).split("toString");n(9).inspectSource=function(e){return s.call(e)},(e.exports=function(e,t,n,s){var l="function"==typeof n;l&&(i(n,"name")||a(n,"name",t)),e[t]!==n&&(l&&(i(n,o)||a(n,o,e[t]?""+e[t]:u.join(String(t)))),e===r?e[t]=n:s?e[t]?e[t]=n:a(e,t,n):(delete e[t],a(e,t,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[o]||s.call(this)})},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(21);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,a){return e.call(t,n,r,a)}}return function(){return e.apply(t,arguments)}}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(19)("meta"),a=n(13),i=n(5),o=n(11).f,s=0,u=Object.isExtensible||function(){return!0},l=!n(7)(function(){return u(Object.preventExtensions({}))}),c=function(e){o(e,r,{value:{i:"O"+ ++s,w:{}}})},d=function(e,t){if(!a(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,r)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[r].i},f=function(e,t){if(!i(e,r)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[r].w},h=function(e){return l&&p.NEED&&u(e)&&!i(e,r)&&c(e),e},p=e.exports={KEY:r,NEED:!1,fastKey:d,getWeak:f,onFreeze:h}},function(e,t,n){var r=n(4),a=r["__core-js_shared__"]||(r["__core-js_shared__"]={});e.exports=function(e){return a[e]||(a[e]={})}},function(e,t,n){var r=n(11).f,a=n(5),i=n(25)("toStringTag");e.exports=function(e,t,n){e&&!a(e=n?e:e.prototype,i)&&r(e,i,{configurable:!0,value:t})}},function(e,t,n){var r=n(23)("wks"),a=n(19),i=n(4).Symbol,o="function"==typeof i;(e.exports=function(e){return r[e]||(r[e]=o&&i[e]||(o?i:a)("Symbol."+e))}).store=r},function(e,t,n){t.f=n(25)},function(e,t,n){var r=n(4),a=n(9),i=n(28),o=n(26),s=n(11).f;e.exports=function(e){var t=a.Symbol||(a.Symbol=i?{}:r.Symbol||{});"_"==e.charAt(0)||e in t||s(t,e,{value:o.f(e)})}},function(e,t){e.exports=!1},function(e,t,n){var r=n(30),a=n(32);e.exports=function(e,t){for(var n,i=a(e),o=r(i),s=o.length,u=0;s>u;)if(i[n=o[u++]]===t)return n}},function(e,t,n){var r=n(31),a=n(41);e.exports=Object.keys||function(e){return r(e,a)}},function(e,t,n){var r=n(5),a=n(32),i=n(36)(!1),o=n(40)("IE_PROTO");e.exports=function(e,t){var n,s=a(e),u=0,l=[];for(n in s)n!=o&&r(s,n)&&l.push(n);for(;t.length>u;)r(s,n=t[u++])&&(~i(l,n)||l.push(n));return l}},function(e,t,n){var r=n(33),a=n(35);e.exports=function(e){return r(a(e))}},function(e,t,n){var r=n(34);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==r(e)?e.split(""):Object(e)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(32),a=n(37),i=n(39);e.exports=function(e){return function(t,n,o){var s,u=r(t),l=a(u.length),c=i(o,l);if(e&&n!=n){for(;l>c;)if((s=u[c++])!=s)return!0}else for(;l>c;c++)if((e||c in u)&&u[c]===n)return e||c||0;return!e&&-1}}},function(e,t,n){var r=n(38),a=Math.min;e.exports=function(e){return e>0?a(r(e),9007199254740991):0}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(38),a=Math.max,i=Math.min;e.exports=function(e,t){return e=r(e),e<0?a(e+t,0):i(e,t)}},function(e,t,n){var r=n(23)("keys"),a=n(19);e.exports=function(e){return r[e]||(r[e]=a(e))}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(30),a=n(43),i=n(44);e.exports=function(e){var t=r(e),n=a.f;if(n)for(var o,s=n(e),u=i.f,l=0;s.length>l;)u.call(e,o=s[l++])&&t.push(o);return t}},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var r=n(34);e.exports=Array.isArray||function(e){return"Array"==r(e)}},function(e,t,n){var r=n(12),a=n(47),i=n(41),o=n(40)("IE_PROTO"),s=function(){},u=function(){var e,t=n(15)("iframe"),r=i.length;for(t.style.display="none",n(48).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write("