Skip to content

Repository files navigation

众衡

本系统是为 ThinkSpirit 实验室的下一代在线评测系统设计的评测机系统的评测端。专职负责运行用户程序并得出判定结论。

系统的详细结构参见协议仓库, 参考的控制端实现在 Heng-Controler

本仓库的 Docker 镜像(语言环境已封装)见 https://hub.docker.com/r/thinkspiritlab/heng-client

部署

推荐关闭宿主机的 Swap。

Docker

Host的内核版本需大于 4.6 (支持cgroup_namespaces)

dnf install --assumeyes yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
dnf install --assumeyes docker-ce
systemctl start docker
systemctl enable docker
docker pull thinkspiritlab/heng-client:latest
docker run --cgroupns private --privileged -it -v $(pwd)/config.toml:/hc/config/config.toml thinkspiritlab/heng-client
# docker run --cgroupns private --privileged -d --restart=always -v $(pwd)/config.toml:/hc/config/config.toml thinkspiritlab/heng-client

CentOS8

cd~
dnf install git -y
git clone https://github.com/ThinkSpiritLab/Heng-Client.git
cd ./Heng-Client
bash prepare-centos8.sh
cp config/config.example.toml config/config.toml
npm run start # pm2 start ./dist/index.js --name judger

Ubuntu20.04

sudo -i
cd~
apt update
apt install git -y
git clone https://github.com/ThinkSpiritLab/Heng-Client.git
cd ./Heng-Client
bash prepare-ubuntu20.sh
cp config/config.example.toml config/config.toml
npm run start # pm2 start ./dist/index.js --name judger

依赖

沙盒部分

本系统依赖 nsjailHeng-Core 作为沙盒内核。需要在配置文件中指定对应路径。

它的仓库是 https://github.com/google/nsjailhttps://github.com/ThinkSpiritLab/Heng-Core

语言

为了评测机正常工作,需要其支持的各种语言环境。

运行时

开发使用 nodejs:14 不保证在更低版本下能够运行。

架构

基础设施

沙盒运行支持

使用 nsjailHeng-Core

语言支持

对于每种语言,实现一个 Language 类型的函数并在 src/Spawn/Language/index.tsimport 并注册。

限流

Throttle 模块实现了异步限流,调用方法是将逻辑封装在异步函数中发送给 withThrottle 方法。

业务逻辑

控制端模块

src/controller.ts 中实现了控制端相关逻辑。

调用时,实例化一个 Controller 对象,注册各类评测机方法后获取 token 并开启连接。

评测

仅通过 ExecutableAgent 调用外部程序,ExecutableAgent 有编译和运行功能;ExecutableAgent 传入可执行对象 Executable(包括代码、语言、限制),根据不同语言调用相应 Language。编译或运行时可提供输入输出流,ExecutableAgent 询问 Language 编译参数或运行参数,并作一些合并,然后执行。

对于 NormalSpj,用户程序的输出被重定向到文件,随后被提供给结果判断程序;对于 Interactiveuserinteractor 同时运行,双方的输入输出被 pipe 到另一方,由于管道缓冲区有容量限制,写满后写程序阻塞,要避免大量输入输出、避免 interactor 过慢、避免 interactor 时限小于 user

对于 NormalSpj,用户程序没有正常结束运行时,跳过执行结果判断程序。

其他

spj 返回值及输出结果汇总

#ifndef OK_EXIT_CODE
# ifdef CONTESTER
# defineOK_EXIT_CODE0xAC
# else
# defineOK_EXIT_CODE0
# endif
#endif
#ifndef WA_EXIT_CODE
# ifdef EJUDGE
# defineWA_EXIT_CODE5
# elif defined(CONTESTER)
# defineWA_EXIT_CODE0xAB
# else
# defineWA_EXIT_CODE1
# endif
#endif
#ifndef PE_EXIT_CODE
# ifdef EJUDGE
# definePE_EXIT_CODE4
# elif defined(CONTESTER)
# definePE_EXIT_CODE0xAA
# else
# definePE_EXIT_CODE2
# endif
#endif
#ifndef FAIL_EXIT_CODE
# ifdef EJUDGE
# defineFAIL_EXIT_CODE6
# elif defined(CONTESTER)
# defineFAIL_EXIT_CODE0xA3
# else
# defineFAIL_EXIT_CODE3
# endif
#endif
#ifndef DIRT_EXIT_CODE
# ifdef EJUDGE
# defineDIRT_EXIT_CODE6
# else
# defineDIRT_EXIT_CODE4
# endif
#endif
#ifndef POINTS_EXIT_CODE
# definePOINTS_EXIT_CODE7
#endif
#ifndef UNEXPECTED_EOF_EXIT_CODE
# defineUNEXPECTED_EOF_EXIT_CODE8
#endif
#ifndef PC_BASE_EXIT_CODE
# ifdef TESTSYS
# definePC_BASE_EXIT_CODE50
# else
# definePC_BASE_EXIT_CODE0
# endif
#endifintresultExitCode(TResult r) {
if (r == _ok)
returnOK_EXIT_CODE;
if (r == _wa)
returnWA_EXIT_CODE;
if (r == _pe)
returnPE_EXIT_CODE;
if (r == _fail)
returnFAIL_EXIT_CODE;
if (r == _dirt)
returnDIRT_EXIT_CODE;
if (r == _points)
returnPOINTS_EXIT_CODE;
if (r == _unexpected_eof)
#ifdef ENABLE_UNEXPECTED_EOF
returnUNEXPECTED_EOF_EXIT_CODE;
#elsereturnPE_EXIT_CODE;
#endifif (r >= _partially)
returnPC_BASE_EXIT_CODE + (r - _partially);
returnFAIL_EXIT_CODE;
}
switch (result) {
case _ok:
errorName = "ok ";
quitscrS(LightGreen, errorName);
break;
case _wa:
errorName = "wrong answer ";
quitscrS(LightRed, errorName);
break;
case _pe:
errorName = "wrong output format ";
quitscrS(LightRed, errorName);
break;
case _fail:
errorName = "FAIL ";
quitscrS(LightRed, errorName);
break;
case _dirt:
errorName = "wrong output format ";
quitscrS(LightCyan, errorName);
result = _pe;
break;
case _points:
errorName = "points ";
quitscrS(LightYellow, errorName);
break;
case _unexpected_eof:
errorName = "unexpected eof ";
quitscrS(LightCyan, errorName);
break;
default:
if (result >= _partially) {
errorName = format("partially correct (%d) ", pctype);
isPartial = true;
quitscrS(LightYellow, errorName);
} elsequit(_fail, "What is the code ??? ");

其他平台编译参数汇总

luogu:https://www.luogu.com.cn/discuss/86673

codeforces(may be old):https://codeforces.com/blog/entry/79

loj:https://github.com/syzoj/syzoj-ng-judge/tree/master/src/languages

lojv3:https://github.com/syzoj/judge-v3/tree/master/src/languages

uoj:https://github.com/UniversalOJ/UOJ-System/blob/230738b770022cc6b882c42b67b82d7b29b82003/judger/uoj_judger/include/uoj_judger.h#L1137

pta: https://github.com/pintia/ljudge/tree/master/etc/ljudge

todo

  • spj cache LRU

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages