From c305611b9caa36f63109fde811251b4ba0a2f865 Mon Sep 17 00:00:00 2001 From: Christoph Stahl Date: Mon, 8 May 2017 11:07:28 +0200 Subject: [PATCH] Download logs, improved output, css fixes for medium screen size --- warp/hook.py | 22 ++++++++++++++++++++-- warp/static/css/app.css | 7 ++++++- warp/static/js/app.js | 2 +- warp/templates/index.html | 5 +++-- warp/views.py | 32 +++++++++++++++++++++++--------- 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/warp/hook.py b/warp/hook.py index dbf86b7..ed540d9 100644 --- a/warp/hook.py +++ b/warp/hook.py @@ -4,6 +4,7 @@ import argparse from threading import Thread, Event from multiprocessing import Queue +from os import fdopen, path from . import argparser_wrapper from . import views @@ -31,7 +32,6 @@ class QueuedOut(io.StringIO): self.seek(0) self.truncate(0) - class FlaskThread(Thread): def __init__(self, port, host): super().__init__() @@ -41,15 +41,29 @@ class FlaskThread(Thread): def run(self): views.app.run(port=self.port, threaded=True, host=self.host) +class Output(): + def __init__(self, queue, restart): + self._queue = queue + self._restart = restart + self.cache = [] + + def get_output(self): + def gen_output(): + while not self._restart.is_set(): + msg_type, line = self._queue.get() + self.cache.append((msg_type, line)) + yield (msg_type, line) + return gen_output() def start_module(name, is_module): views.app.restart.clear() - views.app.name = "" + views.app.name = path.basename(name) views.app.desc = "" views.app.actions = [] views.app.queue = Queue() ioout = QueuedOut("out", views.app.queue) ioerr = QueuedOut("err", views.app.queue) + views.app.output = Output(views.app.queue, views.app.restart) views.app.actionQueue = Queue() # This holds only one Argparser Object views.app.namespaceQueue = Queue() # This hold only one Namespace Object @@ -65,6 +79,10 @@ def start_module(name, is_module): is_module = is_module ) views.app.module_process.start() + views.app.mutex_groups, views.app.actions, name, views.app.desc = views.app.actionQueue.get() + if name: + app.name = name + views.app.module_process.join() ioerr.write("Process stopped ({})\n".format(views.app.module_process.exitcode)) diff --git a/warp/static/css/app.css b/warp/static/css/app.css index 38062d2..c0fa93f 100644 --- a/warp/static/css/app.css +++ b/warp/static/css/app.css @@ -18,6 +18,11 @@ li.action{ position: relative; } +li.subparser { + padding-left: 2px; + padding-right: 2px; +} + #arguments { padding: 0px; } @@ -54,7 +59,7 @@ html, body { } li.action { - padding: 1rem 1rem 1rem 1rem; + padding: 1rem 0; } .unlock-button { diff --git a/warp/static/js/app.js b/warp/static/js/app.js index a542082..f0c08dc 100644 --- a/warp/static/js/app.js +++ b/warp/static/js/app.js @@ -1,5 +1,5 @@ function createSubparserAction(action) { - var column = $("
  • ").addClass("action");//.addClass("column small-12 medium-12") + var column = $("
  • ").addClass("action subparser");//.addClass("column small-12 medium-12") //var card = $("
    ").addClass("card action").appendTo(column); var label = $("
    -
    +
    -
    +
    diff --git a/warp/views.py b/warp/views.py index 6d33f3e..8d45e49 100644 --- a/warp/views.py +++ b/warp/views.py @@ -3,7 +3,10 @@ import signal import os import json import argparse -from flask import Flask, render_template, request, Response, jsonify +from datetime import datetime + +from flask import Flask, render_template, request, Response, \ + jsonify, send_file, make_response # Initialize global variables app = Flask(__name__) @@ -30,10 +33,8 @@ def parse_argument(name, json, action): def fill_namespace(): json = dict(request.form) namespace = argparse.Namespace() - if app.actions == []: - if not app.actionQueue.empty(): - app.mutex_groups, app.actions, app.name, app.desc = app.actionQueue.get() all_actions = app.actions + for group in app.mutex_groups: all_actions.extend(group.actions) @@ -47,9 +48,6 @@ def fill_namespace(): @app.route("/arguments", methods=['GET']) def get_arguments(): - if app.actions == []: - if not app.actionQueue.empty(): - app.mutex_groups, app.actions, app.name, app.desc = app.actionQueue.get() return jsonify({'actions': [a.as_dict() for a in app.actions], 'groups': [g.as_dict() for g in app.mutex_groups]}) @@ -77,16 +75,32 @@ def reload(): app.restart.set() return "OK" +@app.route("/download", methods=['GET']) +def download(): + output = "\n".join([line for msg_type, line in app.output.cache]) + response = make_response(output) + response.headers["Content-Disposition"] = \ + "attachment; filename=%s_%s.log" \ + % (app.name, datetime.now().strftime('%Y%m%d-%H%M%S')) + return response + + @app.route("/output.json", methods=['GET']) def output(): def generate(): yield '{"output":[' - while not app.restart.is_set(): - msg_type, line = app.queue.get() + cache = app.output.cache + for msg_type, line in cache: + yield json.dumps({'type' : msg_type, 'line': line}) + yield ',' + + output = app.output.get_output() + for msg_type, line in output: print("Send ({}): {} (length: {})".format(msg_type, line, len(line)), file=sys.__stdout__) yield json.dumps({'type' : msg_type, 'line': line}) yield ',' yield '\{\}]}' + return Response(generate(), mimetype="application/json")