mirror of
https://github.com/QingdaoU/JudgeServer.git
synced 2025-11-04 14:50:01 +08:00
126 lines
4.9 KiB
Python
126 lines
4.9 KiB
Python
# coding=utf-8
|
|
from __future__ import unicode_literals
|
|
|
|
import SocketServer
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import socket
|
|
import shutil
|
|
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
|
|
|
|
import _judger
|
|
import psutil
|
|
|
|
from judge_client import JudgeClient
|
|
from compiler import Compiler
|
|
from config import JUDGER_WORKSPACE_BASE, TEST_CASE_DIR
|
|
from exception import SignatureVerificationFailed, CompileError, SPJCompileError
|
|
from utils import make_signature, check_signature
|
|
|
|
|
|
class InitSubmissionEnv(object):
|
|
def __init__(self, judger_workspace, submission_id):
|
|
self.path = os.path.join(judger_workspace, submission_id)
|
|
|
|
def __enter__(self):
|
|
os.mkdir(self.path)
|
|
os.chmod(self.path, 0777)
|
|
return self.path
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
pass
|
|
# shutil.rmtree(self.path, ignore_errors=True)
|
|
|
|
|
|
class JudgeServer(object):
|
|
def _health_check(self):
|
|
ver = _judger.VERSION
|
|
return {"hostname": socket.gethostname(),
|
|
"cpu": psutil.cpu_percent(),
|
|
"cpu_core": psutil.cpu_count(),
|
|
"memory": psutil.virtual_memory().percent,
|
|
"judger_version": ((ver >> 16) & 0xff, (ver >> 8) & 0xff, ver & 0xff)}
|
|
|
|
def pong(self):
|
|
return make_signature(token=self._token, **self._health_check())
|
|
|
|
@property
|
|
def _token(self):
|
|
t = os.getenv("judger_token")
|
|
if not t:
|
|
raise SignatureVerificationFailed("token not set")
|
|
return hashlib.sha256(t).hexdigest()
|
|
|
|
def judge(self, data, signature, timestamp):
|
|
# check_signature(token=self._token, data=data, signature=signature, timestamp=timestamp)
|
|
ret = {"code": None, "data": None}
|
|
try:
|
|
ret["data"] = self._judge(**json.loads(data))
|
|
except (CompileError, SPJCompileError, SignatureVerificationFailed) as e:
|
|
ret["code"] = e.__class__.__name__
|
|
ret["data"] = e.message
|
|
except Exception as e:
|
|
import traceback
|
|
traceback.print_exc()
|
|
ret["code"] = "ServerError"
|
|
ret["data"] = ": ".join([e.__class__.__name__, e.message])
|
|
return make_signature(token=self._token, **ret)
|
|
|
|
def _judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id):
|
|
# init
|
|
compile_config = language_config["compile"]
|
|
spj_compile_config = language_config.get("spj_compile")
|
|
|
|
with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=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=test_case_id)
|
|
return judge_client.run()
|
|
|
|
if spj_compile_config:
|
|
spj_compile_config["src_name"].format(spj_version=spj_compile_config["version"])
|
|
spj_compile_config["exe_name"].format(spj_version=spj_compile_config["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(spj_compile_config["src"].encode("utf-8"))
|
|
|
|
spj_exe_path = os.path.join(TEST_CASE_DIR, test_case_id, spj_compile_config["exe_name"])
|
|
|
|
# if spj exe file not found, then compile it
|
|
if not os.path.exists(spj_exe_path):
|
|
try:
|
|
spj_exe_path = 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 exe_path
|
|
|
|
|
|
class RPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
|
|
pass
|
|
|
|
|
|
server = RPCServer(('0.0.0.0', 8080), SimpleXMLRPCRequestHandler, allow_none=True)
|
|
server.register_instance(JudgeServer())
|
|
server.serve_forever()
|