JudgeServer/server/server.py

145 lines
5.5 KiB
Python
Raw Normal View History

2016-09-02 12:04:29 +00:00
import json
import os
2016-09-11 02:35:08 +00:00
import shutil
2016-10-07 05:32:30 +00:00
import uuid
2016-09-02 12:04:29 +00:00
2018-03-18 00:19:44 +00:00
from flask import Flask, request, Response
2016-09-02 12:04:29 +00:00
from compiler import Compiler
2016-11-17 12:08:27 +00:00
from config import JUDGER_WORKSPACE_BASE, SPJ_SRC_DIR, SPJ_EXE_DIR
2018-03-18 00:19:44 +00:00
from exception import TokenVerificationFailed, CompileError, SPJCompileError, JudgeClientError
2016-09-28 12:43:46 +00:00
from judge_client import JudgeClient
2016-11-17 12:08:27 +00:00
from utils import server_info, logger, token
2016-10-03 08:13:46 +00:00
2018-03-18 00:19:44 +00:00
app = Flask(__name__)
2016-09-28 12:43:46 +00:00
DEBUG = os.environ.get("judger_debug") == "1"
2018-03-18 00:19:44 +00:00
app.debug = DEBUG
2016-09-28 12:43:46 +00:00
2016-09-02 12:04:29 +00:00
class InitSubmissionEnv(object):
def __init__(self, judger_workspace, submission_id):
self.path = os.path.join(judger_workspace, submission_id)
def __enter__(self):
try:
os.mkdir(self.path)
2018-03-18 00:19:44 +00:00
os.chmod(self.path, 0o777)
except Exception as e:
2016-10-04 05:24:50 +00:00
logger.exception(e)
raise JudgeClientError("failed to create runtime dir")
2016-09-02 12:04:29 +00:00
return self.path
def __exit__(self, exc_type, exc_val, exc_tb):
2016-09-28 12:43:46 +00:00
if not DEBUG:
try:
shutil.rmtree(self.path)
except Exception as e:
2016-10-04 05:24:50 +00:00
logger.exception(e)
raise JudgeClientError("failed to clean runtime dir")
2016-09-02 12:04:29 +00:00
2018-03-18 00:19:44 +00:00
class JudgeServer:
@classmethod
def ping(cls):
2016-10-03 08:13:46 +00:00
data = server_info()
data["action"] = "pong"
return data
2016-09-02 12:04:29 +00:00
2018-03-18 00:19:44 +00:00
@classmethod
def judge(cls, language_config, src, max_cpu_time, max_memory, test_case_id,
spj_version=None, spj_config=None, spj_compile_config=None, spj_src=None, output=False):
2016-09-02 12:04:29 +00:00
# init
2016-10-09 12:05:04 +00:00
compile_config = language_config.get("compile")
run_config = language_config["run"]
2018-03-18 00:19:44 +00:00
submission_id = uuid.uuid4().hex
2016-09-02 12:04:29 +00:00
2017-11-25 11:27:08 +00:00
if spj_version and spj_config:
spj_exe_path = os.path.join(SPJ_EXE_DIR, spj_config["exe_name"].format(spj_version=spj_version))
# spj src has not been compiled
if not os.path.isfile(spj_exe_path):
logger.warning("%s does not exists, spj src will be recompiled")
2018-03-18 00:19:44 +00:00
cls.compile_spj(spj_version=spj_version, src=spj_src,
spj_compile_config=spj_compile_config)
2016-10-09 14:16:30 +00:00
2016-10-01 18:05:16 +00:00
with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id)) as submission_dir:
2016-10-09 12:05:04 +00:00
if compile_config:
src_path = os.path.join(submission_dir, compile_config["src_name"])
# write source code into file
2018-03-25 23:07:36 +00:00
with open(src_path, "w", encoding="utf-8") as f:
2018-03-18 00:19:44 +00:00
f.write(src)
2016-10-09 12:05:04 +00:00
# compile source code, return exe file path
exe_path = Compiler().compile(compile_config=compile_config,
src_path=src_path,
output_dir=submission_dir)
else:
2016-10-09 14:16:30 +00:00
exe_path = os.path.join(submission_dir, run_config["exe_name"])
2018-03-25 23:07:36 +00:00
with open(exe_path, "w", encoding="utf-8") as f:
2018-03-18 00:19:44 +00:00
f.write(src)
2016-09-02 12:04:29 +00:00
2016-09-11 02:35:08 +00:00
judge_client = JudgeClient(run_config=language_config["run"],
exe_path=exe_path,
max_cpu_time=max_cpu_time,
max_memory=max_memory,
2016-10-01 18:05:16 +00:00
test_case_id=str(test_case_id),
submission_dir=submission_dir,
2016-10-06 03:43:49 +00:00
spj_version=spj_version,
spj_config=spj_config,
output=output)
run_result = judge_client.run()
return run_result
2016-09-02 12:04:29 +00:00
2018-03-18 00:19:44 +00:00
@classmethod
def compile_spj(cls, spj_version, src, spj_compile_config):
2016-09-28 13:58:00 +00:00
spj_compile_config["src_name"] = spj_compile_config["src_name"].format(spj_version=spj_version)
spj_compile_config["exe_name"] = spj_compile_config["exe_name"].format(spj_version=spj_version)
2016-09-28 12:43:46 +00:00
2016-10-09 14:16:30 +00:00
spj_src_path = os.path.join(SPJ_SRC_DIR, spj_compile_config["src_name"])
2016-09-28 12:43:46 +00:00
# if spj source code not found, then write it into file
if not os.path.exists(spj_src_path):
2018-03-25 23:07:36 +00:00
with open(spj_src_path, "w", encoding="utf-8") as f:
2018-03-18 00:19:44 +00:00
f.write(src)
2016-09-28 12:43:46 +00:00
try:
Compiler().compile(compile_config=spj_compile_config,
src_path=spj_src_path,
2016-10-09 14:16:30 +00:00
output_dir=SPJ_EXE_DIR)
2016-09-28 12:43:46 +00:00
# turn common CompileError into SPJCompileError
except CompileError as e:
raise SPJCompileError(e.message)
return "success"
2018-03-18 00:19:44 +00:00
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=["POST"])
def server(path):
if path in ("judge", "ping", "compile_spj"):
_token = request.headers.get("X-Judge-Server-Token")
try:
2016-10-27 10:38:04 +00:00
if _token != token:
raise TokenVerificationFailed("invalid token")
2018-03-18 00:19:44 +00:00
try:
data = request.json
except Exception:
data = {}
2018-03-18 00:19:44 +00:00
ret = {"err": None, "data": getattr(JudgeServer, path)(**data)}
2016-10-04 05:03:54 +00:00
except (CompileError, TokenVerificationFailed, SPJCompileError, JudgeClientError) as e:
2016-10-04 05:24:50 +00:00
logger.exception(e)
2018-03-18 00:19:44 +00:00
ret = {"err": e.__class__.__name__, "data": e.message}
2016-10-04 05:03:54 +00:00
except Exception as e:
2016-10-04 05:24:50 +00:00
logger.exception(e)
2018-03-18 00:19:44 +00:00
ret = {"err": "JudgeClientError", "data": e.__class__.__name__ + " :" + str(e)}
else:
ret = {"err": "InvalidRequest", "data": "404"}
return Response(json.dumps(ret), mimetype='application/json')
2016-09-02 12:04:29 +00:00
2016-09-28 05:38:12 +00:00
if DEBUG:
2016-10-04 05:24:50 +00:00
logger.info("DEBUG=ON")
2018-03-18 00:19:44 +00:00
# gunicorn -w 4 -b 0.0.0.0:8080 server:app
if __name__ == "__main__":
2018-03-18 00:19:44 +00:00
app.run(debug=DEBUG)