Commit 51ae9171 authored by Kento HASEGAWA's avatar Kento HASEGAWA

Merge branch 'comm' into 'master'

Merge comm

See merge request adc2018/adc2018-system!18
parents 3531a1ec ed903e2f
...@@ -52,6 +52,8 @@ def start(): ...@@ -52,6 +52,8 @@ def start():
"resolver": request.form['resolver'] "resolver": request.form['resolver']
} }
print(option['req_id'])
pynqrouter.start_solver(boardstr, qseed, option) pynqrouter.start_solver(boardstr, qseed, option)
# 実行だけ開始する # 実行だけ開始する
......
...@@ -60,8 +60,10 @@ def resolve(): ...@@ -60,8 +60,10 @@ def resolve():
with open(outpath, "r") as fp: with open(outpath, "r") as fp:
resolved = fp.read() resolved = fp.read()
print(data['req_id'])
res = { res = {
'answer': resolved, 'solution': resolved,
'solved': True, 'solved': True,
'solver': data['client'], 'solver': data['client'],
'resolver': client_baseurl, 'resolver': client_baseurl,
......
...@@ -17,6 +17,8 @@ import threading ...@@ -17,6 +17,8 @@ import threading
import time import time
from collections import OrderedDict from collections import OrderedDict
from flask import Flask, render_template, request, g from flask import Flask, render_template, request, g
from gevent import pywsgi, monkey
from geventwebsocket.handler import WebSocketHandler
from queue import Queue from queue import Queue
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver') sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver')
...@@ -25,10 +27,12 @@ import BoardStr ...@@ -25,10 +27,12 @@ import BoardStr
import adcclilib import adcclilib
app = Flask(__name__) app = Flask(__name__)
monkey.patch_all()
app_args = {} app_args = {}
questions = None questions = None
clients = None clients = None
current_seed = 1 current_seed = 1
wsq = None
def load_questions(): def load_questions():
global app_args global app_args
...@@ -58,10 +62,10 @@ def load_questions(): ...@@ -58,10 +62,10 @@ def load_questions():
"path": v, "path": v,
"status": "Not solved", "status": "Not solved",
"answer": "", "answer": "",
"queue": Queue(),
"board_size": board_size, "board_size": board_size,
"line_num": line_num, "line_num": line_num,
"last_req": None, "last_req": None,
"solver": OrderedDict(),
"answers": OrderedDict(), "answers": OrderedDict(),
} }
...@@ -79,7 +83,7 @@ def load_questions(): ...@@ -79,7 +83,7 @@ def load_questions():
with open(v, "r") as fp: with open(v, "r") as fp:
_ans_dat = fp.read() _ans_dat = fp.read()
try: try:
questions[_name]["status"] = "Solved" questions[_name]["status"] = "Saved"
questions[_name]["answer"] = _ans_dat questions[_name]["answer"] = _ans_dat
except KeyError as e: except KeyError as e:
pass pass
...@@ -88,9 +92,14 @@ def update_answer_list(qname): ...@@ -88,9 +92,14 @@ def update_answer_list(qname):
global app_args global app_args
global questions global questions
global clients
questions[qname]['solver'] = OrderedDict()
questions[qname]['answers'] = OrderedDict() questions[qname]['answers'] = OrderedDict()
for c in clients['solver']:
questions[qname]['solver'][c[0]] = "-"
_folder_name = os.path.splitext(qname)[0] _folder_name = os.path.splitext(qname)[0]
_answers_path = "{}/{}".format(app_args['out'], _folder_name) _answers_path = "{}/{}".format(app_args['out'], _folder_name)
if os.path.isdir(_answers_path): if os.path.isdir(_answers_path):
...@@ -98,30 +107,51 @@ def update_answer_list(qname): ...@@ -98,30 +107,51 @@ def update_answer_list(qname):
answer_log_file.sort() answer_log_file.sort()
answer_log_file.reverse() answer_log_file.reverse()
is_solved = False
for v2 in answer_log_file: for v2 in answer_log_file:
json_name = os.path.basename(v2) json_name = os.path.basename(v2)
with open(v2, "r") as fp: with open(v2, "r") as fp:
answer_log = json.load(fp) answer_log = json.load(fp)
questions[qname]['answers'][json_name] = answer_log questions[qname]['answers'][json_name] = answer_log
if answer_log['solved'] == "True":
is_solved = True
if questions[qname]['answer'] == answer_log['answer']: if questions[qname]['answer'] == answer_log['answer']:
questions[qname]['best_json'] = json_name 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"
else:
questions[qname]['solver'][answer_log['solver']] = "DNS"
if is_solved > 0:
questions[qname]['status'] = "Solved"
@app.before_request @app.before_request
def before_request(): def before_request():
global app_args global app_args
g.local_mode = (request.remote_addr == "127.0.0.1") if app_args["force_local_mode"]:
g.local_mode = True
else:
g.local_mode = (request.remote_addr in ["127.0.0.1", "::1"])
@app.route("/post", methods=["POST"]) @app.route("/post", methods=["POST"])
def post(): def post():
global questions global questions
global app_args global app_args
global wsq
_qname = request.form["qname"] _qname = request.form["qname"]
_answer = request.form["answer"] _answer = request.form["solution"]
_client = request.form["client"] _client = request.form["client"]
_req_id = request.form["req_id"]
_is_solved = request.form["solved"]
if "solver" in request.form: if "solver" in request.form:
_solver = request.form["solver"] _solver = request.form["solver"]
...@@ -132,14 +162,18 @@ def post(): ...@@ -132,14 +162,18 @@ def post():
receive_time_str = receive_time.strftime("%Y%m%d%H%M%S") receive_time_str = receive_time.strftime("%Y%m%d%H%M%S")
dat = { dat = {
"req_id": request.form['req_id'], "req_id": _req_id,
"qname": _qname,
"client": _client, "client": _client,
"solver": _solver, "solver": _solver,
"answer": _answer, "answer": _answer,
"cputime": request.form['cputime'], "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,
} }
if _is_solved == "True":
# Create a temporary file to execute "nlcheck.py" # Create a temporary file to execute "nlcheck.py"
tmp_path = "{}/{}".format(app_args['out'], "tmp") tmp_path = "{}/{}".format(app_args['out'], "tmp")
if not os.path.isdir(tmp_path): if not os.path.isdir(tmp_path):
...@@ -160,8 +194,6 @@ def post(): ...@@ -160,8 +194,6 @@ def post():
m = re.match(pattern, nlcheck) m = re.match(pattern, nlcheck)
if m and (m.group(1) == "True"): if m and (m.group(1) == "True"):
dat["nlcheck"] = float(m.group(2)) dat["nlcheck"] = float(m.group(2))
else:
dat["nlcheck"] = -1
save_path = "{}/{}".format(app_args['out'], os.path.splitext(_qname)[0]) save_path = "{}/{}".format(app_args['out'], os.path.splitext(_qname)[0])
if not os.path.isdir(save_path): if not os.path.isdir(save_path):
...@@ -171,6 +203,17 @@ def post(): ...@@ -171,6 +203,17 @@ def post():
save_file_path = "{}/{}".format(save_path, file_name) save_file_path = "{}/{}".format(save_path, file_name)
with open(save_file_path, "w") as fp: with open(save_file_path, "w") as fp:
json.dump(dat, fp, indent=4) json.dump(dat, fp, indent=4)
else:
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)
wsq.put(dat)
res = {"status": "OK"} res = {"status": "OK"}
...@@ -317,6 +360,7 @@ def save_best_solution(): ...@@ -317,6 +360,7 @@ def save_best_solution():
with open(out_file_path, 'w') as fp: with open(out_file_path, 'w') as fp:
fp.write(questions[qname]['answers'][_best_json]['answer']) fp.write(questions[qname]['answers'][_best_json]['answer'])
questions[_name]["status"] = "Saved"
questions[qname]['best_json'] = _best_json questions[qname]['best_json'] = _best_json
res = {"status": "OK"} res = {"status": "OK"}
...@@ -547,7 +591,23 @@ def question_status(): ...@@ -547,7 +591,23 @@ def question_status():
update_answer_list(qname) update_answer_list(qname)
qdata = questions[qname] qdata = questions[qname]
return render_template("part_question_status.html", qname=qname, qdata=qdata, solvers=clients["solver"]) return render_template("part_question_status.html", qname=qname, qdata=qdata, solvers=clients["solver"], localmode=g.local_mode)
@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("/") @app.route("/")
def index(): def index():
...@@ -567,9 +627,7 @@ def init_system(): ...@@ -567,9 +627,7 @@ def init_system():
global app_args global app_args
global questions global questions
global clients global clients
global wsq
if questions is None:
load_questions()
if clients is None: if clients is None:
...@@ -592,6 +650,12 @@ def init_system(): ...@@ -592,6 +650,12 @@ def init_system():
"resolver": resolver "resolver": resolver
} }
if questions is None:
load_questions()
if wsq is None:
wsq = Queue()
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="PYNQ control panel.") parser = argparse.ArgumentParser(description="PYNQ control panel.")
...@@ -599,6 +663,7 @@ if __name__ == "__main__": ...@@ -599,6 +663,7 @@ if __name__ == "__main__":
parser.add_argument("-a", "--adccli", action="store", type=str, default="./adccli.json", help="Path to the ADCCLI configuration json file.") parser.add_argument("-a", "--adccli", action="store", type=str, default="./adccli.json", help="Path to the ADCCLI configuration json file.")
parser.add_argument("-q", "--question", action="store", type=str, default="./problems", help="Path to the question folder.") parser.add_argument("-q", "--question", action="store", type=str, default="./problems", help="Path to the question folder.")
parser.add_argument("-o", "--out", action="store", type=str, default="./answers", help="Path to the output folder.") parser.add_argument("-o", "--out", action="store", type=str, default="./answers", help="Path to the output folder.")
parser.add_argument("--force-local-mode", action="store_true", default=False, help="Apply local mode view to all clients.")
parser.add_argument("--debug", action="store_true", default=False, help="Debug mode.") parser.add_argument("--debug", action="store_true", default=False, help="Debug mode.")
args = vars(parser.parse_args()) args = vars(parser.parse_args())
app_args = args app_args = args
...@@ -607,5 +672,9 @@ if __name__ == "__main__": ...@@ -607,5 +672,9 @@ if __name__ == "__main__":
if args["debug"]: if args["debug"]:
app.debug = True 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()
html, body{ html, body{
/*width: 800px;*/
/*height: 500px;*/
font-size: 11px; font-size: 11px;
overflow: hidden; overflow: hidden;
} }
...@@ -10,7 +8,7 @@ body{ ...@@ -10,7 +8,7 @@ body{
/* scrollbar settings */ /* scrollbar settings */
::-webkit-scrollbar{ ::-webkit-scrollbar{
width: 25px; width: 20px;
border: 1px solid rgba(0, 0, 50, .2); border: 1px solid rgba(0, 0, 50, .2);
} }
::-webkit-scrollbar-thumb{ ::-webkit-scrollbar-thumb{
...@@ -18,7 +16,7 @@ body{ ...@@ -18,7 +16,7 @@ body{
} }
#question-table-wrapper{ #question-table-wrapper{
height: 300px; height: calc(100vh - 50px);
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
} }
...@@ -45,7 +43,7 @@ body{ ...@@ -45,7 +43,7 @@ body{
} }
#client-control-pane{ #client-control-pane{
height: 330px; height: calc(100vh - 20px);
overflow-y: scroll; overflow-y: scroll;
} }
......
...@@ -63,7 +63,6 @@ var PynqManager = (function(){ ...@@ -63,7 +63,6 @@ var PynqManager = (function(){
}).done(function(res){ }).done(function(res){
var answer = res; var answer = res;
$("#solving-question-status").text(answer["status"]); $("#solving-question-status").text(answer["status"]);
$("#solved-client").text(answer["answer"]["client"]);
if (after !== null){ if (after !== null){
after(); after();
...@@ -110,6 +109,7 @@ $(function(){ ...@@ -110,6 +109,7 @@ $(function(){
var pynqClients = {} var pynqClients = {}
var pm = null; var pm = null;
var last_req = 0;
var refresh_question_table = function(){ var refresh_question_table = function(){
$.ajax({ $.ajax({
...@@ -179,7 +179,7 @@ $(function(){ ...@@ -179,7 +179,7 @@ $(function(){
$("#adccli-status").text("ログアウト"); $("#adccli-status").text("ログアウト");
}); });
pm.getStatus(); if(pm) pm.getStatus();
}); });
} }
...@@ -195,7 +195,7 @@ $(function(){ ...@@ -195,7 +195,7 @@ $(function(){
$("#client-control-pane").find(".start-button").eq(0).click(function(){ $("#client-control-pane").find(".start-button").eq(0).click(function(){
var qname = $(this).data("qname"); 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(){ $("#client-control-pane").find(".stop-button").eq(0).click(function(){
pm.sendStop(); pm.sendStop();
...@@ -241,6 +241,19 @@ $(function(){ ...@@ -241,6 +241,19 @@ $(function(){
} }
}).trigger('hashchange'); }).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(); refresh_question_table();
$.ajax({ $.ajax({
...@@ -250,6 +263,10 @@ $(function(){ ...@@ -250,6 +263,10 @@ $(function(){
}).done(function(d){ }).done(function(d){
pynqClients = d; pynqClients = d;
pm = PynqManager(pynqClients); pm = PynqManager(pynqClients);
if(location.hash.replace("#", "") == ""){
pm.getStatus();
}
}); });
}); });
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
<div id="wrapper"> <div id="wrapper">
<div id="contorol-panel-wrapper" class="container-fluid"> <div id="control-panel-wrapper" class="container-fluid">
<div class="row"> <div id="control-panel-row" class="row">
<div class="col-5" id="question-control-pane"> <div class="col-5" id="question-control-pane">
<h3>問題一覧</h3>&nbsp; <h3>問題一覧</h3>&nbsp;
<span><a href="/#" id="view-server-status-button">システム状況</a></span> <span><a href="/#" id="view-server-status-button">システム状況</a></span>
......
...@@ -9,12 +9,13 @@ Viewer Mode ...@@ -9,12 +9,13 @@ Viewer Mode
{% endif %} {% endif %}
</p> </p>
{% if local_mode %}
<h4>自動運営システム</h4> <h4>自動運営システム</h4>
<button type="button" class="btn btn-primary" id="adccli-login-button">Login</button> <button type="button" class="btn btn-primary" id="adccli-login-button">Login</button>
<button type="button" class="btn btn-light" id="adccli-logout-button">Logout</button> <button type="button" class="btn btn-light" id="adccli-logout-button">Logout</button>
<span id="adccli-status"></span>
<br />
<button type="button" class="btn btn-info" id="adccli-get-all-q">問題DL</button> <button type="button" class="btn btn-info" id="adccli-get-all-q">問題DL</button>
<span id="adccli-status"></span>
{% endif %}
<h4>クライアント</h4> <h4>クライアント</h4>
<table class="table table-bordered" id="clients-table"> <table class="table table-bordered" id="clients-table">
......
<div class="row"> <div class="row">
<div class="col-4"> <div class="col-4">
<h3> 【{{qname}}】</h3> <h3> 【{{qname}}】</h3>
{% if localmode %}
<p> <p>
<button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{qname}}">Start</button> <button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{qname}}">Start</button>
<button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button> <button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button>
...@@ -9,6 +10,9 @@ ...@@ -9,6 +10,9 @@
<button class="btn btn-info btn-lg save-button" type="button" data-qname="{{qname}}">Save</button> <button class="btn btn-info btn-lg save-button" type="button" data-qname="{{qname}}">Save</button>
<button class="btn btn-success btn-lg submit-button" type="button" data-qname="{{qname}}">Up</button> <button class="btn btn-success btn-lg submit-button" type="button" data-qname="{{qname}}">Up</button>
</p> </p>
{% else %}
[View Only]
{% endif %}
</div> </div>
<div class="col-8"> <div class="col-8">
<p>処理結果</p> <p>処理結果</p>
...@@ -28,7 +32,7 @@ ...@@ -28,7 +32,7 @@
&nbsp;({{c[2]}}) &nbsp;({{c[2]}})
{% endif %} {% endif %}
</td> </td>
<td></td> <td>{{qdata.solver[c[0]]}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
...@@ -44,20 +48,22 @@ ...@@ -44,20 +48,22 @@
<th>Score</th> <th>Score</th>
</tr> </tr>
{% for k, v in qdata.answers.items() %} {% for k, v in qdata.answers.items() %}
{% if qdata.best_json == k %} {% if (qdata.best_json == k) and (v.answer != "") %}
<tr class="answer-detail-row submit-answer" data-json="{{k}}" data-qname="{{qname}}"> <tr class="answer-detail-row submit-answer" data-json="{{k}}" data-qname="{{qname}}">
{% else %} {% else %}
<tr class="answer-detail-row" data-json="{{k}}" data-qname="{{qname}}"> <tr class="answer-detail-row" data-json="{{k}}" data-qname="{{qname}}">
{% endif %} {% endif %}
<td>{{v.timestamp}}</td> <td>{{v.timestamp}}</td>
<td>{{v.solver}}</td> <td>{{v.solver}}</td>
<td>{{v.nlcheck}}</td> <td>
{% if v.nlcheck == -1 %}
Not solved
{% else %}
{{v.nlcheck}}
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
<p>状況:<span id="solving-question-status">{{qdata.status}}</span></p>
<h4>結果</h4>
<p>クライアント:<span id="solved-client">{{qdata.answer.client}}</span></p>
<pre id="solved-result">{{qdata.answer.answer}}</pre>
...@@ -99,7 +99,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()): ...@@ -99,7 +99,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
solver_thread.stopped() solver_thread.stopped()
solver_thread = None solver_thread = None
if "host" in option: if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res) r = requests.post("http://{}/post".format(option['host']), data=res)
return res return res
# ボード文字列から X, Y, Z を読んでくる # ボード文字列から X, Y, Z を読んでくる
...@@ -149,7 +149,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()): ...@@ -149,7 +149,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
solver_thread.stopped() solver_thread.stopped()
solver_thread = None solver_thread = None
if "host" in option: if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res) r = requests.post("http://{}/post".format(option['host']), data=res)
return res return res
# 完了の確認 # 完了の確認
...@@ -168,7 +168,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()): ...@@ -168,7 +168,7 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
mmio_led.write(0, 0) mmio_led.write(0, 0)
sys.stderr.write('Cannot solve it!\n') sys.stderr.write('Cannot solve it!\n')
if "host" in option: if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res) r = requests.post("http://{}/post".format(option['host']), data=res)
solver_thread = None solver_thread = None
return res return res
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment