mirror of
https://github.com/QingdaoU/JudgeServer.git
synced 2024-12-29 14:11:44 +00:00
158 lines
5.4 KiB
Python
158 lines
5.4 KiB
Python
# coding=utf-8
|
|
from __future__ import unicode_literals
|
|
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import shutil
|
|
|
|
import web
|
|
|
|
from compiler import Compiler
|
|
from config import JUDGER_WORKSPACE_BASE, TEST_CASE_DIR
|
|
from exception import TokenVerificationFailed, CompileError, SPJCompileError,JudgeClientError
|
|
from judge_client import JudgeClient
|
|
from utils import server_info, get_token, logger
|
|
|
|
|
|
DEBUG = os.environ.get("judger_debug") == "1"
|
|
|
|
|
|
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)
|
|
os.chmod(self.path, 0777)
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
raise JudgeClientError("failed to create runtime dir")
|
|
return self.path
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
if not DEBUG:
|
|
try:
|
|
shutil.rmtree(self.path)
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
raise JudgeClientError("failed to clean runtime dir")
|
|
|
|
|
|
class JudgeServer(object):
|
|
def pong(self):
|
|
data = server_info()
|
|
data["action"] = "pong"
|
|
return data
|
|
|
|
@property
|
|
def _token(self):
|
|
t = get_token()
|
|
if not t:
|
|
raise TokenVerificationFailed("token not set")
|
|
return hashlib.sha256(t).hexdigest()
|
|
|
|
def judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id,
|
|
spj_version=None, spj_config=None):
|
|
# init
|
|
compile_config = language_config["compile"]
|
|
|
|
with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id)) as submission_dir:
|
|
src_path = os.path.join(submission_dir, compile_config["src_name"])
|
|
|
|
# write source code into file
|
|
with open(src_path, "w") as f:
|
|
f.write(src.encode("utf-8"))
|
|
|
|
# compile source code, return exe file path
|
|
exe_path = Compiler().compile(compile_config=compile_config,
|
|
src_path=src_path,
|
|
output_dir=submission_dir)
|
|
|
|
judge_client = JudgeClient(run_config=language_config["run"],
|
|
exe_path=exe_path,
|
|
max_cpu_time=max_cpu_time,
|
|
max_memory=max_memory,
|
|
test_case_id=str(test_case_id),
|
|
submission_dir=submission_dir,
|
|
spj_version=spj_version,
|
|
spj_config=spj_config)
|
|
run_result = judge_client.run()
|
|
return run_result
|
|
|
|
def compile_spj(self, spj_version, src, spj_compile_config, test_case_id):
|
|
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)
|
|
|
|
spj_src_path = os.path.join(TEST_CASE_DIR, test_case_id, spj_compile_config["src_name"])
|
|
|
|
# if spj source code not found, then write it into file
|
|
if not os.path.exists(spj_src_path):
|
|
with open(spj_src_path, "w") as f:
|
|
f.write(src.encode("utf-8"))
|
|
try:
|
|
Compiler().compile(compile_config=spj_compile_config,
|
|
src_path=spj_src_path,
|
|
output_dir=os.path.join(TEST_CASE_DIR, test_case_id))
|
|
# turn common CompileError into SPJCompileError
|
|
except CompileError as e:
|
|
raise SPJCompileError(e.message)
|
|
return "success"
|
|
|
|
def POST(self):
|
|
token = web.ctx.env.get("HTTP_X_JUDGE_SERVER_TOKEN", None)
|
|
try:
|
|
if token != self._token:
|
|
raise TokenVerificationFailed("invalid token")
|
|
if web.data():
|
|
try:
|
|
data = json.loads(web.data())
|
|
except Exception as e:
|
|
logger.info(web.data())
|
|
return {"ret": "ServerError", "data": "invalid json"}
|
|
else:
|
|
data = {}
|
|
|
|
if web.ctx["path"] == "/judge":
|
|
callback = self.judge
|
|
elif web.ctx["path"] == "/ping":
|
|
callback = self.pong
|
|
elif web.ctx["path"] == "/compile_spj":
|
|
callback = self.compile_spj
|
|
else:
|
|
return json.dumps({"err": "InvalidMethod", "data": None})
|
|
return json.dumps({"err": None, "data": callback(**data)})
|
|
except (CompileError, TokenVerificationFailed, SPJCompileError, JudgeClientError) as e:
|
|
logger.exception(e)
|
|
ret = dict()
|
|
ret["err"] = e.__class__.__name__
|
|
ret["data"] = e.message
|
|
return json.dumps(ret)
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
ret = dict()
|
|
ret["err"] = "JudgeClientError"
|
|
ret["data"] =e.__class__.__name__ + ":" + e.message
|
|
return json.dumps(ret)
|
|
|
|
|
|
urls = (
|
|
"/judge", "JudgeServer",
|
|
"/ping", "JudgeServer",
|
|
"/compile_spj", "JudgeServer"
|
|
)
|
|
|
|
|
|
if DEBUG:
|
|
logger.info("DEBUG=ON")
|
|
|
|
# check token
|
|
JudgeServer()._token
|
|
|
|
app = web.application(urls, globals())
|
|
wsgiapp = app.wsgifunc()
|
|
|
|
# gunicorn -w 4 -b 0.0.0.0:8080 server:wsgiapp
|
|
if __name__ == "__main__":
|
|
app.run() |