Download logs, improved output, css fixes for medium screen size

This commit is contained in:
Christoph Stahl 2017-05-08 11:07:28 +02:00
parent 2b45e00347
commit c305611b9c
5 changed files with 53 additions and 15 deletions

View file

@ -4,6 +4,7 @@ import argparse
from threading import Thread, Event from threading import Thread, Event
from multiprocessing import Queue from multiprocessing import Queue
from os import fdopen, path
from . import argparser_wrapper from . import argparser_wrapper
from . import views from . import views
@ -31,7 +32,6 @@ class QueuedOut(io.StringIO):
self.seek(0) self.seek(0)
self.truncate(0) self.truncate(0)
class FlaskThread(Thread): class FlaskThread(Thread):
def __init__(self, port, host): def __init__(self, port, host):
super().__init__() super().__init__()
@ -41,15 +41,29 @@ class FlaskThread(Thread):
def run(self): def run(self):
views.app.run(port=self.port, threaded=True, host=self.host) 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): def start_module(name, is_module):
views.app.restart.clear() views.app.restart.clear()
views.app.name = "" views.app.name = path.basename(name)
views.app.desc = "" views.app.desc = ""
views.app.actions = [] views.app.actions = []
views.app.queue = Queue() views.app.queue = Queue()
ioout = QueuedOut("out", views.app.queue) ioout = QueuedOut("out", views.app.queue)
ioerr = QueuedOut("err", 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.actionQueue = Queue() # This holds only one Argparser Object
views.app.namespaceQueue = Queue() # This hold only one Namespace 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 is_module = is_module
) )
views.app.module_process.start() 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() views.app.module_process.join()
ioerr.write("Process stopped ({})\n".format(views.app.module_process.exitcode)) ioerr.write("Process stopped ({})\n".format(views.app.module_process.exitcode))

View file

@ -18,6 +18,11 @@ li.action{
position: relative; position: relative;
} }
li.subparser {
padding-left: 2px;
padding-right: 2px;
}
#arguments { #arguments {
padding: 0px; padding: 0px;
} }
@ -54,7 +59,7 @@ html, body {
} }
li.action { li.action {
padding: 1rem 1rem 1rem 1rem; padding: 1rem 0;
} }
.unlock-button { .unlock-button {

View file

@ -1,5 +1,5 @@
function createSubparserAction(action) { function createSubparserAction(action) {
var column = $("<li/>").addClass("action");//.addClass("column small-12 medium-12") var column = $("<li/>").addClass("action subparser");//.addClass("column small-12 medium-12")
//var card = $("<div/>").addClass("card action").appendTo(column); //var card = $("<div/>").addClass("card action").appendTo(column);
var label = $("<label/>", {for: action['uuid']}).appendTo(column); var label = $("<label/>", {for: action['uuid']}).appendTo(column);
var center = $("<center/>").appendTo(label); var center = $("<center/>").appendTo(label);

View file

@ -24,15 +24,16 @@
<button type="button" style="display: none;" class="button secondary" id="resumeButton" onclick="resumeProcess()"> <i class="fi-play"></i> </button> <button type="button" style="display: none;" class="button secondary" id="resumeButton" onclick="resumeProcess()"> <i class="fi-play"></i> </button>
<button type="button" class="button alert disabled" disabled id="stopButton" onclick="stopProcess()"> <i class="fi-stop"></i> </button> <button type="button" class="button alert disabled" disabled id="stopButton" onclick="stopProcess()"> <i class="fi-stop"></i> </button>
<button type="button" class="button disabled" disabled id="reloadButton" onclick="reloadProcess()"> <i class="fi-refresh"></i> </button> <button type="button" class="button disabled" disabled id="reloadButton" onclick="reloadProcess()"> <i class="fi-refresh"></i> </button>
<button type="button" class="button" onclick="window.open('/download')"> <i class="fi-download"></i> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="columns large-3 medium-4 small-12" id="arguments"> <div class="columns large-3 medium-5 small-12" id="arguments">
<ul id="actions" class="vertical menu"> <ul id="actions" class="vertical menu">
</ul> </ul>
</div> </div>
<div class="columns large-9 medium-8 small-12" id="output_wrap"> <div class="columns large-9 medium-7 small-12" id="output_wrap">
<div id="output"></div> <div id="output"></div>
</div> </div>
</div> </div>

View file

@ -3,7 +3,10 @@ import signal
import os import os
import json import json
import argparse 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 # Initialize global variables
app = Flask(__name__) app = Flask(__name__)
@ -30,10 +33,8 @@ def parse_argument(name, json, action):
def fill_namespace(): def fill_namespace():
json = dict(request.form) json = dict(request.form)
namespace = argparse.Namespace() 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 all_actions = app.actions
for group in app.mutex_groups: for group in app.mutex_groups:
all_actions.extend(group.actions) all_actions.extend(group.actions)
@ -47,9 +48,6 @@ def fill_namespace():
@app.route("/arguments", methods=['GET']) @app.route("/arguments", methods=['GET'])
def get_arguments(): 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], return jsonify({'actions': [a.as_dict() for a in app.actions],
'groups': [g.as_dict() for g in app.mutex_groups]}) 'groups': [g.as_dict() for g in app.mutex_groups]})
@ -77,16 +75,32 @@ def reload():
app.restart.set() app.restart.set()
return "OK" 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']) @app.route("/output.json", methods=['GET'])
def output(): def output():
def generate(): def generate():
yield '{"output":[' yield '{"output":['
while not app.restart.is_set(): cache = app.output.cache
msg_type, line = app.queue.get() 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__) print("Send ({}): {} (length: {})".format(msg_type, line, len(line)), file=sys.__stdout__)
yield json.dumps({'type' : msg_type, 'line': line}) yield json.dumps({'type' : msg_type, 'line': line})
yield ',' yield ','
yield '\{\}]}' yield '\{\}]}'
return Response(generate(), mimetype="application/json") return Response(generate(), mimetype="application/json")