diff --git a/comm/server/main.py b/comm/server/main.py index 68157a4bdcef71640336aba841d9c5378f451665..274b61f16819c1b71f54435d811c04842ca49609 100644 --- a/comm/server/main.py +++ b/comm/server/main.py @@ -17,6 +17,8 @@ import threading import time from collections import OrderedDict from flask import Flask, render_template, request, g +from gevent import pywsgi, monkey +from geventwebsocket.handler import WebSocketHandler from queue import Queue sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver') @@ -25,10 +27,12 @@ import BoardStr import adcclilib app = Flask(__name__) +monkey.patch_all() app_args = {} questions = None clients = None current_seed = 1 +wsq = None def load_questions(): global app_args @@ -58,10 +62,10 @@ def load_questions(): "path": v, "status": "Not solved", "answer": "", - "queue": Queue(), "board_size": board_size, "line_num": line_num, "last_req": None, + "solver": OrderedDict(), "answers": OrderedDict(), } @@ -79,7 +83,7 @@ def load_questions(): with open(v, "r") as fp: _ans_dat = fp.read() try: - questions[_name]["status"] = "Solved" + questions[_name]["status"] = "Saved" questions[_name]["answer"] = _ans_dat except KeyError as e: pass @@ -88,9 +92,14 @@ def update_answer_list(qname): global app_args global questions + global clients + questions[qname]['solver'] = OrderedDict() questions[qname]['answers'] = OrderedDict() + for c in clients['solver']: + questions[qname]['solver'][c[0]] = "-" + _folder_name = os.path.splitext(qname)[0] _answers_path = "{}/{}".format(app_args['out'], _folder_name) if os.path.isdir(_answers_path): @@ -98,6 +107,8 @@ def update_answer_list(qname): answer_log_file.sort() answer_log_file.reverse() + is_solved = False + for v2 in answer_log_file: json_name = os.path.basename(v2) with open(v2, "r") as fp: @@ -107,6 +118,17 @@ def update_answer_list(qname): if questions[qname]['answer'] == answer_log['answer']: questions[qname]['best_json'] = json_name + if (questions[qname]['last_req'] == float(answer_log['req_id'])): + if answer_log['solver'] in questions[qname]['solver']: + if answer_log['solved'] == "True": + questions[qname]['solver'][answer_log['solver']] = "Solved" + is_solved = True + else: + questions[qname]['solver'][answer_log['solver']] = "DNS" + + if is_solved > 0: + questions[qname]['status'] = "Solved" + @app.before_request def before_request(): global app_args @@ -118,10 +140,13 @@ def post(): global questions global app_args + global wsq _qname = request.form["qname"] - _answer = request.form["answer"] + _answer = request.form["solution"] _client = request.form["client"] + _req_id = request.form["req_id"] + _is_solved = request.form["solved"] if "solver" in request.form: _solver = request.form["solver"] @@ -132,45 +157,58 @@ def post(): receive_time_str = receive_time.strftime("%Y%m%d%H%M%S") dat = { - "req_id": request.form['req_id'], + "req_id": _req_id, + "qname": _qname, "client": _client, "solver": _solver, "answer": _answer, "cputime": request.form['cputime'], - "timestamp": receive_time.strftime("%Y/%m/%d %H:%M:%S") + "timestamp": receive_time.strftime("%Y/%m/%d %H:%M:%S"), + "nlcheck": -1, + "solved": _is_solved, } - # Create a temporary file to execute "nlcheck.py" - tmp_path = "{}/{}".format(app_args['out'], "tmp") - if not os.path.isdir(tmp_path): - os.makedirs(tmp_path) - tmp_file_name = "{}-{}.tmp".format(receive_time_str, _client.replace(":", ".")) - tmp_file_path = "{}/{}".format(tmp_path, tmp_file_name) - with open(tmp_file_path, "w") as fp: - fp.write(_answer) - probpath = "{}/{}".format(app_args["question"], _qname) - - # Format check - cmd = "/usr/bin/python /home/pi/adc2018/conmgr/adc2018/server/nlcheck.py --input {} --target {}".format(probpath, tmp_file_path) - print("`{}`".format(cmd)) - p = subprocess.run(cmd.strip().split(" "), stdout=subprocess.PIPE) - nlcheck = p.stdout.decode().strip() - - pattern = r"judge += +\[(.+?), ([0-9.]+)\]" - m = re.match(pattern, nlcheck) - if m and (m.group(1) == "True"): - dat["nlcheck"] = float(m.group(2)) + if _is_solved == "True": + # Create a temporary file to execute "nlcheck.py" + tmp_path = "{}/{}".format(app_args['out'], "tmp") + if not os.path.isdir(tmp_path): + os.makedirs(tmp_path) + tmp_file_name = "{}-{}.tmp".format(receive_time_str, _client.replace(":", ".")) + tmp_file_path = "{}/{}".format(tmp_path, tmp_file_name) + with open(tmp_file_path, "w") as fp: + fp.write(_answer) + probpath = "{}/{}".format(app_args["question"], _qname) + + # Format check + cmd = "/usr/bin/python /home/pi/adc2018/conmgr/adc2018/server/nlcheck.py --input {} --target {}".format(probpath, tmp_file_path) + print("`{}`".format(cmd)) + p = subprocess.run(cmd.strip().split(" "), stdout=subprocess.PIPE) + nlcheck = p.stdout.decode().strip() + + pattern = r"judge += +\[(.+?), ([0-9.]+)\]" + m = re.match(pattern, nlcheck) + if m and (m.group(1) == "True"): + dat["nlcheck"] = float(m.group(2)) + + save_path = "{}/{}".format(app_args['out'], os.path.splitext(_qname)[0]) + if not os.path.isdir(save_path): + os.makedirs(save_path) + + file_name = "{}-{}.json".format(receive_time_str, _solver.replace(":", ".")) + save_file_path = "{}/{}".format(save_path, file_name) + with open(save_file_path, "w") as fp: + json.dump(dat, fp, indent=4) else: - dat["nlcheck"] = -1 + save_path = "{}/{}".format(app_args['out'], os.path.splitext(_qname)[0]) + if not os.path.isdir(save_path): + os.makedirs(save_path) - save_path = "{}/{}".format(app_args['out'], os.path.splitext(_qname)[0]) - if not os.path.isdir(save_path): - os.makedirs(save_path) + file_name = "{}-{}.json".format(receive_time_str, _solver.replace(":", ".")) + save_file_path = "{}/{}".format(save_path, file_name) + with open(save_file_path, "w") as fp: + json.dump(dat, fp, indent=4) - file_name = "{}-{}.json".format(receive_time_str, _solver.replace(":", ".")) - save_file_path = "{}/{}".format(save_path, file_name) - with open(save_file_path, "w") as fp: - json.dump(dat, fp, indent=4) + wsq.put(dat) res = {"status": "OK"} @@ -317,6 +355,7 @@ def save_best_solution(): with open(out_file_path, 'w') as fp: fp.write(questions[qname]['answers'][_best_json]['answer']) + questions[_name]["status"] = "Saved" questions[qname]['best_json'] = _best_json res = {"status": "OK"} @@ -549,6 +588,22 @@ def question_status(): return render_template("part_question_status.html", qname=qname, qdata=qdata, solvers=clients["solver"]) +@app.route('/ws') +def ws(): + global wsq + + if request.environ.get('wsgi.websocket'): + ws = request.environ['wsgi.websocket'] + + while True: + if wsq is None: + time.sleep(1) + continue + else: + data = wsq.get() + str_data = json.dumps(data) + ws.send(str_data) + @app.route("/") def index(): @@ -567,9 +622,7 @@ def init_system(): global app_args global questions global clients - - if questions is None: - load_questions() + global wsq if clients is None: @@ -591,6 +644,12 @@ def init_system(): "solver": solver, "resolver": resolver } + + if questions is None: + load_questions() + + if wsq is None: + wsq = Queue() if __name__ == "__main__": @@ -607,5 +666,9 @@ if __name__ == "__main__": if args["debug"]: app.debug = True - app.run(host='0.0.0.0', threaded=True) + + app.threaded = True + # app.run(host='0.0.0.0', threaded=True) + server = pywsgi.WSGIServer(("", 5000), app, handler_class=WebSocketHandler) + server.serve_forever() diff --git a/comm/server/static/js/pynq-manager.js b/comm/server/static/js/pynq-manager.js index 995d93ca348f7431e90838ad183f351b16e38e39..8361e2a63018fe3ae98098683f7ccea2dcfee601 100644 --- a/comm/server/static/js/pynq-manager.js +++ b/comm/server/static/js/pynq-manager.js @@ -63,7 +63,6 @@ var PynqManager = (function(){ }).done(function(res){ var answer = res; $("#solving-question-status").text(answer["status"]); - $("#solved-client").text(answer["answer"]["client"]); if (after !== null){ after(); @@ -110,6 +109,7 @@ $(function(){ var pynqClients = {} var pm = null; + var last_req = 0; var refresh_question_table = function(){ $.ajax({ @@ -179,7 +179,7 @@ $(function(){ $("#adccli-status").text("ログアウト"); }); - pm.getStatus(); + if(pm) pm.getStatus(); }); } @@ -195,7 +195,7 @@ $(function(){ $("#client-control-pane").find(".start-button").eq(0).click(function(){ var qname = $(this).data("qname"); - pm.sendQuestion(qname, after=refresh_question_table); + pm.sendQuestion(qname); }); $("#client-control-pane").find(".stop-button").eq(0).click(function(){ pm.sendStop(); @@ -241,6 +241,19 @@ $(function(){ } }).trigger('hashchange'); + var ws = new WebSocket("ws://" + location.host + "/ws"); + ws.onmessage = function(e){ + var recv = JSON.parse(e.data.replace(/\n/g, "\\n")); + + console.log(recv); + + var hash = location.hash.replace("#", ""); + if(hash == recv['qname']){ + show_question_status(hash); + } + refresh_question_table(); + }; + refresh_question_table(); $.ajax({ @@ -250,6 +263,10 @@ $(function(){ }).done(function(d){ pynqClients = d; pm = PynqManager(pynqClients); + + if(location.hash.replace("#", "") == ""){ + pm.getStatus(); + } }); }); diff --git a/comm/server/templates/part_question_status.html b/comm/server/templates/part_question_status.html index a6f634cd7df0708d1510b6629e52078ecfc9b7f8..997194f385e4ae1742d98838e35dfbe722e325b8 100644 --- a/comm/server/templates/part_question_status.html +++ b/comm/server/templates/part_question_status.html @@ -28,7 +28,7 @@  ({{c[2]}}) {% endif %} - + {{qdata.solver[c[0]]}} {% endfor %}