commit 44478df607a7a5b3e3fbdb129651ad4c9a2b2729 Author: Arturo Filastò arturo@filasto.net Date: Fri Oct 7 20:13:38 2016 +0200
When generating a summary do so inside of a separate thread to avoid blocking the reactor thread --- ooni/measurements.py | 15 ++++++++++++--- ooni/ui/web/server.py | 6 ++++-- 2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/ooni/measurements.py b/ooni/measurements.py index 422fc55..46a447e 100644 --- a/ooni/measurements.py +++ b/ooni/measurements.py @@ -1,5 +1,7 @@ import json
+from twisted.internet import defer +from twisted.internet.threads import deferToThread from twisted.python.filepath import FilePath from ooni.utils import log, is_process_running from ooni.utils.files import directory_usage @@ -56,6 +58,7 @@ def generate_summary(input_file, output_file):
with open(output_file, "w") as fw: json.dump(results, fw) + return results
class MeasurementNotFound(Exception): pass @@ -103,21 +106,27 @@ def get_measurement(measurement_id, compute_size=False):
def get_summary(measurement_id): + """ + Returns a deferred that will fire with the content of the summary + or will errback with MeasurementInProgress if the measurement has not + yet finished running. + """ measurement_path = FilePath(config.measurements_directory) measurement = measurement_path.child(measurement_id)
if measurement.child("measurements.njson.progress").exists(): - raise MeasurementInProgress + return defer.fail(MeasurementInProgress)
summary = measurement.child("summary.json") if not summary.exists(): - generate_summary( + return deferToThread( + generate_summary, measurement.child("measurements.njson").path, summary.path )
with summary.open("r") as f: - return json.load(f) + return defer.succeed(json.load(f))
def list_measurements(compute_size=False): diff --git a/ooni/ui/web/server.py b/ooni/ui/web/server.py index 385bf18..fa35af0 100644 --- a/ooni/ui/web/server.py +++ b/ooni/ui/web/server.py @@ -527,7 +527,9 @@ class WebUIAPI(object): @app.route('/api/measurement/string:measurement_id', methods=["GET"]) @xsrf_protect(check=False) @requires_true(attrs=['_is_initialized']) + @defer.inlineCallbacks def api_measurement_summary(self, request, measurement_id): + log.warn("SUMMARY") try: measurement = get_measurement(measurement_id) except InsecurePath: @@ -540,8 +542,8 @@ class WebUIAPI(object): if measurement['completed'] is False: raise WebUIError(400, "measurement in progress")
- summary = get_summary(measurement_id) - return self.render_json(summary, request) + summary = yield get_summary(measurement_id) + defer.returnValue(self.render_json(summary, request))
@app.route('/api/measurement/string:measurement_id', methods=["DELETE"]) @xsrf_protect(check=True)