[tor-commits] [ooni-probe/master] Start the director after the GUI is available. Implement a long polling mechanism.
art at torproject.org
art at torproject.org
Mon Sep 19 12:14:24 UTC 2016
commit f7f272d93a640d091855c7ca85c274b3aa7113e9
Author: Arturo Filastò <arturo at filasto.net>
Date: Mon Jul 18 19:18:39 2016 +0200
Start the director after the GUI is available. Implement a long polling mechanism.
---
ooni/ui/web/server.py | 80 +++++++++++++++++++++++++++++++++++++++++++++------
ooni/ui/web/web.py | 14 ++-------
2 files changed, 75 insertions(+), 19 deletions(-)
diff --git a/ooni/ui/web/server.py b/ooni/ui/web/server.py
index ccc5d87..ca51041 100644
--- a/ooni/ui/web/server.py
+++ b/ooni/ui/web/server.py
@@ -3,7 +3,7 @@ from __future__ import print_function
import os
import json
-from twisted.internet import defer
+from twisted.internet import defer, task, reactor
from twisted.python import usage
from twisted.python.filepath import FilePath, InsecurePath
from twisted.web import static
@@ -11,6 +11,7 @@ from twisted.web import static
from klein import Klein
from werkzeug.exceptions import NotFound
+from ooni import __version__ as ooniprobe_version
from ooni import errors
from ooni.deck import Deck
from ooni.settings import config
@@ -46,11 +47,74 @@ def getNetTestLoader(test_options, test_file):
class WebUIAPI(object):
app = Klein()
+ # Maximum number in seconds after which to return a result even if not
+ # change happenned.
+ _long_polling_timeout = 5
+ _reactor = reactor
def __init__(self, config, director):
self.director = director
self.config = config
- self.active_measurements = {}
+ self.status = {
+ "software_version": ooniprobe_version,
+ "software_name": "ooniprobe",
+ "asn": config.probe_ip.geodata['asn'],
+ "country_code": config.probe_ip.geodata['countrycode'],
+ "active_measurements": {},
+ "completed_measurements": [],
+ "director_started": False,
+ "failures": []
+ }
+ self.status_updates = []
+ d = self.director.start(start_tor=True)
+
+ d.addCallback(self.director_started)
+ d.addErrback(self.director_startup_failed)
+ d.addBoth(lambda _: self.broadcast_status_update())
+
+ def add_failure(self, failure):
+ self.status['failures'].append(failure)
+
+ def director_started(self, _):
+ self.status['director_started'] = True
+ self.status["asn"] = config.probe_ip.geodata['asn']
+ self.status["country_code"] = config.probe_ip.geodata['countrycode']
+
+ def director_startup_failed(self, failure):
+ self.add_failure(failure)
+
+ def broadcast_status_update(self):
+ for su in self.status_updates:
+ if not su.called:
+ su.callback(None)
+
+ def completed_measurement(self, measurement_id):
+ del self.status['active_measurements'][measurement_id]
+ self.status['completed_measurements'].append(measurement_id)
+
+ def failed_measurement(self, measurement_id, failure):
+ del self.status['active_measurements'][measurement_id]
+ self.add_failure(failure)
+
+ @app.route('/api/status', methods=["GET"])
+ def api_status(self, request):
+ print("Rendering status...")
+ return self.render_json(self.status, request)
+
+ @app.route('/api/status/update', methods=["GET"])
+ def api_status_update(self, request):
+ status_update = defer.Deferred()
+ status_update.addCallback(lambda _:
+ self.status_updates.remove(status_update))
+ status_update.addCallback(lambda _: self.api_status(request))
+
+ self.status_updates.append(status_update)
+
+ # After long_polling_timeout we fire the callback
+ task.deferLater(self._reactor, self._long_polling_timeout,
+ status_update.callback, None)
+
+ return status_update
@app.handle_errors(NotFound)
def not_found(self, request, _):
@@ -91,11 +155,15 @@ class WebUIAPI(object):
report_filename = os.path.join(measurement_dir,
"measurements.njson")
measurement_ids.append(measurement_id)
- self.active_measurements[measurement_id] = {
+ self.status['active_measurements'][measurement_id] = {
'test_name': test_details['test_name'],
'test_start_time': test_details['test_start_time']
}
- self.director.startNetTest(net_test_loader, report_filename)
+ self.broadcast_status_update()
+ d = self.director.startNetTest(net_test_loader, report_filename)
+ d.addCallback(lambda _: self.completed_measurement(measurement_id))
+ d.addErrback(lambda failure:
+ self.failed_measurement(measurement_id, failure))
@app.route('/api/nettest/<string:test_name>/start', methods=["POST"])
def api_nettest_start(self, request, test_name):
@@ -147,10 +215,6 @@ class WebUIAPI(object):
def api_nettest_list(self, request):
return self.render_json(self.director.netTests, request)
- @app.route('/api/status', methods=["GET"])
- def api_status(self):
- return self.render_json()
-
@app.route('/api/measurement', methods=["GET"])
def api_measurement_list(self, request):
measurement_ids = os.listdir(os.path.join(config.ooni_home,
diff --git a/ooni/ui/web/web.py b/ooni/ui/web/web.py
index 6c6971c..40ee3b4 100644
--- a/ooni/ui/web/web.py
+++ b/ooni/ui/web/web.py
@@ -19,19 +19,11 @@ class WebUIService(service.MultiService):
config.set_paths()
config.initialize_ooni_home()
config.read_config_file()
- def _started(res):
- log.msg("Director started")
- root = server.Site(WebUIAPI(config, director).app.resource())
- self._port = reactor.listenTCP(self.portNum, root)
director = Director()
+ web_ui_api = WebUIAPI(config, director)
+ root = server.Site(web_ui_api.app.resource())
+ self._port = reactor.listenTCP(self.portNum, root)
d = director.start()
- d.addCallback(_started)
- d.addErrback(self._startupFailed)
-
- def _startupFailed(self, err):
- log.err("Failed to start the director")
- log.exception(err)
- os.abort()
def stopService(self):
if self._port:
More information about the tor-commits
mailing list