├── .gitignore ├── consumer ├── pom.xml └── src │ ├── main │ ├── java │ │ └── cn │ │ │ └── wzy │ │ │ └── consumer │ │ │ ├── ConsumerApplication.java │ │ │ ├── bean │ │ │ ├── KafkaConsumerConfiguration.java │ │ │ └── RestTemplateConfig.java │ │ │ ├── controller │ │ │ └── Consumer.java │ │ │ ├── handler │ │ │ ├── GoHandler.java │ │ │ ├── JSHandler.java │ │ │ ├── JavaHandler.java │ │ │ ├── Main.java │ │ │ ├── MonoHandler.java │ │ │ ├── Py2Handler.java │ │ │ ├── Py3Handler.java │ │ │ ├── RubyHandler.java │ │ │ ├── base │ │ │ │ ├── CHandler.java │ │ │ │ ├── CPPHandler.java │ │ │ │ └── Handler.java │ │ │ ├── cpphandler │ │ │ │ ├── GNUCPP11Handler.java │ │ │ │ ├── GNUCPP14Handler.java │ │ │ │ ├── GNUCPP17Handler.java │ │ │ │ └── GNUCPP98Handler.java │ │ │ └── gcchandler │ │ │ │ ├── GNUC11Handler.java │ │ │ │ ├── GNUC90Handler.java │ │ │ │ └── GNUC99Handler.java │ │ │ ├── service │ │ │ ├── JudgeService.java │ │ │ └── Security.java │ │ │ ├── util │ │ │ ├── ExecutorUtil.java │ │ │ ├── FileUtils.java │ │ │ └── ZipUtils.java │ │ │ └── vo │ │ │ ├── JudgeResult.java │ │ │ ├── JudgeTask.java │ │ │ └── ResultCase.java │ └── resources │ │ ├── application.properties │ │ ├── judge.c │ │ └── log4j.properties │ └── test │ └── java │ └── cn │ └── wzy │ └── consumer │ └── ConsumerApplicationTests.java ├── imgs ├── structure.png ├── wx.jpg └── zfb.png ├── package.bat ├── pom.xml ├── producer ├── pom.xml └── src │ ├── main │ ├── java │ │ └── cn │ │ │ └── wzy │ │ │ └── producer │ │ │ ├── ProducerApplication.java │ │ │ ├── controller │ │ │ └── JudgeController.java │ │ │ └── vo │ │ │ ├── JudgeResult.java │ │ │ ├── JudgeTask.java │ │ │ └── ResultCase.java │ └── resources │ │ ├── application.properties │ │ ├── log4j.properties │ │ └── static │ │ └── error │ │ └── 405.html │ └── test │ └── java │ └── cn │ └── wzy │ └── producer │ └── ProducerApplicationTests.java └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | */target/ 2 | *.iml 3 | /.idea -------------------------------------------------------------------------------- /consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | cn.wzy 6 | consumer 7 | 0.0.1-SNAPSHOT 8 | consumer 9 | Demo project for Spring Boot 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 2.1.0.RELEASE 15 | 16 | 17 | 18 | 19 | 20 | UTF-8 21 | UTF-8 22 | 1.8 23 | 24 | 25 | 26 | 27 | org.slf4j 28 | slf4j-log4j12 29 | 1.7.25 30 | 31 | 32 | 33 | org.springframework.kafka 34 | spring-kafka 35 | 2.2.0.RELEASE 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | ch.qos.logback 44 | logback-classic 45 | 46 | 47 | org.slf4j 48 | log4j-over-slf4j 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | 1.5.9.RELEASE 56 | 57 | 58 | 59 | 60 | com.alibaba 61 | fastjson 62 | 1.2.51 63 | 64 | 65 | 66 | junit 67 | junit 68 | 4.13.1 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-maven-plugin 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/ConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ConsumerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ConsumerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/bean/KafkaConsumerConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.bean; 2 | 3 | import org.apache.kafka.clients.consumer.ConsumerConfig; 4 | import org.apache.kafka.common.serialization.StringDeserializer; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.kafka.annotation.EnableKafka; 9 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 10 | import org.springframework.kafka.config.KafkaListenerContainerFactory; 11 | import org.springframework.kafka.core.ConsumerFactory; 12 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 13 | import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; 14 | import org.springframework.kafka.listener.ContainerProperties; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | @Configuration 20 | @EnableKafka 21 | public class KafkaConsumerConfiguration { 22 | @Value("${spring.kafka.bootstrap-servers}") 23 | private String servers; 24 | @Value("${spring.kafka.consumer.enable-auto-commit}") 25 | private boolean enableAutoCommit; 26 | @Value("${spring.kafka.consumer.auto-commit-interval-ms}") 27 | private String autoCommitInterval; 28 | @Value("${spring.kafka.consumer.group-id}") 29 | private String groupId; 30 | @Value("${spring.kafka.consumer.auto-offset-reset}") 31 | private String autoOffsetReset; 32 | @Value("${spring.kafka.consumer.max.poll.records}") 33 | private String maxPollRecords; 34 | @Value("${spring.kafka.consumer.max.poll.interval.ms}") 35 | private String maxPollInterval; 36 | @Value("${spring.kafka.consumer.session.timeout.ms}") 37 | private String maxSessionTimeOut; 38 | 39 | @Bean 40 | public KafkaListenerContainerFactory> kafkaListenerContainerFactory() { 41 | ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); 42 | factory.setConsumerFactory(consumerFactory()); 43 | factory.getContainerProperties().setPollTimeout(1500); 44 | factory.setBatchListener(false); 45 | factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL); 46 | return factory; 47 | } 48 | 49 | private ConsumerFactory consumerFactory() { 50 | return new DefaultKafkaConsumerFactory<>(consumerConfigs()); 51 | } 52 | 53 | private Map consumerConfigs() { 54 | Map propsMap = new HashMap<>(); 55 | propsMap.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); 56 | propsMap.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, enableAutoCommit); 57 | propsMap.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitInterval); 58 | propsMap.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 59 | propsMap.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 60 | propsMap.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); 61 | propsMap.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset); 62 | propsMap.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, maxSessionTimeOut); 63 | propsMap.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords); 64 | propsMap.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, maxPollInterval); 65 | return propsMap; 66 | } 67 | } -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/bean/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.bean; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.http.client.ClientHttpRequestFactory; 6 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Configuration 10 | public class RestTemplateConfig { 11 | 12 | @Bean 13 | public RestTemplate restTemplate(ClientHttpRequestFactory factory){ 14 | return new RestTemplate(factory); 15 | } 16 | 17 | @Bean 18 | public ClientHttpRequestFactory simpleClientHttpRequestFactory(){ 19 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); 20 | factory.setConnectTimeout(15000); 21 | factory.setReadTimeout(5000); 22 | return factory; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/controller/Consumer.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.controller; 2 | 3 | import cn.wzy.consumer.service.JudgeService; 4 | import cn.wzy.consumer.vo.JudgeResult; 5 | import cn.wzy.consumer.vo.JudgeTask; 6 | import com.alibaba.fastjson.JSON; 7 | import org.apache.kafka.clients.consumer.ConsumerRecord; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.kafka.annotation.KafkaListener; 11 | import org.springframework.kafka.support.Acknowledgment; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.client.RestTemplate; 14 | 15 | import java.util.Optional; 16 | 17 | @Component 18 | public class Consumer { 19 | 20 | private final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); 21 | 22 | private final RestTemplate template; 23 | 24 | private final JudgeService service; 25 | 26 | public Consumer(JudgeService service, 27 | RestTemplate template) { 28 | this.service = service; 29 | this.template = template; 30 | } 31 | 32 | @KafkaListener(topics = {"judge"}) 33 | public void listen(ConsumerRecord record, Acknowledgment ack) { 34 | Optional kafkaMessage = Optional.ofNullable(record.value()); 35 | if (kafkaMessage.isPresent()) { 36 | try { 37 | String message = kafkaMessage.get(); 38 | JudgeTask task = JSON.parseObject(message, JudgeTask.class); 39 | JudgeResult result = service.judge(task); 40 | LOGGER.info("judge result:{}", JSON.toJSONString(result)); 41 | try { 42 | template.put(task.getCallBack(), result); 43 | } catch (Exception e) { 44 | LOGGER.error("CallBack is wrong {}, result:{}", task.getCallBack(), JSON.toJSONString(result)); 45 | } 46 | } catch (Exception e) { 47 | LOGGER.error("判题出现错误:" + e.getCause(), e); 48 | } finally { 49 | ack.acknowledge(); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/GoHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class GoHandler extends Handler { 15 | 16 | @Value("${judge.GoWord}") 17 | private String compilerWord; 18 | 19 | @Value("${judge.GoRun}") 20 | private String runWord; 21 | 22 | @Override 23 | protected void createSrc(JudgeTask task, File path) throws IOException { 24 | File src = new File(path, "main.go"); 25 | FileUtils.write(task.getSrc(), src); 26 | } 27 | 28 | @Override 29 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 30 | String cmd = compilerWord.replace("PATH", path.getPath()); 31 | return ExecutorUtil.exec(cmd, 2000); 32 | } 33 | 34 | @Override 35 | protected String getRunCommand(File path) { 36 | return runWord.replace("PATH",path.getPath()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/JSHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class JSHandler extends Handler { 15 | 16 | @Value("${judge.JSrun}") 17 | private String runWord; 18 | 19 | @Override 20 | protected void createSrc(JudgeTask task, File path) throws IOException { 21 | File src = new File(path, "main.js"); 22 | FileUtils.write(task.getSrc(), src); 23 | } 24 | 25 | @Override 26 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 27 | String cmd = runWord.replace("PATH",path.getPath()); 28 | ExecutorUtil.ExecMessage msg = ExecutorUtil.exec(cmd, 2000); 29 | if (msg.getError() == null || msg.getError().equals("timeOut")){ 30 | msg.setError(null); 31 | } 32 | return msg; 33 | } 34 | 35 | @Override 36 | protected String getRunCommand(File path) { 37 | return runWord.replace("PATH",path.getPath()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/JavaHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class JavaHandler extends Handler { 15 | 16 | @Value("${judge.Javaword}") 17 | private String compilerWord; 18 | 19 | @Value("${judge.Javarun}") 20 | private String runWord; 21 | 22 | @Override 23 | protected void createSrc(JudgeTask task, File path) throws IOException { 24 | File src = new File(path, "Main.java"); 25 | FileUtils.write(task.getSrc(), src); 26 | } 27 | 28 | @Override 29 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 30 | String cmd = compilerWord.replace("PATH",path.getPath()); 31 | return ExecutorUtil.exec(cmd, 2000); 32 | } 33 | 34 | @Override 35 | protected String getRunCommand(File path) { 36 | return runWord.replace("PATH",path.getPath()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/Main.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | String sensitive = "fork,exec,system,popen,,,,Runtime,Popen,subprocess,getstatusoutput(,getoutput(,pbs,apt-get"; 6 | String src = "import os \nsystem('')"; 7 | for (String key : sensitive.split(",")) { 8 | System.out.println(src.contains(key)); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/MonoHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class MonoHandler extends Handler { 15 | 16 | @Value("${judge.MonoWord}") 17 | private String compilerWord; 18 | 19 | @Value("${judge.MonoRun}") 20 | private String runWord; 21 | 22 | @Override 23 | protected void createSrc(JudgeTask task, File path) throws IOException { 24 | File src = new File(path, "main.cs"); 25 | FileUtils.write(task.getSrc(), src); 26 | } 27 | 28 | @Override 29 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 30 | String cmd = compilerWord.replace("PATH", path.getPath()); 31 | return ExecutorUtil.exec(cmd, 2000); 32 | } 33 | 34 | @Override 35 | protected String getRunCommand(File path) { 36 | return runWord.replace("PATH",path.getPath()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/Py2Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class Py2Handler extends Handler { 15 | @Value("${judge.Python2word}") 16 | private String compilerWord; 17 | 18 | @Value("${judge.Python2run}") 19 | private String runWord; 20 | 21 | @Override 22 | protected void createSrc(JudgeTask task, File path) throws IOException { 23 | File src = new File(path, "main.py"); 24 | FileUtils.write(task.getSrc(), src); 25 | } 26 | 27 | @Override 28 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 29 | String cmd = compilerWord.replace("PATH",path.getPath()); 30 | return ExecutorUtil.exec(cmd, 2000); 31 | } 32 | 33 | @Override 34 | protected String getRunCommand(File path) { 35 | return runWord.replace("PATH",path.getPath()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/Py3Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class Py3Handler extends Handler { 15 | @Value("${judge.Python3word}") 16 | private String compilerWord; 17 | 18 | @Value("${judge.Python3run}") 19 | private String runWord; 20 | 21 | @Override 22 | protected void createSrc(JudgeTask task, File path) throws IOException { 23 | File src = new File(path, "main.py"); 24 | FileUtils.write(task.getSrc(), src); 25 | } 26 | 27 | @Override 28 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 29 | String cmd = compilerWord.replace("PATH",path.getPath()); 30 | return ExecutorUtil.exec(cmd, 2000); 31 | } 32 | 33 | @Override 34 | protected String getRunCommand(File path) { 35 | return runWord.replace("PATH",path.getPath()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/RubyHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler; 2 | 3 | import cn.wzy.consumer.handler.base.Handler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import cn.wzy.consumer.util.FileUtils; 6 | import cn.wzy.consumer.vo.JudgeTask; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | @Service 14 | public class RubyHandler extends Handler { 15 | 16 | @Value("${judge.RubyWord}") 17 | private String compilerWord; 18 | 19 | @Value("${judge.RubyRun}") 20 | private String runWord; 21 | 22 | @Override 23 | protected void createSrc(JudgeTask task, File path) throws IOException { 24 | File src = new File(path, "main.rb"); 25 | FileUtils.write(task.getSrc(), src); 26 | } 27 | 28 | @Override 29 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 30 | String cmd = compilerWord.replace("PATH", path.getPath()); 31 | return ExecutorUtil.exec(cmd, 2000); 32 | } 33 | 34 | @Override 35 | protected String getRunCommand(File path) { 36 | return runWord.replace("PATH",path.getPath()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/base/CHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.base; 2 | 3 | import cn.wzy.consumer.util.FileUtils; 4 | import cn.wzy.consumer.vo.JudgeTask; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | @Service 12 | public abstract class CHandler extends Handler { 13 | 14 | 15 | @Value("${judge.Crun}") 16 | private String runWord; 17 | 18 | @Override 19 | protected void createSrc(JudgeTask task, File path) throws IOException { 20 | File src = new File(path, "main.c"); 21 | FileUtils.write(task.getSrc(), src); 22 | } 23 | 24 | @Override 25 | protected String getRunCommand(File path) { 26 | return runWord.replace("PATH", path.getPath()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/base/CPPHandler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.base; 2 | 3 | import cn.wzy.consumer.util.FileUtils; 4 | import cn.wzy.consumer.vo.JudgeTask; 5 | import org.springframework.beans.factory.annotation.Value; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | 10 | public abstract class CPPHandler extends Handler { 11 | 12 | @Value("${judge.Crun}") 13 | private String runWord; 14 | 15 | @Override 16 | protected void createSrc(JudgeTask task, File path) throws IOException { 17 | File src = new File(path, "main.cpp"); 18 | FileUtils.write(task.getSrc(), src); 19 | } 20 | 21 | @Override 22 | protected String getRunCommand(File path) { 23 | return runWord.replace("PATH", path.getPath()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/base/Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.base; 2 | 3 | 4 | import cn.wzy.consumer.service.Security; 5 | import cn.wzy.consumer.util.ExecutorUtil; 6 | import cn.wzy.consumer.util.FileUtils; 7 | import cn.wzy.consumer.util.ZipUtils; 8 | import cn.wzy.consumer.vo.JudgeResult; 9 | import cn.wzy.consumer.vo.JudgeTask; 10 | import cn.wzy.consumer.vo.ResultCase; 11 | import com.alibaba.fastjson.JSON; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.beans.factory.annotation.Value; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * Base Handler 22 | */ 23 | public abstract class Handler { 24 | /** 25 | * 'Accepted', 26 | * 'Presentation Error', 27 | * 'Time Limit Exceeded', 28 | * 'Memory Limit Exceeded', 29 | * 'Wrong Answer', 30 | * 'Runtime Error', 31 | * 'Output Limit Exceeded', 32 | * 'Compile Error', 33 | * 'System Error' 34 | */ 35 | protected final int AC = 0; 36 | protected final int PE = 1; 37 | protected final int TLE = 2; 38 | protected final int MLE = 3; 39 | protected final int WA = 4; 40 | protected final int RE = 5; 41 | protected final int OLE = 6; 42 | protected final int CE = 7; 43 | protected final int SE = 8; 44 | 45 | @Value("${judge.judgePath}") 46 | private String judgePath; 47 | 48 | @Value("${judge.scriptPath}") 49 | private String script; 50 | 51 | @Value("${judge.download}") 52 | private String download; 53 | 54 | @Autowired 55 | private Security security; 56 | 57 | /** 58 | * 验证参数是否合法 59 | * 60 | * @param task task. 61 | * @param result result. 62 | * @return bool. 63 | */ 64 | private boolean checkTask(JudgeTask task, JudgeResult result) { 65 | if (task.getProId() == null) { 66 | if (task.getInput() == null || task.getOutput() == null 67 | || task.getInput().size() == 0 || task.getOutput().size() == 0) { 68 | result.setGlobalMsg("测试数据不能为空!"); 69 | return false; 70 | } 71 | if (task.getInput().size() != task.getOutput().size()) { 72 | result.setGlobalMsg("测试数据组数不对应!"); 73 | return false; 74 | } 75 | } 76 | if (task.getCallBack() == null) { 77 | result.setGlobalMsg("CallBack为空!"); 78 | return false; 79 | } 80 | if (task.getSrc() == null || task.getSrc().trim().equals("")) { 81 | result.setGlobalMsg("测试代码不能为空!"); 82 | return false; 83 | } 84 | if (task.getTimeLimit() == null || task.getMemoryLimit() == null) { 85 | result.setGlobalMsg("时间消耗、空间消耗不能为空!"); 86 | return false; 87 | } 88 | if (task.getTimeLimit() < 0 || task.getTimeLimit() > 5000) { 89 | result.setGlobalMsg("时间消耗应在范围0-5s内!"); 90 | return false; 91 | } 92 | if (task.getMemoryLimit() < 0 || task.getMemoryLimit() > 524288) { 93 | result.setGlobalMsg("空间消耗应在范围524288kb内!"); 94 | return false; 95 | } 96 | return true; 97 | } 98 | 99 | /** 100 | * (模板方法)创建对应的源程序 101 | * 102 | * @throws IOException 103 | */ 104 | protected abstract void createSrc(JudgeTask task, File path) throws IOException; 105 | 106 | /** 107 | * 编译(模板方法) 108 | * 109 | * @param path 110 | * @return 111 | */ 112 | protected abstract ExecutorUtil.ExecMessage HandlerCompiler(File path); 113 | 114 | /** 115 | * 运行命令(模板方法) 116 | * 117 | * @param path 118 | * @return 119 | */ 120 | protected abstract String getRunCommand(File path); 121 | 122 | /** 123 | * 创建工作目录 124 | * 125 | * @param task 126 | * @param result 127 | * @param path 128 | * @return 129 | */ 130 | private boolean createWorkspace(JudgeTask task, JudgeResult result, File path) { 131 | try { 132 | if (!path.exists()) 133 | path.mkdirs(); 134 | if (task.getProId() == null) {//create input and output 135 | for (int i = 0; i < task.getInput().size(); i++) { 136 | File inFile = new File(path, i + ".in"); 137 | File outFile = new File(path, i + ".out"); 138 | inFile.createNewFile(); 139 | FileUtils.write(task.getInput().get(i), inFile); 140 | outFile.createNewFile(); 141 | FileUtils.write(task.getOutput().get(i), outFile); 142 | } 143 | } else {//download the testData 144 | String param = download.replace("{ProId}", task.getProId().toString()).replace("PATH", path.getPath()); 145 | ExecutorUtil.ExecMessage msg = ExecutorUtil.exec(param, 5000); 146 | if (msg.getError() == null || !msg.getError().contains("0K")) { 147 | throw new IOException("文件目录出错!"); 148 | } 149 | ZipUtils.unzip(path.getPath() + File.separator + "main.zip", path.getPath()); 150 | } 151 | createSrc(task, path); 152 | } catch (IOException e) { 153 | result.setGlobalMsg("服务器工作目录出错:" + e); 154 | return false; 155 | } 156 | return true; 157 | } 158 | 159 | /** 160 | * 编译程序 161 | * 162 | * @param result 163 | * @param path 164 | * @return 165 | */ 166 | private boolean compiler(JudgeResult result, File path) { 167 | ExecutorUtil.ExecMessage msg = HandlerCompiler(path); 168 | if (msg.getError() != null) { 169 | result.setGlobalMsg(msg.getError()); 170 | return false; 171 | } 172 | return true; 173 | } 174 | 175 | /** 176 | * 测试源程序 177 | * 178 | * @param task 179 | * @param result 180 | * @param path 181 | */ 182 | private void runSrc(JudgeTask task, JudgeResult result, File path) { 183 | //cmd : command timeLimit memoryLimit inFile tmpFile 184 | String cmd = "script process timeLimit memoryLimit inputFile tmpFile"; 185 | cmd = cmd.replace("script", script); 186 | cmd = cmd.replace("process", getRunCommand(path).replace(" ", "@")); 187 | cmd = cmd.replace("timeLimit", task.getTimeLimit().toString()); 188 | cmd = cmd.replace("memoryLimit", task.getMemoryLimit().toString()); 189 | cmd = cmd.replace("tmpFile", path.getPath() + File.separator + "tmp.out"); 190 | List cases = new ArrayList<>(); 191 | for (int i = 0; ; i++) { 192 | File inFile = new File(path.getPath() + File.separator + i + ".in"); 193 | File outFile = new File(path.getPath() + File.separator + i + ".out"); 194 | if (!inFile.exists() || !outFile.exists()) { 195 | break; 196 | } 197 | System.out.println(cmd.replace("inputFile", inFile.getPath())); 198 | ExecutorUtil.ExecMessage msg = ExecutorUtil.exec(cmd.replace("inputFile", inFile.getPath()), 50000); 199 | ResultCase caseOne = JSON.parseObject(msg.getStdout(), ResultCase.class); 200 | if (caseOne == null) { 201 | caseOne = new ResultCase(SE, -1, -1, null); 202 | } 203 | if (caseOne.getStatus() == AC) { 204 | diff(caseOne, new File(path.getPath() + File.separator + "tmp.out"), outFile); 205 | } 206 | //运行报错 207 | if (msg.getError() != null) { 208 | caseOne.setStatus(RE); 209 | caseOne.setMemoryUsed(-1); 210 | caseOne.setTimeUsed(-1); 211 | caseOne.setErrorMessage(msg.getError()); 212 | } 213 | cases.add(caseOne); 214 | ExecutorUtil.exec("rm " + path.getPath() + File.separator + "tmp.out", 1000); 215 | } 216 | result.setResult(cases); 217 | } 218 | 219 | /** 220 | * 比对结果 221 | * @param caseOne 222 | * @param tmpOut 223 | * @param stdOut 224 | */ 225 | public void diff(ResultCase caseOne, File tmpOut, File stdOut) { 226 | String tem = FileUtils.read(tmpOut); 227 | String std = FileUtils.read(stdOut); 228 | if (tem.equals(std)) { 229 | caseOne.setStatus(AC); 230 | return; 231 | } 232 | StringBuilder sb1 = new StringBuilder(); 233 | StringBuilder sb2 = new StringBuilder(); 234 | for (int i = 0; i < tem.length(); i++) { 235 | if (tem.charAt(i) != ' ' && tem.charAt(i) != '\n') { 236 | sb1.append(tem.charAt(i)); 237 | } 238 | } 239 | for (int i = 0; i < std.length(); i++) { 240 | if (std.charAt(i) != ' ' && std.charAt(i) != '\n') { 241 | sb2.append(std.charAt(i)); 242 | } 243 | } 244 | if (sb1.toString().equals(sb2.toString())) { 245 | caseOne.setStatus(PE); 246 | } else { 247 | caseOne.setStatus(WA); 248 | } 249 | } 250 | 251 | /** 252 | * 判题主流程 253 | * 254 | * @param task 255 | * @return 256 | */ 257 | public JudgeResult judge(JudgeTask task) { 258 | JudgeResult result = new JudgeResult(); 259 | //检验输入是否合法 260 | if (!checkTask(task, result)) { 261 | return result; 262 | } 263 | if (!security.checkSecurity(task, result)) { 264 | return result; 265 | } 266 | //创建工作目录 267 | File path = new File(judgePath + File.separator + System.currentTimeMillis()); 268 | if (!createWorkspace(task, result, path)) { 269 | ExecutorUtil.exec("rm -rf " + path.getPath(), 1000); 270 | return result; 271 | } 272 | //编译 273 | if (!compiler(result, path)) { 274 | ExecutorUtil.exec("rm -rf " + path.getPath(), 1000); 275 | return result; 276 | } 277 | runSrc(task, result, path); 278 | ExecutorUtil.exec("rm -rf " + path.getPath(), 1000); 279 | return result; 280 | } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/cpphandler/GNUCPP11Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.cpphandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUCPP11Handler extends CHandler { 12 | 13 | @Value("${judge.GNUCPP11}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/cpphandler/GNUCPP14Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.cpphandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUCPP14Handler extends CHandler { 12 | 13 | @Value("${judge.GNUCPP14}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/cpphandler/GNUCPP17Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.cpphandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUCPP17Handler extends CHandler { 12 | 13 | @Value("${judge.GNUCPP17}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/cpphandler/GNUCPP98Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.cpphandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUCPP98Handler extends CHandler { 12 | 13 | @Value("${judge.GNUCPP98}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/gcchandler/GNUC11Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.gcchandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUC11Handler extends CHandler { 12 | 13 | @Value("${judge.GNUC11}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/gcchandler/GNUC90Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.gcchandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUC90Handler extends CHandler { 12 | 13 | @Value("${judge.GNUC90}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/handler/gcchandler/GNUC99Handler.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.handler.gcchandler; 2 | 3 | import cn.wzy.consumer.handler.base.CHandler; 4 | import cn.wzy.consumer.util.ExecutorUtil; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.io.File; 9 | 10 | @Service 11 | public class GNUC99Handler extends CHandler { 12 | 13 | @Value("${judge.GNUC99}") 14 | private String compilerWord; 15 | 16 | @Override 17 | protected ExecutorUtil.ExecMessage HandlerCompiler(File path) { 18 | String cmd = compilerWord.replace("PATH",path.getPath()); 19 | return ExecutorUtil.exec(cmd, 5000); 20 | } 21 | } -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/service/JudgeService.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.service; 2 | 3 | import cn.wzy.consumer.handler.*; 4 | import cn.wzy.consumer.handler.base.Handler; 5 | import cn.wzy.consumer.handler.cpphandler.GNUCPP11Handler; 6 | import cn.wzy.consumer.handler.cpphandler.GNUCPP14Handler; 7 | import cn.wzy.consumer.handler.cpphandler.GNUCPP17Handler; 8 | import cn.wzy.consumer.handler.cpphandler.GNUCPP98Handler; 9 | import cn.wzy.consumer.handler.gcchandler.GNUC11Handler; 10 | import cn.wzy.consumer.handler.gcchandler.GNUC90Handler; 11 | import cn.wzy.consumer.handler.gcchandler.GNUC99Handler; 12 | import cn.wzy.consumer.vo.JudgeResult; 13 | import cn.wzy.consumer.vo.JudgeTask; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Service; 16 | 17 | @Service 18 | public class JudgeService { 19 | 20 | @Autowired 21 | private GNUC90Handler gnuc90Handler; 22 | 23 | @Autowired 24 | private GNUC99Handler gnuc99Handler; 25 | 26 | @Autowired 27 | private GNUC11Handler gnuc11Handler; 28 | 29 | @Autowired 30 | private GNUCPP98Handler gnucpp98Handler; 31 | 32 | @Autowired 33 | private GNUCPP11Handler gnucpp11Handler; 34 | 35 | @Autowired 36 | private GNUCPP14Handler gnucpp14Handler; 37 | 38 | @Autowired 39 | private GNUCPP17Handler gnucpp17Handler; 40 | 41 | @Autowired 42 | private Py2Handler py2Handler; 43 | 44 | @Autowired 45 | private Py3Handler py3Handler; 46 | 47 | @Autowired 48 | private JavaHandler javaHandler; 49 | 50 | @Autowired 51 | private JSHandler jsHandler; 52 | 53 | @Autowired 54 | private MonoHandler monoHandler; 55 | 56 | @Autowired 57 | private RubyHandler rubyHandler; 58 | 59 | @Autowired 60 | private GoHandler goHandler; 61 | 62 | public JudgeResult judge(JudgeTask task) { 63 | JudgeResult result; 64 | if (task.getJudgeId() == null || task.getJudgeId() < 1 || task.getJudgeId() > 14) { 65 | result = new JudgeResult("编译选项有误!", null); 66 | } else { 67 | Handler handler; 68 | switch (task.getJudgeId()) { 69 | case 2: 70 | handler = gnuc99Handler; 71 | break; 72 | case 3: 73 | handler = gnuc11Handler; 74 | break; 75 | case 4: 76 | handler = gnucpp98Handler; 77 | break; 78 | case 5: 79 | handler = gnucpp11Handler; 80 | break; 81 | case 6: 82 | handler = gnucpp14Handler; 83 | break; 84 | case 7: 85 | handler = gnucpp17Handler; 86 | break; 87 | case 8: 88 | handler = javaHandler; 89 | break; 90 | case 9: 91 | handler = py2Handler; 92 | break; 93 | case 10: 94 | handler = py3Handler; 95 | break; 96 | case 11: 97 | handler = jsHandler; 98 | break; 99 | case 12: 100 | handler = monoHandler; 101 | break; 102 | case 13: 103 | handler = rubyHandler; 104 | break; 105 | case 14: 106 | handler = goHandler; 107 | break; 108 | default: 109 | handler = gnuc90Handler; 110 | } 111 | result = handler.judge(task); 112 | } 113 | return result; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/service/Security.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.service; 2 | 3 | import cn.wzy.consumer.vo.JudgeResult; 4 | import cn.wzy.consumer.vo.JudgeTask; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class Security { 10 | 11 | @Value("${judge.sensitive-key}") 12 | private String sensitive; 13 | 14 | public boolean checkSecurity(JudgeTask task, JudgeResult result) { 15 | for (String key: sensitive.split(",")) { 16 | if (task.getSrc().contains(key)) { 17 | result.setGlobalMsg("the src is't allowed to contains sensitive key : " + key); 18 | return false; 19 | } 20 | } 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/util/ExecutorUtil.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | 9 | public class ExecutorUtil { 10 | 11 | public static void main(String[] args) { 12 | System.out.println(exec(args[0], 10000)); 13 | } 14 | 15 | public static class ExecMessage { 16 | 17 | private String error; 18 | 19 | private String stdout; 20 | 21 | public ExecMessage() { 22 | } 23 | 24 | public ExecMessage(String error, String stdout) { 25 | this.error = error; 26 | this.stdout = stdout; 27 | } 28 | 29 | public String getError() { 30 | return error; 31 | } 32 | 33 | public void setError(String error) { 34 | this.error = error; 35 | } 36 | 37 | public String getStdout() { 38 | return stdout; 39 | } 40 | 41 | public void setStdout(String stdout) { 42 | this.stdout = stdout; 43 | } 44 | } 45 | 46 | public static ExecMessage exec(String cmd, long milliseconds) { 47 | Runtime runtime = Runtime.getRuntime(); 48 | final Process exec; 49 | try { 50 | exec = runtime.exec(cmd); 51 | if (!exec.waitFor(milliseconds, TimeUnit.MILLISECONDS)) { 52 | if (exec.isAlive()) { 53 | exec.destroy(); 54 | } 55 | throw new InterruptedException(); 56 | } 57 | } catch (IOException e) { 58 | return new ExecMessage(e.getMessage(), null); 59 | } catch (InterruptedException e) { 60 | return new ExecMessage("timeOut", null); 61 | } 62 | ExecMessage res = new ExecMessage(); 63 | res.setError(message(exec.getErrorStream())); 64 | res.setStdout(message(exec.getInputStream())); 65 | return res; 66 | } 67 | 68 | private static String message(InputStream inputStream) { 69 | ByteArrayOutputStream buffer = null; 70 | try { 71 | buffer = new ByteArrayOutputStream(); 72 | byte[] bytes = new byte[1024]; 73 | int len; 74 | while ((len = inputStream.read(bytes)) != -1) { 75 | buffer.write(bytes, 0, len); 76 | } 77 | String result = buffer.toString("UTF-8").trim(); 78 | if (result.equals("")) { 79 | return null; 80 | } 81 | return result; 82 | } catch (IOException e) { 83 | return e.getMessage(); 84 | } finally { 85 | try { 86 | inputStream.close(); 87 | buffer.close(); 88 | } catch (Exception e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.util; 2 | 3 | import java.io.*; 4 | import java.nio.charset.StandardCharsets; 5 | 6 | public class FileUtils { 7 | 8 | public static void write(String str, File file) throws IOException { 9 | OutputStream outputStream = new FileOutputStream(file); 10 | outputStream.write(str.getBytes()); 11 | outputStream.close(); 12 | } 13 | 14 | public static void write(InputStream inputStream, OutputStream outputStream, boolean close) throws IOException { 15 | byte[] by = new byte[1024]; 16 | int n; 17 | while ((n = inputStream.read(by)) != -1) { 18 | outputStream.write(by, 0, n); 19 | } 20 | if (close) { 21 | inputStream.close(); 22 | outputStream.close(); 23 | } 24 | } 25 | 26 | public static String read(File src) { 27 | byte[] bytes = new byte[1024]; 28 | int len; 29 | InputStream inputStream = null; 30 | try { 31 | inputStream = new FileInputStream(src); 32 | StringBuilder builder = new StringBuilder(); 33 | while ((len = inputStream.read(bytes)) != -1) { 34 | byte[] effective = new byte[len]; 35 | System.arraycopy(bytes, 0, effective, 0, len); 36 | builder.append(new String(effective, StandardCharsets.UTF_8)); 37 | } 38 | return builder.toString(); 39 | } catch (IOException e) { 40 | return ""; 41 | } finally { 42 | try { 43 | assert inputStream != null; 44 | inputStream.close(); 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/util/ZipUtils.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.util; 2 | 3 | import java.io.*; 4 | import java.util.Enumeration; 5 | import java.util.zip.ZipEntry; 6 | import java.util.zip.ZipFile; 7 | import java.util.zip.ZipOutputStream; 8 | 9 | public class ZipUtils { 10 | 11 | public static boolean zip(String fileName, String zipName) { 12 | ZipOutputStream zipOutputStream = null; 13 | try { 14 | zipOutputStream = new ZipOutputStream(new FileOutputStream(zipName)); 15 | write_readme(zipOutputStream); 16 | zipOne(fileName, zipOutputStream, ""); 17 | } catch (FileNotFoundException e) { 18 | e.printStackTrace(); 19 | return false; 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | return false; 23 | } finally { 24 | if (zipOutputStream != null) { 25 | try { 26 | zipOutputStream.close(); 27 | } catch (IOException e) { 28 | e.printStackTrace(); 29 | return false; 30 | } 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | private static void zipOne(String filePath, ZipOutputStream zipOutputStream, String relative_path) throws IOException { 37 | File file = new File(filePath); 38 | if (!file.exists()) { 39 | return; 40 | } 41 | if (file.isDirectory()) { 42 | for (File tmp : file.listFiles()) { 43 | zipOne(tmp.getPath(), zipOutputStream, relative_path + file.getName() + "/"); 44 | } 45 | } else { 46 | zipOutputStream.putNextEntry(new ZipEntry(relative_path + file.getName())); 47 | FileUtils.write(new FileInputStream(file), zipOutputStream, false); 48 | zipOutputStream.flush(); 49 | zipOutputStream.closeEntry(); 50 | } 51 | } 52 | 53 | private static void write_readme(ZipOutputStream zipOutputStream) { 54 | try { 55 | zipOutputStream.putNextEntry(new ZipEntry("readme.txt")); 56 | zipOutputStream.write("这是在压缩过程中产生的readme文件====wzy不短不长八字刚好".getBytes()); 57 | zipOutputStream.flush(); 58 | zipOutputStream.closeEntry(); 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | public static boolean unzip(String zipName, String target) throws IOException { 65 | if (!new File(target).exists()) { 66 | return false; 67 | } 68 | ZipFile zipFile = new ZipFile(zipName); 69 | Enumeration entries = (Enumeration) zipFile.entries(); 70 | while (entries.hasMoreElements()) { 71 | ZipEntry entry = entries.nextElement(); 72 | if (entry.isDirectory()) { 73 | File file = new File(target + "/" + entry.getName()); 74 | if (!file.exists()) { 75 | file.mkdirs(); 76 | } 77 | } else { 78 | File file = new File(target + "/" + entry.getName()); 79 | if (!file.getParentFile().exists()) { 80 | file.getParentFile().mkdirs(); 81 | } 82 | file.createNewFile(); 83 | FileUtils.write(zipFile.getInputStream(entry), new FileOutputStream(file), true); 84 | } 85 | } 86 | zipFile.close(); 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/vo/JudgeResult.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.vo; 2 | 3 | import java.util.List; 4 | 5 | public class JudgeResult { 6 | 7 | private String globalMsg; 8 | 9 | private List result; 10 | 11 | public JudgeResult() { 12 | } 13 | 14 | public JudgeResult(String globalMsg, List result) { 15 | this.globalMsg = globalMsg; 16 | this.result = result; 17 | } 18 | 19 | public String getGlobalMsg() { 20 | return globalMsg; 21 | } 22 | 23 | public void setGlobalMsg(String globalMsg) { 24 | this.globalMsg = globalMsg; 25 | } 26 | 27 | public List getResult() { 28 | return result; 29 | } 30 | 31 | public void setResult(List result) { 32 | this.result = result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/vo/JudgeTask.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.vo; 2 | 3 | 4 | import java.util.List; 5 | 6 | public class JudgeTask { 7 | 8 | private Integer proId; 9 | 10 | private List input; 11 | 12 | private List output; 13 | 14 | private Integer timeLimit; 15 | 16 | private Integer memoryLimit; 17 | 18 | private Integer judgeId; 19 | 20 | private String src; 21 | 22 | private String callBack; 23 | 24 | public Integer getProId() { 25 | return proId; 26 | } 27 | 28 | public void setProId(Integer proId) { 29 | this.proId = proId; 30 | } 31 | 32 | public List getInput() { 33 | return input; 34 | } 35 | 36 | public void setInput(List input) { 37 | this.input = input; 38 | } 39 | 40 | public List getOutput() { 41 | return output; 42 | } 43 | 44 | public void setOutput(List output) { 45 | this.output = output; 46 | } 47 | 48 | public Integer getTimeLimit() { 49 | return timeLimit; 50 | } 51 | 52 | public void setTimeLimit(Integer timeLimit) { 53 | this.timeLimit = timeLimit; 54 | } 55 | 56 | public Integer getMemoryLimit() { 57 | return memoryLimit; 58 | } 59 | 60 | public void setMemoryLimit(Integer memoryLimit) { 61 | this.memoryLimit = memoryLimit; 62 | } 63 | 64 | public Integer getJudgeId() { 65 | return judgeId; 66 | } 67 | 68 | public void setJudgeId(Integer judgeId) { 69 | this.judgeId = judgeId; 70 | } 71 | 72 | public String getSrc() { 73 | return src; 74 | } 75 | 76 | public void setSrc(String src) { 77 | this.src = src; 78 | } 79 | 80 | public String getCallBack() { 81 | return callBack; 82 | } 83 | 84 | public void setCallBack(String callBack) { 85 | this.callBack = callBack; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /consumer/src/main/java/cn/wzy/consumer/vo/ResultCase.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer.vo; 2 | 3 | public class ResultCase { 4 | 5 | private Integer status; 6 | 7 | private Integer timeUsed; 8 | 9 | private Integer memoryUsed; 10 | 11 | private String errorMessage; 12 | 13 | public ResultCase(Integer status, Integer timeUsed, Integer memoryUsed, String errorMessage) { 14 | this.status = status; 15 | this.timeUsed = timeUsed; 16 | this.memoryUsed = memoryUsed; 17 | this.errorMessage = errorMessage; 18 | } 19 | 20 | public Integer getStatus() { 21 | return status; 22 | } 23 | 24 | public void setStatus(Integer status) { 25 | this.status = status; 26 | } 27 | 28 | public Integer getTimeUsed() { 29 | return timeUsed; 30 | } 31 | 32 | public void setTimeUsed(Integer timeUsed) { 33 | this.timeUsed = timeUsed; 34 | } 35 | 36 | public Integer getMemoryUsed() { 37 | return memoryUsed; 38 | } 39 | 40 | public void setMemoryUsed(Integer memoryUsed) { 41 | this.memoryUsed = memoryUsed; 42 | } 43 | 44 | public String getErrorMessage() { 45 | return errorMessage; 46 | } 47 | 48 | public void setErrorMessage(String errorMessage) { 49 | this.errorMessage = errorMessage; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /consumer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path=/Consumer 2 | server.port=8082 3 | # kafka configuration 4 | spring.kafka.bootstrap-servers=192.168.0.115:9092 5 | # consumer 6 | spring.kafka.consumer.group-id=1 7 | spring.kafka.consumer.auto-commit-interval-ms=1000 8 | spring.kafka.consumer.enable-auto-commit=false 9 | spring.kafka.consumer.auto-offset-reset=latest 10 | spring.kafka.consumer.max.poll.records=5 11 | spring.kafka.consumer.max.poll.interval.ms=300000 12 | spring.kafka.consumer.session.timeout.ms=10000 13 | # encoding 14 | spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer 15 | spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer 16 | 17 | # security config 18 | judge.sensitive-key=fork,system,popen,exec,,,,Runtime,Popen,subprocess,getstatusoutput,getoutput,pbs,apt-get 19 | # judge script path 20 | judge.scriptPath=/judge 21 | # workspace 22 | judge.judgePath=/tmp/OnlineJudgeWorkspace 23 | # testDataUrl 24 | judge.testDataPwd=ok1293983411faasdf 25 | judge.testDataUrl=http://acm.swust.edu.cn/API/testdata/download.do?key=${judge.testDataPwd}&problemId={ProId} 26 | judge.download=wget ${judge.testDataUrl} -O PATH/main.zip 27 | # GCC 28 | judge.GNUC11=gcc -lm -w -O3 -std=gnu11 PATH/main.c -o PATH/main 29 | judge.GNUC99=gcc -lm -w -O3 -std=gnu99 PATH/main.c -o PATH/main 30 | judge.GNUC90=gcc -lm -w -O3 -std=gnu90 PATH/main.c -o PATH/main 31 | judge.Crun=PATH/main 32 | # G++ 33 | judge.GNUCPP98=g++ -lm -w -O3 -std=gnu++98 PATH/main.c -o PATH/main 34 | judge.GNUCPP11=g++ -lm -w -O3 -std=gnu++11 PATH/main.c -o PATH/main 35 | judge.GNUCPP14=g++ -lm -w -O3 -std=gnu++14 PATH/main.c -o PATH/main 36 | judge.GNUCPP17=g++ -lm -w -O3 -std=gnu++17 PATH/main.c -o PATH/main 37 | # java compiler 38 | judge.Javaword=javac PATH/Main.java 39 | judge.Javarun=java -classpath PATH Main 40 | # python compiler 41 | judge.Python2word=python2 -m py_compile PATH/main.py 42 | judge.Python3word=python3 -m py_compile PATH/main.py 43 | judge.Python2run=python2 PATH/main.py 44 | judge.Python3run=python3 PATH/main.py 45 | #node run 46 | judge.JSrun=node PATH/main.js 47 | # C# compiler 48 | judge.MonoWord=mcs PATH/main.cs 49 | judge.MonoRun=mono PATH/main.exe 50 | # go compiler 51 | judge.GoWord=go build -o PATH/main PATH/main.go 52 | judge.GoRun=PATH/main 53 | # ruby compiler 54 | judge.RubyWord=ruby -c PATH/main.rb 55 | judge.RubyRun=ruby PATH/main.rb 56 | -------------------------------------------------------------------------------- /consumer/src/main/resources/judge.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #define AC 0 16 | #define PE 1 17 | #define TLE 2 18 | #define MLE 3 19 | #define WA 4 20 | #define RE 5 21 | #define OLE 6 22 | #define CE 7 23 | #define SE 8 24 | 25 | struct result { 26 | int status; 27 | int timeUsed; 28 | int memoryUsed; 29 | }; 30 | 31 | /* 32 | set the process limit(cpu and memory) 33 | */ 34 | void setProcessLimit(int timelimit, int memory_limit) { 35 | struct rlimit rl; 36 | /* set the time_limit (second)*/ 37 | rl.rlim_cur = timelimit / 1000; 38 | rl.rlim_max = rl.rlim_cur + 1; 39 | setrlimit(RLIMIT_CPU, &rl); 40 | 41 | /* set the memory_limit (b)*/ 42 | rl.rlim_cur = memory_limit * 1024; 43 | rl.rlim_max = rl.rlim_cur + 1024; 44 | setrlimit(RLIMIT_DATA, &rl); 45 | } 46 | 47 | /* 48 | run the user process 49 | */ 50 | void runCmd(char *args[],long timeLimit, long memoryLimit, char *in, char *out) { 51 | int newstdin = open(in,O_RDWR|O_CREAT,0644); 52 | int newstdout = open(out,O_RDWR|O_CREAT,0644); 53 | setProcessLimit(timeLimit, memoryLimit); 54 | if (newstdout != -1 && newstdin != -1){ 55 | dup2(newstdout,fileno(stdout)); 56 | dup2(newstdin,fileno(stdin)); 57 | if (execvp(args[0],args) == -1) { 58 | printf("====== Failed to start the process! =====\n"); 59 | } 60 | close(newstdin); 61 | close(newstdout); 62 | } else { 63 | printf("====== Failed to open file! =====\n"); 64 | } 65 | } 66 | 67 | /* 68 | get data of the user process 69 | */ 70 | void getResult(struct rusage *ru, int data[2]) { 71 | data[0] = ru->ru_utime.tv_sec * 1000 72 | + ru->ru_utime.tv_usec / 1000 73 | + ru->ru_stime.tv_sec * 1000 74 | + ru->ru_stime.tv_usec / 1000; 75 | data[1] = ru->ru_maxrss; 76 | } 77 | 78 | /* 79 | monitor the user process 80 | */ 81 | void monitor(pid_t pid, int timeLimit, int memoryLimit, struct result *rest) { 82 | int status; 83 | struct rusage ru; 84 | if (wait4(pid, &status, 0, &ru) == -1) 85 | printf("wait4 failure"); 86 | rest->timeUsed = ru.ru_utime.tv_sec * 1000 87 | + ru.ru_utime.tv_usec / 1000 88 | + ru.ru_stime.tv_sec * 1000 89 | + ru.ru_stime.tv_usec / 1000; 90 | rest->memoryUsed = ru.ru_maxrss; 91 | if (WIFSIGNALED(status)) { 92 | switch (WTERMSIG(status)) { 93 | case SIGSEGV: 94 | if (rest->memoryUsed > memoryLimit) 95 | rest->status = MLE; 96 | else 97 | rest->status = RE; 98 | break; 99 | case SIGALRM: 100 | case SIGXCPU: 101 | rest->status = TLE; 102 | break; 103 | default: 104 | rest->status = RE; 105 | break; 106 | } 107 | } else { 108 | if (rest->timeUsed > timeLimit) 109 | rest->status = TLE; 110 | else if (rest->memoryUsed > memoryLimit) 111 | rest->status = MLE; 112 | else 113 | rest->status = AC; 114 | } 115 | } 116 | 117 | 118 | int run(char *args[],int timeLimit, int memoryLimit, char *in, char *out){ 119 | pid_t pid = vfork(); 120 | if(pid<0) 121 | printf("error in fork!\n"); 122 | else if(pid == 0) { 123 | runCmd(args, timeLimit, memoryLimit, in, out); 124 | } else { 125 | struct result rest; 126 | monitor(pid, timeLimit, memoryLimit, &rest); 127 | printf("{\"status\":%d,\"timeUsed\":%d,\"memoryUsed\":%d}", rest.status, rest.timeUsed, rest.memoryUsed); 128 | } 129 | } 130 | 131 | void split( char **arr, char *str, const char *del){ 132 | char *s =NULL; 133 | s = strtok(str,del); 134 | while(s != NULL) 135 | { 136 | *arr++ = s; 137 | s = strtok(NULL,del); 138 | } 139 | *arr++ = NULL; 140 | } 141 | 142 | int main(int argc,char *argv[]) 143 | { 144 | char *cmd[20]; 145 | split(cmd, argv[1], "@"); 146 | run(cmd, atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]); 147 | return 0; 148 | } -------------------------------------------------------------------------------- /consumer/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxiaoshuai-lucky/online-judge/de6c6d4d2b2e947e23d68037a9b3af406d746865/consumer/src/main/resources/log4j.properties -------------------------------------------------------------------------------- /consumer/src/test/java/cn/wzy/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.consumer; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.kafka.core.KafkaTemplate; 7 | import org.springframework.kafka.support.SendResult; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import org.springframework.util.concurrent.ListenableFuture; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | @RunWith(SpringRunner.class) 15 | @SpringBootTest(classes = ConsumerApplication.class) 16 | public class ConsumerApplicationTests { 17 | 18 | @Resource 19 | KafkaTemplate kafkaTemplate; 20 | 21 | @Test 22 | public void contextLoads() throws InterruptedException, ExecutionException { 23 | Thread.sleep(5000); 24 | for (int i = 0; i < 10; i++) { 25 | ListenableFuture> judge = kafkaTemplate.send("judge", "newdata" + i); 26 | System.out.println("发送消息:" + judge.get()); 27 | } 28 | while (true) { 29 | 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /imgs/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxiaoshuai-lucky/online-judge/de6c6d4d2b2e947e23d68037a9b3af406d746865/imgs/structure.png -------------------------------------------------------------------------------- /imgs/wx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxiaoshuai-lucky/online-judge/de6c6d4d2b2e947e23d68037a9b3af406d746865/imgs/wx.jpg -------------------------------------------------------------------------------- /imgs/zfb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxiaoshuai-lucky/online-judge/de6c6d4d2b2e947e23d68037a9b3af406d746865/imgs/zfb.png -------------------------------------------------------------------------------- /package.bat: -------------------------------------------------------------------------------- 1 | mvn clean package -DskipTests -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | cn.wzy 8 | online-judge 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | consumer 13 | producer 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /producer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | cn.wzy 6 | producer 7 | 0.0.1-SNAPSHOT 8 | producer 9 | Demo project for Spring Boot 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 2.1.0.RELEASE 15 | 16 | 17 | 18 | 19 | 20 | UTF-8 21 | UTF-8 22 | 1.8 23 | 24 | 25 | 26 | 27 | org.slf4j 28 | slf4j-log4j12 29 | 1.7.25 30 | 31 | 32 | 33 | org.springframework.kafka 34 | spring-kafka 35 | 2.2.0.RELEASE 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | ch.qos.logback 44 | logback-classic 45 | 46 | 47 | org.slf4j 48 | log4j-over-slf4j 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | 1.5.9.RELEASE 56 | 57 | 58 | 59 | 60 | com.alibaba 61 | fastjson 62 | 1.2.51 63 | 64 | 65 | 66 | junit 67 | junit 68 | 4.12 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-maven-plugin 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /producer/src/main/java/cn/wzy/producer/ProducerApplication.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ProducerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ProducerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /producer/src/main/java/cn/wzy/producer/controller/JudgeController.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer.controller; 2 | 3 | import cn.wzy.producer.vo.JudgeResult; 4 | import cn.wzy.producer.vo.JudgeTask; 5 | import com.alibaba.fastjson.JSON; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.kafka.core.KafkaTemplate; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.annotation.Resource; 12 | 13 | @RestController 14 | @CrossOrigin 15 | public class JudgeController { 16 | 17 | 18 | private final Logger LOGGER = LoggerFactory.getLogger(JudgeController.class); 19 | 20 | @Resource 21 | KafkaTemplate kafkaTemplate; 22 | 23 | @PostMapping("/judge.do") 24 | public Object judge(@RequestBody JudgeTask task) { 25 | LOGGER.info("\n************" + "\n" + 26 | "\t收到任务,将回调到:" + task.getCallBack() + "\n" + 27 | "************"); 28 | kafkaTemplate.send("judge", JSON.toJSONString(task)); 29 | return "OK"; 30 | } 31 | 32 | @PutMapping("/result.do") 33 | public String result(String key, Long submitId, @RequestBody JudgeResult result) { 34 | LOGGER.info("\n*****************" + "\n" + 35 | "\tkey: " + key + "\n" + 36 | "\tsubmitId: " + submitId + "\n" + 37 | "\tresult: " + result + "\n" + 38 | "*****************"); 39 | return "OK"; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /producer/src/main/java/cn/wzy/producer/vo/JudgeResult.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer.vo; 2 | 3 | import java.util.List; 4 | 5 | public class JudgeResult { 6 | 7 | private String globalMsg; 8 | 9 | private List result; 10 | 11 | public JudgeResult() { 12 | } 13 | 14 | public JudgeResult(String globalMsg, List result) { 15 | this.globalMsg = globalMsg; 16 | this.result = result; 17 | } 18 | 19 | public String getGlobalMsg() { 20 | return globalMsg; 21 | } 22 | 23 | public void setGlobalMsg(String globalMsg) { 24 | this.globalMsg = globalMsg; 25 | } 26 | 27 | public List getResult() { 28 | return result; 29 | } 30 | 31 | public void setResult(List result) { 32 | this.result = result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /producer/src/main/java/cn/wzy/producer/vo/JudgeTask.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer.vo; 2 | 3 | 4 | import java.util.List; 5 | 6 | public class JudgeTask { 7 | 8 | private Integer proId; 9 | 10 | private List input; 11 | 12 | private List output; 13 | 14 | private Integer timeLimit; 15 | 16 | private Integer memoryLimit; 17 | 18 | private Integer judgeId; 19 | 20 | private String src; 21 | 22 | private String callBack; 23 | 24 | public Integer getProId() { 25 | return proId; 26 | } 27 | 28 | public void setProId(Integer proId) { 29 | this.proId = proId; 30 | } 31 | 32 | public List getInput() { 33 | return input; 34 | } 35 | 36 | public void setInput(List input) { 37 | this.input = input; 38 | } 39 | 40 | public List getOutput() { 41 | return output; 42 | } 43 | 44 | public void setOutput(List output) { 45 | this.output = output; 46 | } 47 | 48 | public Integer getTimeLimit() { 49 | return timeLimit; 50 | } 51 | 52 | public void setTimeLimit(Integer timeLimit) { 53 | this.timeLimit = timeLimit; 54 | } 55 | 56 | public Integer getMemoryLimit() { 57 | return memoryLimit; 58 | } 59 | 60 | public void setMemoryLimit(Integer memoryLimit) { 61 | this.memoryLimit = memoryLimit; 62 | } 63 | 64 | public Integer getJudgeId() { 65 | return judgeId; 66 | } 67 | 68 | public void setJudgeId(Integer judgeId) { 69 | this.judgeId = judgeId; 70 | } 71 | 72 | public String getSrc() { 73 | return src; 74 | } 75 | 76 | public void setSrc(String src) { 77 | this.src = src; 78 | } 79 | 80 | public String getCallBack() { 81 | return callBack; 82 | } 83 | 84 | public void setCallBack(String callBack) { 85 | this.callBack = callBack; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /producer/src/main/java/cn/wzy/producer/vo/ResultCase.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer.vo; 2 | 3 | public class ResultCase { 4 | 5 | private Integer status; 6 | 7 | private Integer timeUsed; 8 | 9 | private Integer memoryUsed; 10 | 11 | private String errorMessage; 12 | 13 | public ResultCase(Integer status, Integer timeUsed, Integer memoryUsed, String errorMessage) { 14 | this.status = status; 15 | this.timeUsed = timeUsed; 16 | this.memoryUsed = memoryUsed; 17 | this.errorMessage = errorMessage; 18 | } 19 | 20 | public Integer getStatus() { 21 | return status; 22 | } 23 | 24 | public void setStatus(Integer status) { 25 | this.status = status; 26 | } 27 | 28 | public Integer getTimeUsed() { 29 | return timeUsed; 30 | } 31 | 32 | public void setTimeUsed(Integer timeUsed) { 33 | this.timeUsed = timeUsed; 34 | } 35 | 36 | public Integer getMemoryUsed() { 37 | return memoryUsed; 38 | } 39 | 40 | public void setMemoryUsed(Integer memoryUsed) { 41 | this.memoryUsed = memoryUsed; 42 | } 43 | 44 | public String getErrorMessage() { 45 | return errorMessage; 46 | } 47 | 48 | public void setErrorMessage(String errorMessage) { 49 | this.errorMessage = errorMessage; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /producer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path=/producer 2 | server.port=8081 3 | # kafka configuration 4 | spring.kafka.bootstrap-servers=202.115.161.211:19092 5 | spring.kafka.producer.retries=0 6 | spring.kafka.producer.batch-size=16384 7 | spring.kafka.producer.buffer-memory=33554432 8 | # encoding 9 | spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer 10 | spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer 11 | -------------------------------------------------------------------------------- /producer/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxiaoshuai-lucky/online-judge/de6c6d4d2b2e947e23d68037a9b3af406d746865/producer/src/main/resources/log4j.properties -------------------------------------------------------------------------------- /producer/src/main/resources/static/error/405.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OnlineJudge 6 | 7 | 8 |

9 | 405-请求接口仅支持POST请求
12 |

13 |

14 | 此项目仅提供POST提交接口,接收结果回调接口需要外网服务器地址。 15 |

16 |

17 | GitHub地址:https://github.com/1510460325/online-judge 19 |

20 |

21 | 请求实例: 22 |

23 |

24 | url:POST:http://wangzhengyu.cn:8081/producer/judge.do 26 |

27 |

28 | Content-Type:application/json 30 |

31 |

32 | body:
33 |

34 |
 35 | {
 36 | 	"input":["12 12","12 12"],
 37 | 	"output":["24","24"],
 38 | 	"timeLimit":1000,
 39 | 	"memoryLimit":65535,
 40 | 	"judgeId":1,
 41 | 	"src":"#include<iostream>\nusing namespace std;\nint main()\n{\n\tint a,b;\n\tcin>>a>>b;\n    int c=a+b;\n    cout<<c;\n\n\treturn 0;\n}\n",
 42 | 	"callBack":"http://wangzhengyu.cn:8081/producer/result.do?key=111&submitId=12"
 43 | }
44 |

45 | 参数列表(json): 46 |

47 |
    49 |
  • 50 |

    51 | 题目id(题目id为本人数据库指定题目id,指定后测试数据为本人系统提供) 52 |

    53 |
  • 54 |
  • 55 |

    56 | 输入样例数组(自定义输入样例,输入id之后忽略) 57 |

    58 |
  • 59 |
  • 60 |

    61 | 输出样例数组(自定义输出样例,输入id之后忽略) 62 |

    63 |
  • 64 |
  • 65 |

    66 | 时间限制:ms 67 |

    68 |
  • 69 |
  • 70 |

    71 | 内存限制:kb 72 |

    73 |
  • 74 |
  • 75 |

    76 | 判题语言:语言列表1-14 77 |

    78 |
  • 79 |
  • 80 |

    81 | 源代码 82 |

    83 |
  • 84 |
  • 85 |

    86 | callBack地址:为put请求方式的地址 87 |

    88 |
  • 89 |
90 |

91 | 判题语言支持: 92 |

93 |
    95 |
  • 96 |

    97 | GCC 98 |

    99 |
  • 100 |
      101 |
    • 102 |

      103 | GNU C90 104 |

      105 |
    • 106 |
    • 107 |

      108 | GNU C99 109 |

      110 |
    • 111 |
    • 112 |

      113 | GNU C11 114 |

      115 |
    • 116 |
    117 |
  • 118 |

    119 | G++ 120 |

    121 |
  • 122 |
      123 |
    • 124 |

      125 | GNU C++98 126 |

      127 |
    • 128 |
    • 129 |

      130 | GNU C++11 131 |

      132 |
    • 133 |
    • 134 |

      135 | GNU C++14 136 |

      137 |
    • 138 |
    • 139 |

      140 | GNU C++17 141 |

      142 |
    • 143 |
    144 |
  • 145 |

    146 | Java 1.8 147 |

    148 |
  • 149 |
  • 150 |

    151 | python2.7 152 |

    153 |
  • 154 |
  • 155 |

    156 | python3.6 157 |

    158 |
  • 159 |
  • 160 |

    161 | JavaScript 162 |

    163 |
  • 164 |
  • 165 |

    166 | C# 167 |

    168 |
  • 169 |
  • 170 |

    171 | Ruby 172 |

    173 |
  • 174 |
  • 175 |

    176 | GO 177 |

    178 |
  • 179 |
180 |

181 | 判题采用异步回调更新函数,网站服务器将判题任务和该id提交给判题服务器,判题服务器判题结束自动调用回调函数携带判题结果。
如上述任务会将结果返回到callBack的put接口中,网站服务器只需要指定一个PUT类型回调地址即可,参数submitId为了分辨是哪个任务的回调结果。
为了回调接口安全,防止其他人篡改结果,建议外加一个密钥:"callBack" 182 | :"http://ip:port/demo/update.do?submitId=111&key=1asdf112asdfasdf", 184 | 由于这个接口地址由网站服务器指定之后发送给判题服务器的,所以只有这两个服务器知道密钥,所以其他人不能修改结果。
回调接口样例:https://github.com/1510460325/online-judge/blob/master/producer/src/main/java/cn/wzy/producer/controller/JudgeController.java
返回数据(json): 187 |

188 |
    190 |
  • 191 |

    192 | 全局信息:编译错误信息之类的,判题正常为null 193 |

    194 |
  • 195 |
  • 196 |

    197 | 判题信息(按参数组数顺序): 198 |

    199 |
  • 200 |
      201 |
    • 202 |

      203 | 结果: 204 |

      205 |
    • 206 |
    • 207 |

      208 | 时间消耗 209 |

      210 |
    • 211 |
    • 212 |

      213 | 空间消耗 214 |

      215 |
    • 216 |
    • 217 |

      218 | 运行错误信息:运行正常为null 219 |

      220 |
    • 221 |
    222 |
223 |
{
224 |     "globalMsg": null,
225 |     "result": [
226 |         {
227 |             "result": 4,
228 |             "timeused": 0,
229 |             "memoryused": 0,
230 |             "errormessage": null
231 |         },
232 |         {
233 |             "result": 1,
234 |             "timeused": 0,
235 |             "memoryused": 0,
236 |             "errormessage": null
237 |         },
238 |         {
239 |             "result": 0,
240 |             "timeused": 1,
241 |             "memoryused": 6896,
242 |             "errormessage": null
243 |         }
244 |     ]
245 | }
246 |

247 | 返回结果集:0 ~ 8 248 |

249 |
    251 |
  • 252 |

    253 | 'Accepted' 254 |

    255 |
  • 256 |
  • 257 |

    258 | 'Presentation Error' 259 |

    260 |
  • 261 |
  • 262 |

    263 | 'Time Limit Exceeded' 264 |

    265 |
  • 266 |
  • 267 |

    268 | 'Memory Limit Exceeded' 269 |

    270 |
  • 271 |
  • 272 |

    273 | 'Wrong Answer' 274 |

    275 |
  • 276 |
  • 277 |

    278 | 'Runtime Error' 279 |

    280 |
  • 281 |
  • 282 |

    283 | 'Output Limit Exceeded' 284 |

    285 |
  • 286 |
  • 287 |

    288 | 'Compile Error' 289 |

    290 |
  • 291 |
  • 292 |

    293 | 'System Error' 294 |

    295 |
  • 296 |
297 |

298 |
299 |

300 | 301 | -------------------------------------------------------------------------------- /producer/src/test/java/cn/wzy/producer/ProducerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.wzy.producer; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ProducerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## ACM独立判题服务 2 | 开源项目地址:[github](https://github.com/1510460325/online-judge/) 3 | 可针对性的添加判题语言,或者修改判题细节 4 | ## 判题语言支持: 5 | * GCC 6 | * GNU C90 7 | * GNU C99 8 | * GNU C11 9 | * G++ 10 | * GNU C++98 11 | * GNU C++11 12 | * GNU C++14 13 | * GNU C++17 14 | * Java 1.8 15 | * python2.7 16 | * python3.6 17 | * JavaScript 18 | * C# 19 | * Ruby 20 | * GO 21 | ## 判题接口 22 | POST http://wangzhengyu.cn:8081/producer/judge.do 23 | 参数列表(json): 24 | * 题目id(题目id为本人数据库指定题目id,指定后测试数据为本人系统提供) 25 | * 输入样例数组(自定义输入样例,输入id之后忽略) 26 | * 输出样例数组(自定义输出样例,输入id之后忽略) 27 | * "input":["12 12","13 12"] 相当于两个测试用例,第一次测试输入12 12,第二次测试输入13 12 28 | * "output":["24","25"] 对应上面的输出用例的标准输出,第一次测试输出24,第二次测试输出25 29 | * 时间限制:ms 30 | * 内存限制:kb 31 | * 判题语言:上述语言列表1-14 32 | * 源代码 33 | * callBack地址:为put请求方式的地址 34 | ~~~ 35 | { 36 | "proId":15, 37 | "input":["99 1","99 1","99 1"], // 有多少个测试数据数组就多长 38 | "output":["98","100\n","100"], // 对应上面每个输入的标准输出 39 | "timeLimit":1000, 40 | "memoryLimit":65535, 41 | "judgeId":1, 42 | "src":"#include\nint main()\n{\n\tint a,b,sum;\n\tscanf(\"%d %d\",&a,&b);\n\tsum=a+b;\n\tprintf(\"%d\",sum);\n\treturn 0;\n}", 43 | "callBack" :"http://ip:port/demo/update.do?submitId=111" 44 | } 45 | ~~~ 46 | 判题采用异步回调更新函数,网站服务器将判题任务和该id提交给判题服务器,判题服务器判题结束自动调用回调函数携带判题结果。 47 | 如上述任务会将结果返回到callBack的put接口中,网站服务器只需要指定一个PUT类型回调地址即可,参数submitId为了分辨是哪个任务的回调结果。 48 | 为了回调接口安全,防止其他人篡改结果,建议外加一个密钥:"callBack" :"http://ip:port/demo/update.do?submitId=111&key=1asdf112asdfasdf", 49 | 由于这个接口地址由网站服务器指定之后发送给判题服务器的,所以只有这两个服务器知道密钥,所以其他人不能修改结果。 50 | 回调接口样例:https://github.com/1510460325/online-judge/blob/master/producer/src/main/java/cn/wzy/producer/controller/JudgeController.java 51 | 返回数据(json): 52 | * 全局信息:编译错误信息之类的,判题正常为null 53 | * 判题信息(按参数组数顺序): 54 | * 结果: 55 | * 时间消耗 56 | * 空间消耗 57 | * 运行错误信息:运行正常为null 58 | ~~~ 59 | { 60 | "globalMsg": null, 61 | "result": [ 62 | { 63 | "status": 4, 64 | "timeUsed": 0, 65 | "memoryUsed": 0, 66 | "errorMessage": null 67 | }, 68 | { 69 | "status": 1, 70 | "timeUsed": 0, 71 | "memoryUsed": 0, 72 | "errorMessage": null 73 | }, 74 | { 75 | "status": 0, 76 | "timeUsed": 1, 77 | "memoryUsed": 6896, 78 | "errorMessage": null 79 | } 80 | ] 81 | } 82 | ~~~ 83 | 返回结果集:0 ~ 8 84 | * 'Accepted' 85 | * 'Presentation Error' 86 | * 'Time Limit Exceeded' 87 | * 'Memory Limit Exceeded' 88 | * 'Wrong Answer' 89 | * 'Runtime Error' 90 | * 'Output Limit Exceeded' 91 | * 'Compile Error' 92 | * 'System Error' 93 | ## 项目整体架构 94 | * 一个判题接收服务:运行在真实服务器上 95 | * kafka消息队列:保存判题任务,让下游服务消费 96 | * docker虚拟服务:运行判题服务消费判题任务,多台负载均衡 97 | 98 | ![架构](imgs/structure.png) 99 | ## 打包 100 | 原本想将项目打包成一个镜像的,但是考虑到kafka的配置,打包成一个镜像实在有些牵强,还是自己配置方便得多。 101 | 102 | 103 | ## 源码说明及个人搭建教程 104 | ### 1.源码结构 105 | * producer:接受外部的POST接口请求,发送到kafka消息对列 106 | * consumer:消费kafka任务,判题后将结果回调到callback中 107 | ### 2.运行环境(linux 环境) 108 | * kakfa:用于producer和consumer之间的通信 109 | * 安装教程:略 110 | ### 3.搭建教程 111 | * clone 此项目 112 | * 修改配置文件 113 | * kafka的地址:spring.kafka.bootstrap-servers=192.168.0.115:9092 114 | * 判题程序编译:用于测试用户时间和内存消耗,是c语言写的,需要编译一下 115 | 命令:g++ judge.c -o judge 116 | * 修改判题文件配置:judge.scriptPath=/home/hadoop/judge/test/judge 117 | * 打包:mvn clean package -DskipTests 118 | * 启动项目: 119 | * java -jar consumer-0.0.1-SNAPSHOT.jar & 120 | * java -jar producer-0.0.1-SNAPSHOT.jar & 121 | * 测试: 122 | ~~~ 123 | 1.PostMan 测试接口:POST http://你的IP:8081/producer/judge.do 124 | 数据为JSON格式,body如下: 125 | { 126 | "proId":15, 127 | "input":["99 1","99 1","99 1"], // 有多少个测试数据数组就多长 128 | "output":["98","100\n","100"], // 对应上面每个输入的标准输出 129 | "timeLimit":1000, 130 | "memoryLimit":65535, 131 | "judgeId":1, 132 | "src":"#include\nint main()\n{\n\tint a,b,sum;\n\tscanf(\"%d %d\",&a,&b);\n\tsum=a+b;\n\tprintf(\"%d\",sum);\n\treturn 0;\n}", 133 | "callBack" :"http://你的IP:8081/producer/result.do" 134 | } 135 | 2.检查返回数据为OK 136 | 3.查看判题回调result接口里面会有日志输出 137 | 2019-09-29 22:03:15 [ http-nio-8081-exec-5:3730303310 ] - [ INFO ] 138 | ************ 139 | 收到任务,将回调到:http://wangzhengyu.cn:8081/producer/result.do?key=111&submitId=12 140 | ************ 141 | 2019-09-29 22:03:18 [ http-nio-8081-exec-2:3730305567 ] - [ INFO ] 142 | ***************** 143 | key: 111 144 | submitId: 12 145 | result: JudgeResult(globalMsg=null, result=[ResultCase(status=1, timeUsed=0, memoryUsed=0, errorMessage=null), ResultCase(status=1, timeUsed=0, memoryUsed=0, errorMessage=null)]) 146 | ***************** 147 | ~~~ 148 | ***如果此项目对您有帮助,希望能给个star!*** 149 | ***如果有爱心人士能给个红包买瓶快乐肥宅水喝也是对我这个小可爱最大的鼓励哟*** 150 | 151 | --------------------------------------------------------------------------------