From 9e8f933956037e79cc16165f1d7e1a38b1d4277f Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Fri, 25 May 2012 19:05:20 +0100 Subject: [PATCH 1/5] Update JSObserver (reliability, features, config) * Should now hide/show the div reliably * Message can now be customised by supplying a dict in the config file --- overviewer_core/data/js_src/views.js | 20 ++++++++---- overviewer_core/observer.py | 46 +++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index bbb9afa..2db2a31 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -142,17 +142,25 @@ overviewer.views.ProgressView = Backbone.View.extend({ this.el.id = 'progressDiv'; this.el.innerHTML = 'Current Render Progress'; overviewer.map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(this.el); - this.hidden = true; + this.el.hidden = true; $.ajaxSetup({cache: false}); }, updateProgress: function() { e = this; - $.getJSON('progress.js', null, function(d){ - e.el.hidden = false; - e.el.innerHTML = d['message']; - if (d.update > 0) { - setTimeout("e.updateProgress()", d.update); + $.getJSON('progress.json', null, function(d){ + console.log(d); + if (!(d == null||d=='')) { + e.el.hidden = false; + e.el.innerHTML = d['message']; + if (d.update > 0) { + setTimeout("e.updateProgress()", d.update); + } else { + setTimeout("e.updateProgress()", 60000); + e.el.innerHTML="Hidden - d.update < 0"; + e.el.hidden = true; + } } else { + e.el.innerHTML="Hidden - !!d==false"; e.el.hidden = true; } }); diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index 7db5061..3b9d5b1 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -18,6 +18,7 @@ import logging import progressbar import sys import os +import json class Observer(object): """Base class that defines the observer interface. @@ -170,21 +171,42 @@ class JSObserver(Observer): """Display progress on index.html using JavaScript """ - def __init__(self, outputdir, minrefresh=5): + def __init__(self, outputdir, minrefresh=5, messages=False): """Initialise observer outputdir must be set to the map output directory path - minrefresh specifies the minimum gap between requests, in seconds + minrefresh specifies the minimum gap between requests, in seconds [optional] + messages is a dictionary which allows the displayed messages to be customised [optional] """ self.last_update = -11 self.last_update_time = -1 self._current_value = -1 self.minrefresh = 1000*minrefresh - self.logfile = open(os.path.join(outputdir, "progress.js"), "w+", 0) + self.logfile = open(os.path.join(outputdir, "progress.json"), "w+", 0) + self.json = dict() + + if (messages == False): + self.messages=dict(totalTiles="Rendering %d tiles", renderCompleted="Render completed in %02d:%02d:%02d", renderProgress="Rendered %d of %d tiles (%d%%)") + elif (isinstance(messages, dict)): + if (totalTiles in messages and renderCompleted in messages and renderProgress in messages): + self.messages = messages + else: + raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") + else: + raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") + + self.json["message"]="" + self.json["update"]=self.minrefresh + self.json["messageTime"]=time.time() + json.dump(self.json, self.logfile) + self.logfile.flush() def start(self, max_value): self.logfile.seek(0) - self.logfile.write('{"message": "Rendering %d tiles", "update": %s}' % (max_value, self.minrefresh)) self.logfile.truncate() + self.json["message"] = self.messages["totalTiles"] % (max_value) + self.json["update"] = self.minrefresh + self.json["messageTime"] = time.time() + json.dump(self.json, self.logfile) self.logfile.flush() self.start_time=time.time() self._set_max_value(max_value) @@ -199,8 +221,15 @@ class JSObserver(Observer): self.end_time = time.time() duration = self.end_time - self.start_time self.logfile.seek(0) - self.logfile.write('{"message": "Render completed in %dm %ds", "update": "false"}' % (duration//60, duration - duration//60)) self.logfile.truncate() + hours = duration // 3600 + duration = duration % 3600 + minutes = duration // 60 + seconds = duration % 60 + self.json["message"] = self.messages["renderCompleted"] % (hours, minutes, seconds) + self.json["update"] = -1 # Initially this was set to False, but that runs into some JS strangeness. -1 is less nice, but works + self.json["messageTime"] = time.time() + json.dump(self.json, self.logfile) self.logfile.close() def is_finished(self): @@ -222,10 +251,13 @@ class JSObserver(Observer): """ self._current_value = current_value if self._need_update(): - refresh = max(1500*(time.time() - self.last_update_time), self.minrefresh) + refresh = max(1500*(time.time() - self.last_update_time), self.minrefresh) // 1 self.logfile.seek(0) - self.logfile.write('{"message": "Rendered %d of %d tiles (%d%%)", "update": %d }' % (self.get_current_value(), self.get_max_value(), self.get_percentage(), refresh)) self.logfile.truncate() + self.json["message"] = self.messages["renderProgress"] % (self.get_current_value(), self.get_max_value(), self.get_percentage()) + self.json["update"] = refresh + self.json["messageTime"] = time.time() + json.dump(self.json, self.logfile) self.logfile.flush() self.last_update_time = time.time() self.last_update = current_value From 0a90f0f896ffef52aec23daf14fb250f3d8cf05a Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Fri, 25 May 2012 19:12:23 +0100 Subject: [PATCH 2/5] Remove errant console.log() --- overviewer_core/data/js_src/views.js | 1 - 1 file changed, 1 deletion(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 2db2a31..1182a57 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -148,7 +148,6 @@ overviewer.views.ProgressView = Backbone.View.extend({ updateProgress: function() { e = this; $.getJSON('progress.json', null, function(d){ - console.log(d); if (!(d == null||d=='')) { e.el.hidden = false; e.el.innerHTML = d['message']; From c05d628723114119e1909ec2119a6e21e1240075 Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Fri, 25 May 2012 19:15:54 +0100 Subject: [PATCH 3/5] Correct 'if x in messages' to 'if "x" in messages' --- overviewer_core/observer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index 3b9d5b1..0e1c587 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -187,7 +187,7 @@ class JSObserver(Observer): if (messages == False): self.messages=dict(totalTiles="Rendering %d tiles", renderCompleted="Render completed in %02d:%02d:%02d", renderProgress="Rendered %d of %d tiles (%d%%)") elif (isinstance(messages, dict)): - if (totalTiles in messages and renderCompleted in messages and renderProgress in messages): + if ('totalTiles' in messages and 'renderCompleted' in messages and 'renderProgress' in messages): self.messages = messages else: raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") From 2ef6951e2827ecbe9a0809b99738e7e2007b901a Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Fri, 25 May 2012 20:38:32 +0100 Subject: [PATCH 4/5] Make JSObserver throw a more helpful error if path not valid --- overviewer_core/observer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index 0e1c587..b2e4619 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -181,7 +181,6 @@ class JSObserver(Observer): self.last_update_time = -1 self._current_value = -1 self.minrefresh = 1000*minrefresh - self.logfile = open(os.path.join(outputdir, "progress.json"), "w+", 0) self.json = dict() if (messages == False): @@ -193,7 +192,10 @@ class JSObserver(Observer): raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") else: raise Exception("JSObserver: messages parameter must be a dictionary with three entries: totalTiles, renderCompleted and renderProgress") + if not os.path.exists(outputdir): + raise Exception("JSObserver: Output directory specified (%s) doesn't appear to exist. This should be the same as the Overviewer output directory") + self.logfile = open(os.path.join(outputdir, "progress.json"), "w+", 0) self.json["message"]="" self.json["update"]=self.minrefresh self.json["messageTime"]=time.time() From beaa2a9f09db9a99c594bf821ebef557b1db429a Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Fri, 25 May 2012 21:44:23 +0100 Subject: [PATCH 5/5] JSObserver documentation --- docs/config.rst | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index c41d995..3e79340 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -269,16 +269,39 @@ the form ``key = value``. Two items take a different form:, ``worlds`` and This is used by default when the output is a terminal. Displays a text based progress bar and some statistics. - ``JSObserver`` + ``JSObserver(outputdir[, minrefresh][, messages])`` This will display render progress on the output map in the bottom right - corner of the screen. ``JSObserver`` must be invoked with two parameters. + corner of the screen. ``JSObserver``. - The first is output directory. For simplicity, specify this as ``outputdir`` - and place this line after setting ``outputdir = ""``. + * ``outputdir="`` + Progress information won't be written to file or requested by your + web browser more frequently than this interval. + + * ``messages=dict(totalTiles=, renderCompleted=, renderProgress=)`` + Customises messages displayed in browser. All three messages must be + defined as follows: + + * ``totalTiles="Rendering %d tiles"`` + The ``%d`` format string will be replaced with the total number of + tiles to be rendered. + + * ``renderCompleted="Render completed in %02d:%02d:%02d"`` + The three format strings will be replaced with the number of hours. + minutes and seconds taken to complete this render. + + * ``renderProgress="Rendered %d of %d tiles (%d%%)"`` + The three format strings will be replaced with the number of tiles + completed, the total number of tiles and the percentage complete + + Format strings are explained here: http://docs.python.org/library/stdtypes.html#string-formatting + All format strings must be present in your custom messages. + :: from observer import JSObserver