加入判题机(测试版)

This commit is contained in:
Himit_ZH 2021-01-26 20:01:41 +08:00
parent 6e3b576ed1
commit abcc15f16a
59 changed files with 1640 additions and 68 deletions

View File

@ -2,6 +2,7 @@
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />

View File

@ -11,6 +11,22 @@
<artifactId>DataBackup</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>top.hcode.hoj.DataBackupApplication</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@ -18,4 +18,9 @@ public class CloudHandler implements ToJudgeService {
public CommonResult submitProblemJudge(Judge judge) {
return CommonResult.errorResponse("判题机系统出错,提交进入重判队列,请等待管理员处理!", CommonResult.STATUS_ERROR);
}
@Override
public CommonResult initTestCase(Long pid, Boolean isSpj) {
return CommonResult.errorResponse("判题机评测数据初始化失败!", CommonResult.STATUS_ERROR);
}
}

View File

@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.pojo.dto.ProblemDto;
import top.hcode.hoj.pojo.entity.*;
import top.hcode.hoj.service.ToJudgeService;
import top.hcode.hoj.service.impl.*;
@ -37,6 +38,9 @@ public class AdminProblemController {
@Autowired
private ProblemCaseServiceImpl problemCaseService;
@Autowired
private ToJudgeService toJudgeService;
@GetMapping("/get-problem-list")
public CommonResult getProblemList(@RequestParam(value = "limit", required = false) Integer limit,
@RequestParam(value = "currentPage", required = false) Integer currentPage,
@ -88,6 +92,8 @@ public class AdminProblemController {
@PostMapping("")
public CommonResult addProblem(@RequestBody ProblemDto problemDto){
boolean result = problemService.adminAddProblem(problemDto);
toJudgeService.initTestCase(problemDto.getProblem().getId(),
!StringUtils.isEmpty(problemDto.getProblem().getSpjCode()));
if (result) { // 添加成功
return CommonResult.successResponse(null,"添加成功!");
} else {
@ -100,6 +106,8 @@ public class AdminProblemController {
@Transactional
public CommonResult updateProblem(@RequestBody ProblemDto problemDto){
boolean result = problemService.adminUpdateProblem(problemDto);
toJudgeService.initTestCase(problemDto.getProblem().getId(),
!StringUtils.isEmpty(problemDto.getProblem().getSpjCode()));
if (result) { // 更新成功
return CommonResult.successResponse(null,"修改成功!");
} else {

View File

@ -4,8 +4,10 @@ package top.hcode.hoj.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import top.hcode.hoj.common.exception.CloudHandler;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.pojo.entity.Judge;
@ -20,5 +22,7 @@ public interface ToJudgeService {
@PostMapping(value = "/judge")
public CommonResult submitProblemJudge(@RequestBody Judge judge);
@GetMapping("/init-test-case")
public CommonResult initTestCase(@RequestParam("pid")Long pid, @RequestParam("isSpj")Boolean isSpj);
}

View File

@ -33,6 +33,7 @@ import top.hcode.hoj.utils.JsoupUtils;
import top.hcode.hoj.utils.RedisUtils;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
/**
@ -89,6 +90,13 @@ public class DataBackupApplicationTests {
// List<AnnouncementVo> contestAnnouncement = announcementService.getContestAnnouncement(1L);
// System.out.println(contestAnnouncement.size());
String test = "{1}....{2}";
String command = "/usr/bin/java -cp {1} -XX:MaxRAM={2}k -Djava.security.manager -Dfile.encoding=UTF-8 -Djava.security.policy==/etc/java_policy -Djava.awt.headless=true Main";
String exePath = "/judge/run/32/1.exe";
String exeDir = "/judge/run/32";
int maxMemory = 1024*10;
List<String> commandList = Arrays.asList(MessageFormat.format(command, exePath, exeDir, (maxMemory / 1024)).split(" "));
System.out.println(commandList);
}
@Test

View File

@ -0,0 +1,25 @@
FROM registry.docker-cn.com/library/ubuntu:16.04
COPY *.jar /app.jar
RUN sed -i s@/archive.ubuntu.com/@/mirror.tuna.tsinghua.edu.cn/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get update
RUN buildDeps='software-properties-common git libtool cmake python-dev python3-pip python-pip libseccomp-dev' && \
apt-get update && apt-get install -y python python3 python-pkg-resources python3-pkg-resources gcc g++ $buildDeps && \
add-apt-repository ppa:openjdk-r/ppa && apt-get update && apt-get install -y openjdk-8-jdk && \
cd /tmp && git clone -b newnew --depth 1 https://github.com/QingdaoU/Judger && cd Judger && \
mkdir build && cd build && cmake .. && make && make install && \
apt-get purge -y --auto-remove $buildDeps && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
useradd -u 12001 compiler && useradd -u 12002 code && useradd -u 12003 spj && usermod -a -G spj
RUN rm -rf /judge/* && \
mkdir -p /judge/run /judge/spj /judge/test_case
CMD ["--server.port=8010"]
EXPOSE 8010
ENTRYPOINT ["java", "-jar", "/app.jar"]

View File

@ -9,15 +9,33 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>JudgeServer</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>top.hcode.hoj.JudgeServerApplication</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
@ -68,6 +86,7 @@
<artifactId>hutool-all</artifactId>
<version>5.3.3</version>
</dependency>
</dependencies>
</project>

View File

@ -1,20 +1,21 @@
package top.hcode.hoj.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import top.hcode.hoj.common.CommonResult;
import top.hcode.hoj.pojo.entity.Contest;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.UserAcproblem;
import top.hcode.hoj.judger.JudgeStrategy;
import top.hcode.hoj.pojo.entity.*;
import top.hcode.hoj.service.impl.*;
import top.hcode.hoj.util.Constants;
import top.hcode.hoj.util.IpUtils;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* @Author: Himit_ZH
@ -24,9 +25,13 @@ import java.util.concurrent.TimeUnit;
@RestController
@Slf4j
public class JudgeController {
@Autowired
private JudgeServiceImpl judgeService;
@Autowired
private ProblemServiceImpl problemService;
@Autowired
private ProblemCountServiceImpl problemCountService;
@ -42,6 +47,9 @@ public class JudgeController {
@Autowired
private ContestServiceImpl contestService;
@Autowired
private ProblemCaseServiceImpl problemCase;
@PostMapping(value = "/judge") // 待定到时再添加服务熔断兜底方法
public CommonResult submitProblemJudge(@RequestBody Judge judge) {
@ -55,57 +63,65 @@ public class JudgeController {
if (!updateResult) { // 出错并不影响主要业务逻辑可以稍微记录一下即可
log.error("修改Judge表失效----->{}", "修改提交评判为评测队列出错");
}
/*
* 先空着此部分调用判题机进行测评,所以先返回成功~
*/
// 线程沉睡模仿判题过程消耗时间
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 进行判题操作
Problem problem = problemService.getById(judge.getPid());
Judge finalJudge = judgeService.Judge(problem, judge);
// 直接默认为通过,且说明该题已被评测过
judge.setStatus(Constants.Judge.STATUS_ACCEPTED.getStatus())
.setTime(1)
.setMemory(1);
// 更新该次提交
judgeService.updateById(judge);
judgeService.updateById(finalJudge);
if (judge.getCid() == 0) { // 非比赛提交
if (finalJudge.getCid() == 0) { // 非比赛提交
// 如果是AC,就更新user_acproblem表,
if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus()) {
if (finalJudge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus()) {
userAcproblemService.saveOrUpdate(new UserAcproblem()
.setPid(judge.getPid())
.setUid(judge.getUid())
.setSubmitId(judge.getSubmitId())
.setPid(finalJudge.getPid())
.setUid(finalJudge.getUid())
.setSubmitId(finalJudge.getSubmitId())
);
}
// 比赛的提交不纳入更新该提交对应题目的数据
problemCountService.updateCount(Constants.Judge.STATUS_ACCEPTED.getStatus(), judge);
problemCountService.updateCount(Constants.Judge.STATUS_ACCEPTED.getStatus(), finalJudge);
// 如果是非比赛提交且为OI题目的提交需要判断是否更新用户得分
if (judge.getScore() != null) {
userRecordService.updateRecord(judge);
if (finalJudge.getScore() != null) {
userRecordService.updateRecord(finalJudge);
}
} else { //如果是比赛提交
Contest contest = contestService.getById(judge.getCid());
Contest contest = contestService.getById(finalJudge.getCid());
if (contest == null) {
log.error("判题机出错----------->{}", "该比赛不存在");
return CommonResult.errorResponse("该比赛不存在");
}
// 每个提交都得记录到contest_record里面,同时需要判断是否为比赛前的提交
if (contest.getStatus().intValue() == Constants.Contest.STATUS_RUNNING.getCode()) {
contestRecordService.UpdateContestRecord(judge);
contestRecordService.UpdateContestRecord(finalJudge);
}
}
return CommonResult.successResponse(judge, "判题机评测完成!");
return CommonResult.successResponse(finalJudge, "判题机评测完成!");
}
@GetMapping("/init-test-case")
public CommonResult initTestCase(@RequestParam("pid")Long pid,@RequestParam("isSpj")Boolean isSpj){
QueryWrapper<ProblemCase> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("pid", pid);
List<ProblemCase> problemCases = problemCase.list(queryWrapper);
List<HashMap<String,Object>> testCases = new LinkedList<>();
for (ProblemCase problemCase:problemCases){
HashMap<String,Object> tmp = new HashMap<>();
tmp.put("input", problemCase.getInput());
tmp.put("output", problemCase.getOutput());
testCases.add(tmp);
}
JudgeStrategy.initTestCase(testCases,pid,isSpj);
return CommonResult.successResponse(null, "初始化评测数据到判题机成功!");
}
}

View File

@ -0,0 +1,21 @@
package top.hcode.hoj.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import top.hcode.hoj.pojo.entity.Problem;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Himit_ZH
* @since 2020-10-23
*/
@Mapper
@Repository
public interface ProblemMapper extends BaseMapper<Problem> {
}

View File

@ -0,0 +1,94 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.util.HashMap;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:13
* @Description:
*/
@Slf4j
public class JudgeC extends JudgeStrategy {
private String code;
private Problem problem;
private Long submitId;
public JudgeC(Problem problem, Judge judge) {
super(problem,judge.getSubmitId());
this.submitId = judge.getSubmitId();
this.code = judge.getCode();
this.problem = problem;
}
@Override
public HashMap<String, Object> judge() {
// 该提交对应的文件夹路径
String fileDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
// 将代码写入文件
String srcFilePath = fileDir + "/" + Constants.CompileConfig.C.getSrcName();
FileWriter fileWriter = new FileWriter(srcFilePath, CharsetUtil.UTF_8);
fileWriter.write(code);
// 编译指令
String command = Constants.CompileConfig.C.getCommand();
// 输出exe文件路径
String exePath = fileDir+"/"+Constants.CompileConfig.C.getExeName();
String spjCompileResult = checkOrCompileSpj(problem.getSpjCode(), problem.getSpjLanguage());
// 如果该题是需要特别判题的但是该特别判题程序不存在或编译时产生异常则此次判题直接判系统错误
if (!spjCompileResult.equals("success")){
HashMap<String,Object> result = new HashMap<>();
result.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
result.put("msg", spjCompileResult);
return result;
}
// 编译的一些时间空间参数等
Long maxCpuTime = Constants.CompileConfig.C.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.C.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.C.getMaxMemory();
List<String> envs = Constants.RunConfig.C.getEnvs();
// 运行的一些指令参数环境配置等
String runCommand = Constants.RunConfig.C.getCommand();
List<String> runEnvs = Constants.RunConfig.C.getEnvs();
String runSeccompRule = Constants.RunConfig.C.getSeccompRule();
Integer memoryLimitCheckOnly = Constants.RunConfig.C.getMemoryLimitCheckOnly();
// 特别判题的参数
String spjRunSeccompRule = null;
if (problem.getSpjLanguage().equals("C")) {
spjRunSeccompRule = Constants.RunConfig.SPJ_C.getSeccompRule();
}else if(problem.getSpjLanguage().equals("C++")){
spjRunSeccompRule = Constants.RunConfig.SPJ_CPP.getSeccompRule();
}
// 调用安全沙盒进行编译操作
HashMap<String, Object> result = compile(srcFilePath, fileDir, command, exePath, maxCpuTime,maxRealTime,maxMemory,envs);
if (!(Boolean) result.get("result")){ // 编译失败
// {msg:error,code:STATUS_COMPILE_ERROR}
result.remove("result");
return result;
}else{
// 编译成功则进行每个测试点进行测试
List<JSONObject> testCaseResultList = judgeAllCase(exePath, fileDir, (long) problem.getTimeLimit(), problem.getTimeLimit() * 3L,
problem.getMemoryLimit()*1024*1024L, runCommand, runEnvs, runSeccompRule, spjRunSeccompRule, memoryLimitCheckOnly);
// 获取判题结果
return getJudgeInfo(testCaseResultList, problem.getType() == 0);
}
}
}

View File

@ -0,0 +1,96 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.util.HashMap;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:14
* @Description:
*/
@Slf4j
public class JudgeCPP extends JudgeStrategy{
private String code;
private Problem problem;
private Long submitId;
public JudgeCPP(Problem problem, Judge judge) {
super(problem,judge.getSubmitId());
this.submitId = judge.getSubmitId();
this.code = judge.getCode();
this.problem = problem;
}
@Override
public HashMap<String, Object> judge() {
// 该提交对应的文件夹路径
String fileDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
// 将代码写入文件
String srcFilePath = fileDir + "/" + Constants.CompileConfig.CPP.getSrcName();
FileWriter fileWriter = new FileWriter(srcFilePath, CharsetUtil.UTF_8);
fileWriter.write(code);
// 编译指令
String command = Constants.CompileConfig.CPP.getCommand();
// 输出exe文件路径
String exePath = fileDir+"/"+Constants.CompileConfig.CPP.getExeName();
String spjCompileResult = checkOrCompileSpj(problem.getSpjCode(), problem.getSpjLanguage());
// 如果该题是需要特别判题的但是该特别判题程序不存在或编译时产生异常则此次判题直接判系统错误
if (!spjCompileResult.equals("success")){
HashMap<String,Object> result = new HashMap<>();
result.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
result.put("msg", spjCompileResult);
return result;
}
// 编译的一些时间空间参数等
Long maxCpuTime = Constants.CompileConfig.CPP.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.CPP.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.CPP.getMaxMemory();
List<String> envs = Constants.RunConfig.CPP.getEnvs();
// 运行的一些指令参数环境配置等
String runCommand = Constants.RunConfig.CPP.getCommand();
List<String> runEnvs = Constants.RunConfig.CPP.getEnvs();
String runSeccompRule = Constants.RunConfig.CPP.getSeccompRule();
Integer memoryLimitCheckOnly = Constants.RunConfig.CPP.getMemoryLimitCheckOnly();
// 特别判题的参数,如果并非特别判题则为null即可
String spjRunSeccompRule = null;
if (problem.getSpjLanguage().equals("C")) {
spjRunSeccompRule = Constants.RunConfig.SPJ_C.getSeccompRule();
}else if(problem.getSpjLanguage().equals("C++")){
spjRunSeccompRule = Constants.RunConfig.SPJ_CPP.getSeccompRule();
}
// 调用安全沙盒进行编译操作
HashMap<String, Object> result = compile(srcFilePath, fileDir, command, exePath, maxCpuTime,maxRealTime,maxMemory,envs);
if (!(Boolean) result.get("result")){ // 编译失败
// {msg:error,code:STATUS_COMPILE_ERROR}
result.remove("result");
}else{
// 编译成功则进行每个测试点进行测试
List<JSONObject> testCaseResultList = judgeAllCase(exePath, fileDir, (long) problem.getTimeLimit(), problem.getTimeLimit() * 3L,
problem.getMemoryLimit()*1024*1024L, runCommand, runEnvs, runSeccompRule, spjRunSeccompRule, memoryLimitCheckOnly);
// 获取判题结果
return getJudgeInfo(testCaseResultList, problem.getType() == 0);
}
return result;
}
}

View File

@ -0,0 +1,22 @@
package top.hcode.hoj.judger;
import java.util.HashMap;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:16
* @Description:
*/
public class JudgeContext {
private JudgeStrategy judgeStrategy;
public JudgeContext(JudgeStrategy judgeStrategy) {
this.judgeStrategy = judgeStrategy;
}
// 判题的上下文接口
public HashMap<String, Object> judge() {
return judgeStrategy.judge();
}
}

View File

@ -0,0 +1,90 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONObject;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.util.HashMap;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:15
* @Description:
*/
public class JudgeJava extends JudgeStrategy {
private String code;
private Problem problem;
private Long submitId;
public JudgeJava(Problem problem, Judge judge) {
super(problem,judge.getSubmitId());
this.submitId = judge.getSubmitId();
this.code = judge.getCode();
this.problem = problem;
}
@Override
public HashMap<String, Object> judge() {
// 该提交对应的文件夹路径
String fileDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
// 将代码写入文件
String srcFilePath = fileDir + "/" + Constants.CompileConfig.JAVA.getSrcName();
FileWriter fileWriter = new FileWriter(srcFilePath, CharsetUtil.UTF_8);
fileWriter.write(code);
// 编译指令
String command = Constants.CompileConfig.JAVA.getCommand();
// 输出exe文件路径
String exePath = fileDir+"/"+Constants.CompileConfig.JAVA.getExeName();
String spjCompileResult = checkOrCompileSpj(problem.getSpjCode(), problem.getSpjLanguage());
// 如果该题是需要特别判题的但是该特别判题程序不存在或编译时产生异常则此次判题直接判系统错误
if (!spjCompileResult.equals("success")){
HashMap<String,Object> result = new HashMap<>();
result.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
result.put("msg", spjCompileResult);
return result;
}
// 编译的一些时间空间参数等
Long maxCpuTime = Constants.CompileConfig.JAVA.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.JAVA.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.JAVA.getMaxMemory();
List<String> envs = Constants.RunConfig.JAVA.getEnvs();
// 运行的一些指令参数环境配置等
String runCommand = Constants.RunConfig.JAVA.getCommand();
List<String> runEnvs = Constants.RunConfig.JAVA.getEnvs();
String runSeccompRule = Constants.RunConfig.JAVA.getSeccompRule();
Integer memoryLimitCheckOnly = Constants.RunConfig.JAVA.getMemoryLimitCheckOnly();
// 特别判题的参数,如果并非特别判题则为null即可
String spjRunSeccompRule = null;
if (problem.getSpjLanguage().equals("C")) {
spjRunSeccompRule = Constants.RunConfig.SPJ_C.getSeccompRule();
}else if(problem.getSpjLanguage().equals("C++")){
spjRunSeccompRule = Constants.RunConfig.SPJ_CPP.getSeccompRule();
}
// 调用安全沙盒进行编译操作
HashMap<String, Object> result = compile(srcFilePath, fileDir, command, exePath, maxCpuTime,maxRealTime,maxMemory,envs);
if (!(Boolean) result.get("result")){ // 编译失败
// {msg:error,code:STATUS_COMPILE_ERROR}
result.remove("result");
}else{
// 编译成功则进行每个测试点进行测试
List<JSONObject> testCaseResultList = judgeAllCase(exePath, fileDir, (long) problem.getTimeLimit(), problem.getTimeLimit() * 3L,
problem.getMemoryLimit()*1024*1024L, runCommand, runEnvs, runSeccompRule, spjRunSeccompRule, memoryLimitCheckOnly);
// 获取判题结果
return getJudgeInfo(testCaseResultList, problem.getType() == 0);
}
return result;
}
}

View File

@ -0,0 +1,92 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONObject;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.util.HashMap;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:15
* @Description:
*/
public class JudgePython2 extends JudgeStrategy {
private String code;
private Problem problem;
private Long submitId;
public JudgePython2(Problem problem, Judge judge) {
super(problem,judge.getSubmitId());
this.submitId = judge.getSubmitId();
this.code = judge.getCode();
this.problem = problem;
}
@Override
public HashMap<String, Object> judge() {
// 该提交对应的文件夹路径
String fileDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
// 将代码写入文件
String srcFilePath = fileDir + "/" + Constants.CompileConfig.PYTHON2.getSrcName();
FileWriter fileWriter = new FileWriter(srcFilePath, CharsetUtil.UTF_8);
fileWriter.write(code);
// 编译指令
String command = Constants.CompileConfig.PYTHON2.getCommand();
// 输出exe文件路径
String exePath = fileDir+"/"+Constants.CompileConfig.PYTHON2.getExeName();
String spjCompileResult = checkOrCompileSpj(problem.getSpjCode(), problem.getSpjLanguage());
// 如果该题是需要特别判题的但是该特别判题程序不存在或编译时产生异常则此次判题直接判系统错误
if (!spjCompileResult.equals("success")){
HashMap<String,Object> result = new HashMap<>();
result.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
result.put("msg", spjCompileResult);
return result;
}
// 编译的一些时间空间参数等
Long maxCpuTime = Constants.CompileConfig.PYTHON2.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.PYTHON2.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.PYTHON2.getMaxMemory();
List<String> envs = Constants.RunConfig.PYTHON2.getEnvs();
// 运行的一些指令参数环境配置等
String runCommand = Constants.RunConfig.PYTHON2.getCommand();
List<String> runEnvs = Constants.RunConfig.PYTHON2.getEnvs();
String runSeccompRule = Constants.RunConfig.PYTHON2.getSeccompRule();
Integer memoryLimitCheckOnly = Constants.RunConfig.PYTHON2.getMemoryLimitCheckOnly();
// 特别判题的参数,如果并非特别判题则为null即可
String spjRunSeccompRule = null;
if (problem.getSpjLanguage().equals("C")) {
spjRunSeccompRule = Constants.RunConfig.SPJ_C.getSeccompRule();
}else if(problem.getSpjLanguage().equals("C++")){
spjRunSeccompRule = Constants.RunConfig.SPJ_CPP.getSeccompRule();
}
// 调用安全沙盒进行编译操作
HashMap<String, Object> result = compile(srcFilePath, fileDir, command, exePath, maxCpuTime,maxRealTime,maxMemory,envs);
if (!(Boolean) result.get("result")){ // 编译失败
// {msg:error,code:STATUS_COMPILE_ERROR}
result.remove("result");
}else{
// 编译成功则进行每个测试点进行测试
List<JSONObject> testCaseResultList = judgeAllCase(exePath, fileDir, (long) problem.getTimeLimit(), problem.getTimeLimit() * 3L,
problem.getMemoryLimit()*1024*1024L, runCommand, runEnvs, runSeccompRule, spjRunSeccompRule, memoryLimitCheckOnly);
// 获取判题结果
return getJudgeInfo(testCaseResultList, problem.getType() == 0);
}
return result;
}
}

View File

@ -0,0 +1,92 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONObject;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/22 21:15
* @Description:
*/
public class JudgePython3 extends JudgeStrategy {
private String code;
private Problem problem;
private Long submitId;
public JudgePython3(Problem problem, Judge judge) {
super(problem,judge.getSubmitId());
this.submitId = judge.getSubmitId();
this.code = judge.getCode();
this.problem = problem;
}
@Override
public HashMap<String, Object> judge() {
// 该提交对应的文件夹路径
String fileDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
// 将代码写入文件
String srcFilePath = fileDir + "/" + Constants.CompileConfig.PYTHON3.getSrcName();
FileWriter fileWriter = new FileWriter(srcFilePath, CharsetUtil.UTF_8);
fileWriter.write(code);
// 编译指令
String command = Constants.CompileConfig.PYTHON3.getCommand();
// 输出exe文件路径
String exePath = fileDir+"/"+Constants.CompileConfig.PYTHON3.getExeName();
String spjCompileResult = checkOrCompileSpj(problem.getSpjCode(), problem.getSpjLanguage());
// 如果该题是需要特别判题的但是该特别判题程序不存在或编译时产生异常则此次判题直接判系统错误
if (!spjCompileResult.equals("success")){
HashMap<String,Object> result = new HashMap<>();
result.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
result.put("msg", spjCompileResult);
return result;
}
// 编译的一些时间空间参数等
Long maxCpuTime = Constants.CompileConfig.PYTHON3.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.PYTHON3.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.PYTHON3.getMaxMemory();
List<String> envs = Constants.RunConfig.PYTHON3.getEnvs();
// 运行的一些指令参数环境配置等
String runCommand = Constants.RunConfig.PYTHON3.getCommand();
List<String> runEnvs = Constants.RunConfig.PYTHON3.getEnvs();
String runSeccompRule = Constants.RunConfig.PYTHON3.getSeccompRule();
Integer memoryLimitCheckOnly = Constants.RunConfig.PYTHON3.getMemoryLimitCheckOnly();
// 特别判题的参数,如果并非特别判题则为null即可
String spjRunSeccompRule = null;
if (problem.getSpjLanguage().equals("C")) {
spjRunSeccompRule = Constants.RunConfig.SPJ_C.getSeccompRule();
}else if(problem.getSpjLanguage().equals("C++")){
spjRunSeccompRule = Constants.RunConfig.SPJ_CPP.getSeccompRule();
}
// 调用安全沙盒进行编译操作
HashMap<String, Object> result = compile(srcFilePath, fileDir, command, exePath, maxCpuTime,maxRealTime,maxMemory,envs);
if (!(Boolean) result.get("result")){ // 编译失败
// {msg:error,code:STATUS_COMPILE_ERROR}
result.remove("result");
}else{
// 编译成功则进行每个测试点进行测试
List<JSONObject> testCaseResultList = judgeAllCase(exePath, fileDir, (long) problem.getTimeLimit(), problem.getTimeLimit() * 3L,
problem.getMemoryLimit()*1024*1024L, runCommand, runEnvs, runSeccompRule, spjRunSeccompRule, memoryLimitCheckOnly);
// 获取判题结果
return getJudgeInfo(testCaseResultList, problem.getType() == 0);
}
return result;
}
}

View File

@ -0,0 +1,480 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.util.Constants;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
@Slf4j
public abstract class JudgeStrategy {
private static final int SPJ_WA = 1;
private static final int SPJ_AC = 0;
private static final int SPJ_ERROR = -1;
private static final int cpuNum = Runtime.getRuntime().availableProcessors();
private JSONObject testCasesInfo;
private String testCasesDir;
private String submissionDir;
private String spjExePath;
private String spjExeName;
private String spjRunCommand;
private Long problemId;
public JudgeStrategy(Problem problem, Long submitId) {
this.problemId = problem.getId();
this.testCasesInfo = loadTestCaseInfo(problemId);
this.testCasesDir = Constants.Compiler.TEST_CASE_DIR.getContent() + "/problem_" + problemId;
this.submissionDir = Constants.Compiler.WORKPLACE.getContent() + "/" + submitId;
if (problem.getSpjLanguage().equals("C")) { //
this.spjRunCommand = Constants.RunConfig.SPJ_C.getCommand();
String spjExeName = MessageFormat.format(Constants.CompileConfig.SPJ_C.getExeName(), problem.getId());
this.spjExeName = spjExeName;
this.spjExePath = Constants.Compiler.SPJ_EXE_DIR.getContent() + "/" + MessageFormat.format(spjExeName, problemId);
if (!FileUtil.exist(spjExePath)) {
this.spjExePath = null;
}
} else if (problem.getSpjLanguage().equals("C++")) {
this.spjRunCommand = Constants.RunConfig.SPJ_CPP.getCommand();
String spjExeName = MessageFormat.format(Constants.CompileConfig.SPJ_CPP.getExeName(), problem.getId());
this.spjExeName = spjExeName;
this.spjExePath = Constants.Compiler.SPJ_EXE_DIR.getContent() + "/" + MessageFormat.format(spjExeName, problemId);
if (!FileUtil.exist(spjExePath)) {
this.spjExePath = null;
}
}
}
public HashMap<String, Object> compile(String srcPath, String outputDir, String command, String exePath,
Long maxCpuTime, Long maxRealTime, Long maxMemory, List<String> envs) {
// 执行的exe指令路径
command = MessageFormat.format(command, srcPath, outputDir, exePath);
List<String> commandList = Arrays.asList(command.split(" "));
// 编译后的重定向到文件
String outFilePath = outputDir + "/compiler.out";
// 调用沙盒进行编译
JSONObject result = SandboxRun.run(maxCpuTime,
maxRealTime,
maxMemory,
128 * 1024 * 1024L,
20 * 1024 * 1024L,
Constants.SandBoxStatus.UNLIMITED.getStatus(),
commandList.get(0),
srcPath,
outFilePath,
outFilePath,
commandList.subList(1, commandList.size()),
envs,
Constants.Compiler.COMPILE_LOG_PATH.getContent(),
null,
0,
0,
0);
System.out.println(result+"\n");
HashMap<String, Object> data = new HashMap<>();
if (result == null) {
data.put("result", false);
data.put("code", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
data.put("msg", "Error running security sandbox.");
return data;
} else if (result.get("result") != Constants.SandBoxStatus.RESULT_SUCCESS.getStatus()) {
data.put("result", false);
if (FileUtil.exist(outFilePath)) {
FileReader fileReader = new FileReader(outFilePath);
String error = fileReader.readString();
FileUtil.del(outFilePath);
if (!StringUtils.isEmpty(error)) {
data.put("msg", error);
data.put("code", Constants.Judge.STATUS_COMPILE_ERROR.getStatus());
return data;
}
}
data.put("msg", MessageFormat.format("Compiler runtime error, info:{0}", result.toString()));
data.put("code", Constants.Judge.STATUS_COMPILE_ERROR.getStatus());
return data;
} else {
FileUtil.del(outFilePath);
data.put("result", true);
data.put("exePath", exePath);
return data;
}
}
public String checkOrCompileSpj(String spjCode, String spjLanguage) {
// 如果是需要特判的题目则需要检测特批程序是否已经编译否则进行编译
if (!StringUtils.isEmpty(spjCode)) {
if (spjLanguage.equals("C")) {
String srcName = MessageFormat.format(Constants.CompileConfig.SPJ_C.getSrcName(), problemId);
String command = Constants.CompileConfig.SPJ_C.getCommand();
Long maxCpuTime = Constants.CompileConfig.SPJ_C.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.SPJ_C.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.SPJ_C.getMaxMemory();
// 如果不存在该已经编译好的特批程序则需要再次进行编译
if (!FileUtil.exist(Constants.Compiler.SPJ_EXE_DIR.getContent() + "/" + spjExeName)) {
String result = compileSpj(spjCode, srcName, spjExeName, command, maxCpuTime, maxRealTime, maxMemory, new LinkedList<String>());
if (!result.equals("success")) { // 如果出错直接在判题结束报系统错误
return result;
}
}
} else if (spjLanguage.equals("C++")) {
String srcName = MessageFormat.format(Constants.CompileConfig.SPJ_CPP.getSrcName(), problemId);
String command = Constants.CompileConfig.SPJ_CPP.getCommand();
Long maxCpuTime = Constants.CompileConfig.SPJ_CPP.getMaxCpuTime();
Long maxRealTime = Constants.CompileConfig.SPJ_CPP.getMaxRealTime();
Long maxMemory = Constants.CompileConfig.SPJ_CPP.getMaxMemory();
// 如果不存在该已经编译好的特批程序则需要再次进行编译
if (!FileUtil.exist(Constants.Compiler.SPJ_EXE_DIR.getContent() + "/" + spjExeName)) {
String result = compileSpj(spjCode, srcName, spjExeName, command, maxCpuTime, maxRealTime, maxMemory, new LinkedList<String>());
if (!result.equals("success")) { // 如果出错直接在判题结束报系统错误
return result;
}
}
}
}
return "success";
}
public String compileSpj(String spjCode, String srcName, String exeName, String command, Long maxCpuTime, Long maxRealTime,
Long maxMemory, List<String> envs) {
String srcPath = Constants.Compiler.SPJ_SRC_DIR.getContent() + "/" + srcName;
String exePath = Constants.Compiler.SPJ_EXE_DIR.getContent() + "/" + exeName;
if (!FileUtil.exist(srcPath) && !StringUtils.isEmpty(spjCode)) {
// 如果不存在则将特别判题代码写入
FileWriter fileWriter = new FileWriter(srcPath);
fileWriter.write(spjCode);
}
// 调用安全沙盒进行编译
HashMap<String, Object> compileResult = compile(srcPath, Constants.Compiler.SPJ_EXE_DIR.getContent(), command, exePath, maxCpuTime, maxRealTime, maxMemory, envs);
if ((Boolean) compileResult.getOrDefault("result", false)) {
return "success";
} else {
log.error("特殊判题程序的编译异常---------------->{}", (String) compileResult.getOrDefault("msg", "特殊判题程序编译失败!"));
return (String) compileResult.getOrDefault("msg", "特殊判题程序编译失败!");
}
}
// 初始化测试数据写成json文件
public static void initTestCase(List<HashMap<String, Object>> testCases, Long problemId, Boolean isSpj) {
JSONObject result = new JSONObject();
result.set("isSpj", isSpj);
result.set("testCasesSize", testCases.size());
result.set("testCases", new JSONArray());
String testCasesDir = Constants.Compiler.TEST_CASE_DIR.getContent() + "/problem_" + problemId;
// 无论有没有测试数据一旦执行该函数一律清空重新生成该题目对应的测试数据文件
FileUtil.del(testCasesDir);
for (int index = 0; index < testCases.size(); index++) {
JSONObject jsonObject = new JSONObject();
String inputName = index + ".in";
jsonObject.set("inputName", inputName);
// 生成对应文件
FileWriter fileWriter = new FileWriter(testCasesDir + "/" + inputName, CharsetUtil.UTF_8);
// 将该测试数据的输入写入到文件
fileWriter.write((String) testCases.get(index).get("input"));
if (!isSpj) {
String outputName = index + ".out";
jsonObject.set("outputName", outputName);
String outputData = (String) testCases.get(index).get("output");
jsonObject.set("outputMd5", DigestUtils.md5DigestAsHex(outputData.getBytes()));
jsonObject.set("outputSize", outputData.length());
jsonObject.set("strippedOutputMd5", DigestUtils.md5DigestAsHex(outputData.trim().getBytes()));
// 生成对应文件
FileWriter outFile = new FileWriter(testCasesDir + "/" + outputName, CharsetUtil.UTF_8);
outFile.write(outputData);
}
((JSONArray) result.get("testCases")).put(index, jsonObject);
}
FileWriter infoFile = new FileWriter(testCasesDir + "/info", CharsetUtil.UTF_8);
// 写入记录文件
infoFile.write(JSONUtil.toJsonStr(result));
}
// 获取指定题目的info数据
public JSONObject loadTestCaseInfo(Long problemId) {
String testCasesDir = Constants.Compiler.TEST_CASE_DIR.getContent() + "/problem_" + problemId;
if (FileUtil.exist(testCasesDir + "/info")) {
FileReader fileReader = new FileReader(testCasesDir + "/info", CharsetUtil.UTF_8);
String infoStr = fileReader.readString();
return JSONUtil.parseObj(infoStr);
} else {
log.error("加载题目测试数据的info文件异常----------------->{}", problemId);
return null;
}
}
public JSONObject getTestCasesInfo(int testCaseId) {
return (JSONObject) ((JSONArray) testCasesInfo.get("testCases")).get(testCaseId);
}
public Integer specialJudge(String inFilePath, String userOutFilePath, Long maxCpuTime, Long maxMemory, String spjRule) {
if (spjRunCommand == null || spjExePath == null) {
log.error("spj-" + problemId + "---------------->{}", "该题特别判题程序不存在!");
return null;
}
List<String> commandList = Arrays.asList(MessageFormat.format(spjRunCommand, spjExePath, inFilePath, userOutFilePath).split(" "));
JSONObject runResult = SandboxRun.run(maxCpuTime * 3,
maxCpuTime * 9,
maxMemory * 3,
128 * 1024 * 1024L,
1024 * 1024 * 1024L,
Constants.SandBoxStatus.UNLIMITED.getStatus(),
commandList.get(0),
inFilePath,
"/tmp/spj.out",
"tmp/spj.out",
commandList.subList(1, commandList.size()),
null,
Constants.Compiler.RUN_LOG_PATH.getContent(),
spjRule,
0,
0,
0);
if (runResult == null) {
return SPJ_ERROR;
} else if (runResult.getInt("result").intValue() == Constants.SandBoxStatus.RESULT_SUCCESS.getStatus() ||
(runResult.getInt("result").intValue() == Constants.SandBoxStatus.RESULT_RUNTIME_ERROR.getStatus() &&
(runResult.getInt("exit_code") == SPJ_WA || runResult.getInt("exit_code") == SPJ_ERROR) &&
runResult.getInt("signal") == 0)) {
return runResult.getInt("exit_code");
} else {
return SPJ_ERROR;
}
}
public JSONObject judgeOneCase(int testCaseId, Boolean getUserOutput, Boolean isSpj, String exePath, String exeDir,
Long maxCpuTime, Long maxRealTime, Long maxMemory, String command, List<String> envs,
String seccompRule, String spjRule, Integer memoryLimitCheckOnly) {
if (testCasesInfo != null) {
JSONObject testCaseInfo = getTestCasesInfo(testCaseId);
String inFile = testCasesDir + "/" + testCaseInfo.get("inputName");
// 对于当前测试样例用户程序的控制台输出对应生成的文件
String realUserOutputFile = submissionDir + "/" + testCaseId + ".out";
List<String> commandList = Arrays.asList(MessageFormat.format(command, exePath, exeDir, maxMemory/1024).split(" "));
// 调用沙盒环境进行程序运行测试样例
JSONObject result = SandboxRun.run(maxCpuTime,
maxRealTime,
maxMemory,
128 * 1024 * 1024L,
Math.max(testCasesInfo.getLong("outputSize", 0L) * 2, 1024 * 1024 * 16L),
Constants.SandBoxStatus.UNLIMITED.getStatus(),
commandList.get(0),
inFile,
realUserOutputFile,
realUserOutputFile,
commandList.subList(1, commandList.size()),
envs,
Constants.Compiler.RUN_LOG_PATH.getContent(),
seccompRule,
0,
0,
memoryLimitCheckOnly);
if (result == null) {
result = new JSONObject();
result.set("msg", "Error running security sandbox.");
result.set("cpu_time", 0L);
result.set("memory", 0L);
result.set("result", Constants.SandBoxStatus.RESULT_SYSTEM_ERROR.getStatus());
return result;
}
result.set("testCaseId", testCaseId);
result.set("outputMd5", null);
result.set("output", null);
if (result.getInt("result").intValue() == Constants.SandBoxStatus.RESULT_SUCCESS.getStatus()) {
if (!FileUtil.exist(realUserOutputFile)) {
result.set("result", Constants.SandBoxStatus.RESULT_WRONG_ANSWER.getStatus());
} else {
if (isSpj) { // 特殊判题
Integer spjResult = specialJudge(inFile, realUserOutputFile, maxCpuTime, maxMemory, spjRule);
if (spjResult == null) {
result.set("result", Constants.SandBoxStatus.RESULT_SYSTEM_ERROR.getStatus());
result.set("msg", "The special Special judgment code doesn't exist.");
} else if (spjResult == SPJ_WA) {
result.set("result", Constants.SandBoxStatus.RESULT_WRONG_ANSWER.getStatus());
} else if (spjResult == SPJ_ERROR) {
result.set("result", Constants.SandBoxStatus.RESULT_SYSTEM_ERROR.getStatus());
result.set("msg", "There's something wrong with the special Special judging.");
}
} else {
// 与原测试数据输出的md5进行对比
HashMap<String, Object> data = compareOutput(testCaseId, realUserOutputFile);
result.set("outputMd5",data.get("outputMd5"));
if (!(Boolean) data.get("result")) {
result.set("result", Constants.SandBoxStatus.RESULT_WRONG_ANSWER.getStatus());
}
}
}
}
if (getUserOutput) { // 如果需要获取用户对于该题目的输出
FileReader fileReader = new FileReader(realUserOutputFile);
result.set("output", fileReader.readString());
}
return result;
} else {
log.error("题号为:" + problemId + "的评测数据出错--------------->{}", "测试数据的统计数据info为空");
return null;
}
}
public List<JSONObject> judgeAllCase(String exePath, String exeDir, Long maxCpuTime, Long maxRealTime, Long maxMemory, String command, List<String> envs,
String seccompRule, String spjRule, Integer memoryLimitCheckOnly) {
// 使用线程池开启多线程测试每一测试输入数据
ExecutorService threadPool = new ThreadPoolExecutor(
cpuNum, // 核心线程数
cpuNum * 2, // 最大线程数最多几个线程并发
3,//当线程无任务时几秒后结束该线程
TimeUnit.SECONDS,// 结束线程时间单位
new LinkedBlockingDeque<>(200), //阻塞队列限制等候线程数
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了尝试去和最早的竞争也不会抛出异常
List<FutureTask<JSONObject>> futureTasks = new ArrayList<>();
JSONArray testcaseList = (JSONArray) testCasesInfo.get("testCases");
Boolean isSpj = testCasesInfo.getBool("isSpj");
for (int index = 0; index < testcaseList.size(); index++) {
// 将每个需要测试的线程任务加入任务列表中
final int testCaseId = index;
futureTasks.add(new FutureTask<>(new Callable<JSONObject>() {
@Override
public JSONObject call() throws Exception {
return judgeOneCase(testCaseId, false, isSpj, exePath, exeDir, maxCpuTime, maxRealTime,
maxMemory, command, envs, seccompRule, spjRule, memoryLimitCheckOnly);
}
}));
}
// 提交到线程池进行执行
for (FutureTask<JSONObject> futureTask : futureTasks) {
threadPool.submit(futureTask);
}
// 所有任务执行完成且等待队列中也无任务关闭线程池
if (!threadPool.isShutdown()) {
threadPool.shutdown();
}
// 阻塞主线程, 直至线程池关闭
try {
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
log.error("判题线程池异常--------------->{}", e.getMessage());
}
List<JSONObject> result = new LinkedList<>();
// 获取线程返回结果
for (int i = 0; i < futureTasks.size(); i++) {
try {
JSONObject tmp = futureTasks.get(i).get();
result.add(tmp);
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
// 根据评测结果与用户程序跑出的字符串MD5进行对比
public HashMap<String, Object> compareOutput(int testCaseId, String userOutputFile) {
FileReader fileReader = new FileReader(userOutputFile, CharsetUtil.UTF_8);
String code = fileReader.readString();
String outputMd5 = DigestUtils.md5DigestAsHex(code.trim().getBytes());
HashMap<String, Object> result = new HashMap<>();
if (outputMd5.equals(getTestCasesInfo(testCaseId).getStr("strippedOutputMd5"))) {
result.put("result", true);
} else {
result.put("result", false);
}
result.put("outputMd5", outputMd5);
return result;
}
// 获取判题的运行时间运行空间OI得分
public HashMap<String, Object> computeResultInfo(List<JSONObject> testCaseResultList, Boolean isACM, Integer errorCaseNum) {
HashMap<String, Object> result = new HashMap<>();
// 用时和内存占用保存为多个测试点中最长的
testCaseResultList.stream().max(Comparator.comparing(t -> t.getLong("cpu_time")))
.ifPresent(t -> result.put("time", t.getLong("cpu_time")));
testCaseResultList.stream().max(Comparator.comparing(t -> t.getLong("memory")))
.ifPresent(t -> result.put("memory", t.getLong("memory")));
// OI题目计算得分
if (!isACM) {
// 现在默认得分规则为 通过测试点数/总测试点数*100
int score = 0;
score = (testCaseResultList.size() - errorCaseNum) / testCaseResultList.size() * 100;
result.put("score", score);
}
return result;
}
// 进行最终测试结果的判断除编译失败外的评测状态码和时间空间,OI题目的得分
public HashMap<String, Object> getJudgeInfo(List<JSONObject> testCaseResultList, Boolean isACM) {
// 过滤出结果不是AC的测试点结果
List<JSONObject> errorTestCaseList = testCaseResultList.stream()
.filter(jsonObject -> jsonObject.getInt("result").intValue() != Constants.SandBoxStatus.RESULT_SUCCESS.getStatus())
.collect(Collectors.toList());
// 获取判题的运行时间运行空间OI得分
HashMap<String, Object> result = computeResultInfo(testCaseResultList, isACM, errorTestCaseList.size());
// 如果该题为ACM类型的题目多个测试点全部正确则AC否则取第一个错误的测试点的状态
// 如果该题为OI类型的题目, 若多个测试点全部正确则AC若全部错误则取第一个错误测试点状态否则为部分正确
if (errorTestCaseList.size() == 0) { // 全部测试点正确则为AC
result.put("code", Constants.Judge.STATUS_ACCEPTED.getStatus());
} else if (isACM || errorTestCaseList.size() == testCaseResultList.size()) {
result.put("code", errorTestCaseList.get(0).getInt("result"));
} else {
result.put("code", Constants.Judge.STATUS_PARTIAL_ACCEPTED.getStatus());
}
return result;
}
public abstract HashMap<String, Object> judge();
}

View File

@ -0,0 +1,104 @@
package top.hcode.hoj.judger;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import top.hcode.hoj.util.Constants;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/23 13:44
* @Description:
*/
@Slf4j
public final class SandboxRun {
public static JSONObject run(Long maxCpuTime, Long maxRealTime, Long maxMemory, Long maxStack, Long maxOutputSize,
Integer maxProcessNumber, String exePath, String inputPath, String outputPath,
String errorPath, List<String> args, List<String> envs, String logPath,
String seccompRuleName, Integer uid, Integer gid, Integer memoryLimitCheckOnly) {
StringBuffer sb = new StringBuffer(Constants.Compiler.JUDGER_LIB_PATH.getContent());
if (args != null) {
for (String arg : args) {
sb.append(" --args=" + arg);
}
}
if (envs != null) {
for (String env : envs) {
sb.append(" --env=" + env);
}
}
sb.append(" --max_cpu_time=" + maxCpuTime);
sb.append(" --max_real_time=" + maxRealTime);
sb.append(" --max_memory=" + maxMemory);
sb.append(" --max_stack=" + maxStack);
sb.append(" --max_output_size=" + maxOutputSize);
sb.append(" --max_process_number=" + maxProcessNumber);
sb.append(" --uid=" + uid);
sb.append(" --gid=" + gid);
sb.append(" --memory_limit_check_only=0");
sb.append(" --exe_path=" + exePath);
sb.append(" --input_path=" + inputPath);
sb.append(" --output_path=" + outputPath);
sb.append(" --error_path=" + errorPath);
sb.append(" --log_path=" + logPath);
if (seccompRuleName != null) {
sb.append(" --seccomp_rule=" + seccompRuleName);
}
Process process = null;
BufferedReader bufIn = null;
BufferedReader bufError = null;
try {
String execution = sb.toString();
process = Runtime.getRuntime().exec(execution);
process.waitFor();
// 获取命令执行结果, 有两个结果: 正常的输出 错误的输出PS: 子进程的输出就是主进程的输入
bufIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
bufError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
// 读取输出
String line = null;
StringBuffer out = new StringBuffer();
StringBuffer errorTmp = new StringBuffer();
while ((line = bufIn.readLine()) != null) {
out.append(line).append('\n');
}
while ((line = bufError.readLine()) != null) {
errorTmp.append(line).append('\n');
}
String error = errorTmp.toString();
if (!StringUtils.isEmpty(error)) { // 如果错误输出不为空的话
log.error("调用沙盒运行程序时出错--------------------->{}", error);
}
JSONObject jsonObject = JSONUtil.parseObj(out.toString());
return jsonObject;
} catch (Exception e) {
log.error("调用沙盒运行程序时出错--------------------->{}", e);
} finally {
if (process != null) {
process.destroy();
}
}
return null;
}
}

View File

@ -2,6 +2,7 @@ package top.hcode.hoj.service;
import com.baomidou.mybatisplus.extension.service.IService;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
/**
@ -14,4 +15,5 @@ import top.hcode.hoj.pojo.entity.Judge;
*/
public interface JudgeService extends IService<Judge> {
String test();
Judge Judge(Problem problem, Judge judge);
}

View File

@ -0,0 +1,18 @@
package top.hcode.hoj.service;
import com.baomidou.mybatisplus.extension.service.IService;
import top.hcode.hoj.pojo.entity.Problem;
/**
* <p>
* 服务类
* </p>
*
* @author Himit_ZH
* @since 2020-10-23
*/
public interface ProblemService extends IService<Problem> {
}

View File

@ -4,8 +4,13 @@ package top.hcode.hoj.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.hcode.hoj.dao.JudgeMapper;
import top.hcode.hoj.judger.*;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.service.JudgeService;
import top.hcode.hoj.util.Constants;
import java.util.HashMap;
/**
* <p>
@ -21,4 +26,51 @@ public class JudgeServiceImpl extends ServiceImpl<JudgeMapper, Judge> implements
public String test() {
return "test";
}
@Override
public Judge Judge(Problem problem, Judge judge) {
JudgeStrategy needJudge = getJudge(problem, judge);
if (needJudge == null) {
judge.setErrorMessage("Unknown Language!");
judge.setStatus(Constants.Judge.STATUS_COMPILE_ERROR.getStatus());
return judge;
}
JudgeContext judgeContext = new JudgeContext(needJudge);
HashMap<String, Object> result = judgeContext.judge();
if (result.get("code") == Constants.Judge.STATUS_COMPILE_ERROR.getStatus() ||
result.get("code") == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()) {
judge.setStatus(Constants.Judge.STATUS_COMPILE_ERROR.getStatus());
judge.setErrorMessage((String) result.get("msg"));
} else {
judge.setStatus((Integer) result.get("code"));
Long memory = (Long)result.get("memory"); // 单位为long类型的b
judge.setMemory(memory.intValue());
Long time = (Long)result.get("time");
judge.setTime(time.intValue());
if (problem.getType() == 0) {
judge.setScore((Integer) result.getOrDefault("score", 0));
}
}
return judge;
}
public JudgeStrategy getJudge(Problem problem, Judge judge) {
switch (judge.getLanguage()) {
case "C":
return new JudgeC(problem, judge);
case "C++":
return new JudgeCPP(problem, judge);
case "Python3":
return new JudgePython3(problem, judge);
case "Python2":
return new JudgePython2(problem, judge);
case "Java":
return new JudgeJava(problem, judge);
default:
return null;
}
}
}

View File

@ -33,12 +33,6 @@ public class ProblemCountServiceImpl extends ServiceImpl<ProblemCountMapper, Pro
@Autowired
private ProblemCountMapper problemCountMapper;
@Autowired
private UserRecordServiceImpl userRecordService;
@Autowired
private JudgeServiceImpl judgeService;
// 默认的事务隔离等级可重复读会产生幻读读不到新的version数据所以需要更换等级为读已提交
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
@Async

View File

@ -0,0 +1,21 @@
package top.hcode.hoj.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.hcode.hoj.dao.ProblemMapper;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.service.ProblemService;
/**
* <p>
* 服务实现类
* </p>
*
* @author Himit_ZH
* @since 2020-10-23
*/
@Service
public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> implements ProblemService {
}

View File

@ -1,5 +1,9 @@
package top.hcode.hoj.util;
import java.util.Arrays;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/1/1 13:00
@ -10,22 +14,22 @@ public class Constants {
* @Description 提交评测结果的状态码
* @Since 2021/1/1
*/
public enum Judge{
STATUS_NOT_SUBMITTED (-10,"Not Submitted"),
STATUS_PRESENTATION_ERROR (-3,"Presentation Error"),
STATUS_COMPILE_ERROR (-2,"Compile Error"),
STATUS_WRONG_ANSWER (-1,"Wrong Answer"),
STATUS_ACCEPTED (0,"Accepted"),
STATUS_CPU_TIME_LIMIT_EXCEEDED (1,"CPU Time Limit Exceeded"),
STATUS_REAL_TIME_LIMIT_EXCEEDED (2,"Real Time Limit Exceeded"),
STATUS_MEMORY_LIMIT_EXCEEDED (3,"Memory Limit Exceeded"),
STATUS_RUNTIME_ERROR (4,"Runtime Error"),
STATUS_SYSTEM_ERROR (5,"System Error"),
STATUS_PENDING (6,"Pending"),
STATUS_JUDGING (7,"Judging"),
STATUS_PARTIAL_ACCEPTED (8,"Partial Accepted"),
STATUS_SUBMITTING (9,"Submitting"),
STATUS_NULL (10,"No Status");
public enum Judge {
STATUS_NOT_SUBMITTED(-10, "Not Submitted"),
STATUS_PRESENTATION_ERROR(-3, "Presentation Error"),
STATUS_COMPILE_ERROR(-2, "Compile Error"),
STATUS_WRONG_ANSWER(-1, "Wrong Answer"),
STATUS_ACCEPTED(0, "Accepted"),
STATUS_CPU_TIME_LIMIT_EXCEEDED(1, "CPU Time Limit Exceeded"),
STATUS_REAL_TIME_LIMIT_EXCEEDED(2, "Real Time Limit Exceeded"),
STATUS_MEMORY_LIMIT_EXCEEDED(3, "Memory Limit Exceeded"),
STATUS_RUNTIME_ERROR(4, "Runtime Error"),
STATUS_SYSTEM_ERROR(5, "System Error"),
STATUS_PENDING(6, "Pending"),
STATUS_JUDGING(7, "Judging"),
STATUS_PARTIAL_ACCEPTED(8, "Partial Accepted"),
STATUS_SUBMITTING(9, "Submitting"),
STATUS_NULL(10, "No Status");
private final Integer status;
private final String name;
@ -43,9 +47,9 @@ public class Constants {
return name;
}
public static Judge getTypeByStatus(int status){
for (Judge judge:Judge.values()){
if (judge.getStatus()==status){
public static Judge getTypeByStatus(int status) {
for (Judge judge : Judge.values()) {
if (judge.getStatus() == status) {
return judge;
}
}
@ -53,6 +57,180 @@ public class Constants {
}
}
public enum SandBoxStatus {
UNLIMITED(-1),
VERSION(0x020101),
RESULT_SUCCESS (0),
RESULT_WRONG_ANSWER (-1),
RESULT_CPU_TIME_LIMIT_EXCEEDED (1),
RESULT_REAL_TIME_LIMIT_EXCEEDED (2),
RESULT_MEMORY_LIMIT_EXCEEDED (3),
RESULT_RUNTIME_ERROR (4),
RESULT_SYSTEM_ERROR (5),
ERROR_INVALID_CONFIG (-1),
ERROR_FORK_FAILED (-2),
ERROR_PTHREAD_FAILED (-3),
ERROR_WAIT_FAILED (-4),
ERROR_ROOT_REQUIRED (-5),
ERROR_LOAD_SECCOMP_FAILED (-6),
ERROR_SETRLIMIT_FAILED (-7),
ERROR_DUP2_FAILED (-8),
ERROR_SETUID_FAILED (-9),
ERROR_EXECVE_FAILED (-10),
ERROR_SPJ_ERROR (-11);
private Integer status;
SandBoxStatus(Integer status) {
this.status = status;
}
public Integer getStatus() {
return status;
}
}
public enum Compiler {
WORKPLACE("/judge/run"),
JUDGER_LIB_PATH("/usr/lib/judger/libjudger.so"),
COMPILE_LOG_PATH("/log/compiler.log"),
RUN_LOG_PATH("/log/judger.log"),
TEST_CASE_DIR("/judge/test_case"),
SPJ_SRC_DIR("/judge/spj"),
SPJ_EXE_DIR("/judge/spj");
private String content;
Compiler(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
public enum CompileConfig {
C("main.c", "main", 3000L, 10000L, 256 * 1024 * 1024L, "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c11 {0} -lm -o {1}"),
CPP("main.cpp", "main", 10000L, 20000L, 1024 * 1024 * 1024L, "/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++14 {0} -lm -o {1}"),
JAVA("Main.java", "Main", 5000L, 10000L, -1L, "/usr/bin/javac {0} -d {1} -encoding UTF8"),
PYTHON2("main.py", "main.pyc", 3000L, 10000L, 128 * 1024 * 1024L, "/usr/bin/python -m py_compile {0}"),
PYTHON3("main.py", "__pycache__/main.cpython-36.pyc", 3000L, 10000L, 128 * 1024 * 1024L, "/usr/bin/python3 -m py_compile {0}"),
SPJ_C("spj-{0}.c","spj-{0}",3000L,5000L,1024*1024*1024L,"/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {0} -lm -o {1}"),
SPJ_CPP("spj-{0}.cpp","spj-{0}",10000L,20000L,1024*1024*1024L,"/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++14 {0} -lm -o {1}");
private String srcName;
private String exeName;
private Long maxCpuTime;
private Long maxRealTime;
private Long maxMemory;
private String command;
CompileConfig(String srcName, String exeName, Long maxCpuTime, Long maxRealTime, Long maxMemory, String command) {
this.srcName = srcName;
this.exeName = exeName;
this.maxCpuTime = maxCpuTime;
this.maxRealTime = maxRealTime;
this.maxMemory = maxMemory;
this.command = command;
}
public String getSrcName() {
return srcName;
}
public String getExeName() {
return exeName;
}
public Long getMaxCpuTime() {
return maxCpuTime;
}
public Long getMaxRealTime() {
return maxRealTime;
}
public Long getMaxMemory() {
return maxMemory;
}
public String getCommand() {
return command;
}
}
public static List<String> defaultEnv = Arrays.asList("LANG=en_US.UTF-8",
"LANGUAGE=en_US:en", "LC_ALL=en_US.UTF-8");
public static List<String> python3Env = Arrays.asList("LANG=en_US.UTF-8",
"LANGUAGE=en_US:en", "LC_ALL=en_US.UTF-8", "PYTHONIOENCODING=utf-8");
public enum RunConfig {
C("{0}", "c_cpp", defaultEnv, 0),
CPP("{0}", "c_cpp", defaultEnv, 0),
JAVA("/usr/bin/java -cp {1} -Djava.security.manager " +
"-Dfile.encoding=UTF-8 -Djava.security.policy==policy -Djava.awt.headless=true Main",
null, defaultEnv, 1),
PYTHON2("/usr/bin/python {0}", "general", defaultEnv, 0),
PYTHON3("/usr/bin/python3 {0}", "general", python3Env, 0),
SPJ_C("{0} {1} {2}","c_cpp",null,0),
SPJ_CPP("{0} {1} {2}","c_cpp",null,0);
private String command;
private String seccompRule;
private List<String> envs;
private Integer memoryLimitCheckOnly;
RunConfig(String command, String seccompRule, List<String> envs, Integer memoryLimitCheckOnly) {
this.command = command;
this.seccompRule = seccompRule;
this.envs = envs;
this.memoryLimitCheckOnly = memoryLimitCheckOnly;
}
public String getCommand() {
return command;
}
public String getSeccompRule() {
return seccompRule;
}
public List<String> getEnvs() {
return envs;
}
public Integer getMemoryLimitCheckOnly() {
return memoryLimitCheckOnly;
}
}
/**
* @Description 比赛相关的常量
* @Since 2021/1/7
@ -61,17 +239,17 @@ public class Constants {
TYPE_ACM(0, "ACM"),
TYPE_OI(1, "OI"),
STATUS_SCHEDULED(-1,"Scheduled"),
STATUS_RUNNING(0,"Running"),
STATUS_ENDED(1,"Ended"),
STATUS_SCHEDULED(-1, "Scheduled"),
STATUS_RUNNING(0, "Running"),
STATUS_ENDED(1, "Ended"),
AUTH_PUBLIC(0,"Public"),
AUTH_PRIVATE(1,"Private"),
AUTH_PROTECT(2,"Protect"),
AUTH_PUBLIC(0, "Public"),
AUTH_PRIVATE(1, "Private"),
AUTH_PROTECT(2, "Protect"),
RECORD_NOT_AC_PENALTY(-1,"未AC通过算罚时"),
RECORD_NOT_AC_NOT_PENALTY(0,"未AC通过不罚时"),
RECORD_AC(1,"AC通过");
RECORD_NOT_AC_PENALTY(-1, "未AC通过算罚时"),
RECORD_NOT_AC_NOT_PENALTY(0, "未AC通过不罚时"),
RECORD_AC(1, "AC通过");
private final Integer code;
private final String name;
@ -89,4 +267,6 @@ public class Constants {
return name;
}
}
}

View File

@ -0,0 +1,5 @@
#Generated by Maven
#Tue Jan 26 15:57:01 CST 2021
version=1.0-SNAPSHOT
groupId=top.hcode
artifactId=JudgeServer

View File

@ -0,0 +1,54 @@
top\hcode\hoj\judger\JudgeStrategy.class
top\hcode\hoj\JudgeServerApplication.class
top\hcode\hoj\service\impl\SystemConfigServiceImpl.class
top\hcode\hoj\common\CommonResult.class
top\hcode\hoj\dao\ProblemMapper.class
top\hcode\hoj\judger\JudgePython2.class
top\hcode\hoj\util\Constants$SandBoxStatus.class
top\hcode\hoj\config\AsyncTaskConfig.class
top\hcode\hoj\dao\JudgeCaseMapper.class
top\hcode\hoj\dao\UserRecordMapper.class
top\hcode\hoj\service\impl\ProblemCountServiceImpl.class
top\hcode\hoj\service\impl\UserAcproblemServiceImpl.class
top\hcode\hoj\controller\JudgeController.class
top\hcode\hoj\judger\JudgeJava.class
top\hcode\hoj\dao\ProblemCountMapper.class
top\hcode\hoj\service\impl\ProblemCaseServiceImpl.class
top\hcode\hoj\util\Constants$RunConfig.class
top\hcode\hoj\dao\ContestMapper.class
top\hcode\hoj\judger\JudgeContext.class
top\hcode\hoj\service\ProblemCountService.class
top\hcode\hoj\judger\JudgeCPP.class
top\hcode\hoj\util\Constants$Compiler.class
top\hcode\hoj\config\MyMetaObjectConfig.class
top\hcode\hoj\service\impl\JudgeCaseServiceImpl.class
top\hcode\hoj\service\SystemConfigService.class
top\hcode\hoj\service\impl\JudgeServiceImpl.class
top\hcode\hoj\service\ContestRecordService.class
top\hcode\hoj\config\MybatisPlusConfig.class
top\hcode\hoj\controller\SystemConfigController.class
top\hcode\hoj\judger\JudgePython3.class
top\hcode\hoj\service\impl\ContestServiceImpl.class
top\hcode\hoj\service\ProblemService.class
top\hcode\hoj\dao\ContestRecordMapper.class
top\hcode\hoj\service\impl\ContestRecordServiceImpl.class
top\hcode\hoj\service\JudgeCaseService.class
top\hcode\hoj\dao\UserAcproblemMapper.class
top\hcode\hoj\util\Constants$CompileConfig.class
top\hcode\hoj\util\IpUtils.class
top\hcode\hoj\service\ContestService.class
top\hcode\hoj\service\impl\ProblemCountServiceImpl$1.class
top\hcode\hoj\service\UserRecordService.class
top\hcode\hoj\util\Constants$Contest.class
top\hcode\hoj\service\impl\ProblemServiceImpl.class
top\hcode\hoj\judger\JudgeStrategy$1.class
top\hcode\hoj\service\UserAcproblemService.class
top\hcode\hoj\dao\ProblemCaseMapper.class
top\hcode\hoj\service\impl\UserRecordServiceImpl.class
top\hcode\hoj\judger\SandboxRun.class
top\hcode\hoj\service\ProblemCaseService.class
top\hcode\hoj\dao\JudgeMapper.class
top\hcode\hoj\judger\JudgeC.class
top\hcode\hoj\service\JudgeService.class
top\hcode\hoj\util\Constants.class
top\hcode\hoj\util\Constants$Judge.class

View File

@ -0,0 +1,46 @@
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgePython2.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\ContestRecordMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\JudgeServerApplication.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\UserAcproblemService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\ProblemMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\ProblemCountMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\config\AsyncTaskConfig.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\SystemConfigServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\SandboxRun.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\JudgeCaseMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\common\CommonResult.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\JudgeService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\UserRecordMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\UserRecordServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\ProblemCountService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\ProblemService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\UserRecordService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\ProblemCountServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgeJava.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\JudgeServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\controller\SystemConfigController.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgeC.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgeStrategy.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgeCPP.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\ProblemCaseMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\ContestRecordServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\ContestRecordService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\ContestServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgePython3.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\util\IpUtils.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\JudgeMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\ProblemServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\util\Constants.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\UserAcproblemServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\SystemConfigService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\ContestService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\UserAcproblemMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\ProblemCaseServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\ProblemCaseService.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\config\MybatisPlusConfig.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\judger\JudgeContext.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\config\MyMetaObjectConfig.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\impl\JudgeCaseServiceImpl.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\controller\JudgeController.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\dao\ContestMapper.java
E:\code\Gitee\hoj\hoj-springboot\JudgeServer\src\main\java\top\hcode\hoj\service\JudgeCaseService.java

View File

@ -24,14 +24,21 @@
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests> <!--默认关掉单元测试 -->
</configuration>
</plugin>
</plugins>
</build>
<!--版本控制-->
<properties>
<project.bulid.sourceEncoding>UTF-8</project.bulid.sourceEncoding>
<maven.compiler.sourse>1.8</maven.compiler.sourse>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.sourse>8</maven.compiler.sourse>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.12</junit.version>
<lombok.version>1.16.10</lombok.version>
<log4j.version>1.2.17</log4j.version>