[Libreoffice-commits] online.git: 6 commits - common/Protocol.hpp loleaflet/src loolwsd.xml.in wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp

Tor Lillqvist tml at collabora.com
Wed Dec 14 16:53:05 UTC 2016


 common/Protocol.hpp          |    3 -
 loleaflet/src/core/Socket.js |    1 
 loleaflet/src/map/Map.js     |  128 ++++++++++++++++++++++++++++---------------
 loolwsd.xml.in               |    2 
 wsd/DocumentBroker.cpp       |    2 
 wsd/DocumentBroker.hpp       |    4 +
 wsd/LOOLWSD.cpp              |   27 +++++++++
 7 files changed, 121 insertions(+), 46 deletions(-)

New commits:
commit 36f3dece7c6ecc8bd0ccb8caacbe8e7c31ab47f7
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 18:12:57 2016 +0200

    Bluntly close sessions that have been idle for more than an hour
    
    By that time the loleaflet code has already done the greying-out (this
    happens at the latest after 10 minutes of inactivity) and marked them
    as 'inactive'. Bluntly closing the session seems to work out fine, no
    new horribly alarming message is displayed by the loleaflet code in
    addition to the already visible 'Inactive document ...' one.
    
    Change-Id: I420f0d7530194e6c8d6f34d7985ab810cde5a76a

diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 21c3b4c..17361ee 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -11,6 +11,7 @@
 #include "config.h"
 
 #include <cassert>
+#include <ctime>
 #include <fstream>
 #include <sstream>
 
@@ -1040,6 +1041,7 @@ void DocumentBroker::closeDocument(const std::string& reason)
 
 void DocumentBroker::updateLastActivityTime()
 {
+    _lastActivity = std::time(nullptr);
     Admin::instance().updateLastActivityTime(_docKey);
 }
 
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 758ece1..5c5ed68 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -303,6 +303,8 @@ public:
 
     void updateLastActivityTime();
 
+    std::time_t getIdleTime() const { return std::time(nullptr) - _lastActivity; }
+
 private:
     /// Sends the .uno:Save command to LoKit.
     bool sendUnoSave(const bool dontSaveIfUnmodified);
@@ -345,6 +347,8 @@ private:
 
     int _debugRenderedTileCount;
 
+    std::time_t _lastActivity;
+
     static constexpr auto IdleSaveDurationMs = 30 * 1000;
     static constexpr auto AutoSaveDurationMs = 300 * 1000;
 };
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 5bff5e6..fbdc975 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2060,6 +2060,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
 #endif
 
     time_t last30SecCheck = time(nullptr);
+    time_t lastOneHourCheck = time(nullptr);
     int status = 0;
     while (!TerminationFlag && !SigUtil::isShuttingDown())
     {
@@ -2150,6 +2151,32 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
             }
             else
             {
+                // Every 15 minutes
+                if (time(nullptr) >= lastOneHourCheck + 900)
+                {
+                    // Bluntly close documents that have been idle over an hour. (By that time
+                    // loleaflet's greying-out has already also kicked in.)
+                    try
+                    {
+                        std::unique_lock<std::mutex> docBrokersLock(DocBrokersMutex);
+                        for (auto& pair : DocBrokers)
+                        {
+                            auto docLock = pair.second->getLock();
+                            if (pair.second->getIdleTime() >= 3600)
+                            {
+                                LOG_INF("Terminating idle document " + pair.second->getDocKey());
+                                pair.second->terminateChild(docLock);
+                            }
+                        }
+                    }
+                    catch (const std::exception& exc)
+                    {
+                        LOG_ERR("Exception: " << exc.what());
+                    }
+
+                    lastOneHourCheck = time(nullptr);
+                }
+
                 // Don't wait if we had been saving, which takes a while anyway.
                 std::this_thread::sleep_for(std::chrono::milliseconds(CHILD_REBALANCE_INTERVAL_MS));
             }
commit 8b05044151e1af11fc160fef6031bab006fe5615
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 18:12:31 2016 +0200

    Add an Emacs mode line to the two JS files I edit most often
    
    Change-Id: I4bcce4a859221aa9581df85945080178f90ae6ce

diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index 010a795..8ef38ec 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -1,3 +1,4 @@
+/* -*- js-indent-level: 8 -*- */
 /*
  * L.Socket contains methods for the communication with the server
  */
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index 76ee25a..784ded6 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -1,3 +1,4 @@
+/* -*- js-indent-level: 8 -*- */
 /*
  * L.Map is the central class of the API - it is used to create a map.
  */
commit 2bbab9bf943723c77498229676b93e9aba0185c7
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 18:09:45 2016 +0200

    Don't let whether the web console is open of not affect our behaviour
    
    After all, why would you have the console open unless when debugging
    (even just following console.log() output), so it is
    counter-productive to have the code behave differently in that case.
    
    Change-Id: I2aa7cf095e249a4c87f920aa0f1911be76a348ca

diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index b31be1c..76ee25a 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -766,7 +766,7 @@ L.Map = L.Evented.extend({
 
 	_dim: function() {
 		// console.log('_dim:');
-		if (window.devtools.open || !map._socket.connected()) {
+		if (!map._socket.connected()) {
 			return;
 		}
 
@@ -837,7 +837,7 @@ L.Map = L.Evented.extend({
 		// console.log('_deactivate:');
 		clearTimeout(vex.timer);
 
-		if (!window.devtools.open && (!this._active || vex.dialogID > 0)) {
+		if (!this._active || vex.dialogID > 0) {
 			// A dialog is already dimming the screen and probably
 			// shows an error message. Leave it alone.
 			this._active = false;
commit 8f98206926e49fcf563b4c4f2dc171d04c01bd69
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 18:02:10 2016 +0200

    Grey-out ("dim") after 10 minutes if idle even while having focus
    
    (The greying-out without focus happens, as before, already after 30
    seconds.)
    
    Factor out the dimming code to a separate function _dim. When we have
    focus, check once a minute if ten minutes has passed without user
    activity. Keep track of when last user activity happened.
    
    There is a bug left: When greyed-out while having focus, you need to
    click on the background layer, not in the layer with the 'Inactive
    document ...' text, to wake it up.
    
    Change-Id: I19160a82f5de860fc609dad391b168acfba560ce

diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index b53c2d7..b31be1c 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -20,6 +20,8 @@ L.Map = L.Evented.extend({
 		urlPrefix: 'lool'
 	},
 
+	lastActiveTime: Date.now(),
+
 	initialize: function (id, options) { // (HTMLElement or String, Object)
 		options = L.setOptions(this, options);
 
@@ -737,17 +739,20 @@ L.Map = L.Evented.extend({
 	},
 
 	_activate: function () {
+		// console.log('_activate:');
 		clearTimeout(vex.timer);
 
 		if (!this._active) {
 			// Only activate when we are connected.
 			if (this._socket.connected()) {
+				// console.log('  sending useractive');
 				this._socket.sendMessage('useractive');
 				this._active = true;
 				this._docLayer._onMessage('invalidatetiles: EMPTY', null);
 				if (vex.dialogID > 0) {
 					var id = vex.dialogID;
 					vex.dialogID = -1;
+					this._startInactiveTimer();
 					return vex.close(id);
 				}
 			} else {
@@ -755,10 +760,81 @@ L.Map = L.Evented.extend({
 			}
 		}
 
+		this._startInactiveTimer();
 		return false;
 	},
 
+	_dim: function() {
+		// console.log('_dim:');
+		if (window.devtools.open || !map._socket.connected()) {
+			return;
+		}
+
+		// console.log('  cont');
+		map._active = false;
+		clearTimeout(vex.timer);
+
+		var options = $.extend({}, vex.defaultOptions, {
+			contentCSS: {'background':'rgba(0, 0, 0, 0)',
+				     'font-size': 'xx-large',
+				     'color': '#fff',
+				     'text-align': 'center'},
+			content: _('Inactive document - please click to resume editing')
+		});
+		options.id = vex.globalID;
+		vex.dialogID = options.id;
+		vex.globalID += 1;
+		options.$vex = $('<div>').addClass(vex.baseClassNames.vex).addClass(options.className).css(options.css).data({
+			vex: options
+		});
+		options.$vexOverlay = $('<div>').addClass(vex.baseClassNames.overlay).addClass(options.overlayClassName).css(options.overlayCSS).data({
+			vex: options
+		});
+
+		options.$vexOverlay.bind('click.vex', function(e) {
+			// console.log('click.vex function');
+			if (e.target !== this) {
+				// console.log('  early return');
+				return 0;
+			}
+			// console.log('  calling _activate');
+			return map._activate();
+		});
+		options.$vex.append(options.$vexOverlay);
+
+		options.$vexContent = $('<div>').addClass(vex.baseClassNames.content).addClass(options.contentClassName).css(options.contentCSS).text(options.content).data({
+			vex: options
+		});
+		options.$vex.append(options.$vexContent);
+
+		$(options.appendLocation).append(options.$vex);
+		vex.setupBodyClassName(options.$vex);
+
+		map._doclayer && map._docLayer._onMessage('textselection:', null);
+		// console.log('  sending userinactive');
+		map._socket.sendMessage('userinactive');
+	},
+
+	_dimIfInactive: function () {
+		// console.log('_dimIfInactive: diff=' + (Date.now() - map.lastActiveTime));
+		if ((Date.now() - map.lastActiveTime) >= 10 * 60 * 1000) { // Dim 10 minutes after last user activity
+			map._dim();
+		} else {
+			map._startInactiveTimer();
+		}
+	},
+
+	_startInactiveTimer: function () {
+		// console.log('_startInactiveTimer:');
+		clearTimeout(vex.timer);
+		var map = this;
+		vex.timer = setTimeout(function() {
+			map._dimIfInactive();
+		}, 1 * 60 * 1000); // Check once a minute
+	},
+
 	_deactivate: function () {
+		// console.log('_deactivate:');
 		clearTimeout(vex.timer);
 
 		if (!window.devtools.open && (!this._active || vex.dialogID > 0)) {
@@ -767,6 +843,7 @@ L.Map = L.Evented.extend({
 			this._active = false;
 			this._docLayer && this._docLayer._onMessage('textselection:', null);
 			if (this._socket.connected()) {
+				// console.log('  sending userinactive');
 				this._socket.sendMessage('userinactive');
 			}
 
@@ -775,49 +852,7 @@ L.Map = L.Evented.extend({
 
 		var map = this;
 		vex.timer = setTimeout(function() {
-			if (window.devtools.open || !map._socket.connected()) {
-				return;
-			}
-
-			map._active = false;
-			clearTimeout(vex.timer);
-
-			var options = $.extend({}, vex.defaultOptions, {
-				contentCSS: {'background':'rgba(0, 0, 0, 0)',
-				             'font-size': 'xx-large',
-				             'color': '#fff',
-				             'text-align': 'center'},
-				content: _('Inactive document - please click to resume editing')
-			});
-			options.id = vex.globalID;
-			vex.dialogID = options.id;
-			vex.globalID += 1;
-			options.$vex = $('<div>').addClass(vex.baseClassNames.vex).addClass(options.className).css(options.css).data({
-				vex: options
-			});
-			options.$vexOverlay = $('<div>').addClass(vex.baseClassNames.overlay).addClass(options.overlayClassName).css(options.overlayCSS).data({
-				vex: options
-			});
-
-			options.$vexOverlay.bind('click.vex', function(e) {
-				if (e.target !== this) {
-					return 0;
-				}
-				return map._activate();
-			});
-			options.$vex.append(options.$vexOverlay);
-
-			options.$vexContent = $('<div>').addClass(vex.baseClassNames.content).addClass(options.contentClassName).css(options.contentCSS).text(options.content).data({
-				vex: options
-			});
-			options.$vex.append(options.$vexContent);
-
-			$(options.appendLocation).append(options.$vex);
-			vex.setupBodyClassName(options.$vex);
-
-			map._doclayer && map._docLayer._onMessage('textselection:', null);
-			map._socket.sendMessage('userinactive');
-
+			map._dim();
 		}, 30 * 1000); // Dim in 30 seconds.
 	},
 
@@ -841,8 +876,10 @@ L.Map = L.Evented.extend({
 	},
 
 	_onGotFocus: function () {
+		// console.log('_onGotFocus:');
 		if (!this._loaded) { return; }
 
+		// console.log('  cont');
 		var doclayer = this._docLayer;
 		if (doclayer) {
 			// we restore the old cursor position by a small delay, so that if the user clicks
@@ -891,6 +928,8 @@ L.Map = L.Evented.extend({
 	_handleDOMEvent: function (e) {
 		if (!this._loaded || !this._enabled || L.DomEvent._skipped(e)) { return; }
 
+		this.lastActiveTime = Date.now();
+
 		// find the layer the event is propagating from
 		var target = this._targets[L.stamp(e.target || e.srcElement)],
 			//type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
commit 0bdac17fa6a5e7bf730b736af99d70fa0650b4a1
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 17:23:42 2016 +0200

    Add 'userinactive' to messages that don't indicate user interaction
    
    In fact, it is more or less the opposite;)
    
    Change-Id: I34eca0ed6b7d4ce369ae803eac542f0996d193eb

diff --git a/common/Protocol.hpp b/common/Protocol.hpp
index 404e01b..d69c14a 100644
--- a/common/Protocol.hpp
+++ b/common/Protocol.hpp
@@ -150,7 +150,8 @@ namespace LOOLProtocol
 
         return (token.find("tile") == std::string::npos &&
                 token.find("status") == std::string::npos &&
-                token.find("state") == std::string::npos);
+                token.find("state") == std::string::npos &&
+                token != "userinactive");
     }
 
     /// Returns the first line of a message.
commit cbb0bec0ab5d70b74731174d58a5e98b230a6054
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Dec 14 13:45:26 2016 +0200

    Mention that without flushing, log lines are not necessarily in chronological order
    
    Change-Id: I9fef5f58ec1ac645f49543fbbe469e6f79ae175f

diff --git a/loolwsd.xml.in b/loolwsd.xml.in
index c3a550b..0df6a01 100644
--- a/loolwsd.xml.in
+++ b/loolwsd.xml.in
@@ -29,7 +29,7 @@
             <property name="purgeAge" desc="The maximum age of log files to preserve. See Poco FileChannel.">10 days</property>
             <property name="purgeCount" desc="The maximum number of log archives to preserve. Use 'none' to disable purging. See Poco FileChannel.">10</property>
             <property name="rotateOnOpen" desc="Enable/disable log file rotation on opening.">true</property>
-            <property name="flush" desc="Enable/disable flushing after each entry. May harm performance.">false</property>
+            <property name="flush" desc="Enable/disable flushing after logging each line. May harm performance. Note that without flushing after each line, the log lines from the different processes will not appear in chronological order.">false</property>
         </file>
     </logging>
 


More information about the Libreoffice-commits mailing list