Browse Source

feat: 把CodeJudgeClient迁移过来

haha 4 years ago
parent
commit
49f6b06e44

+ 60 - 0
codejudge-client/pom.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>SEEC-oj-backend</artifactId>
+        <groupId>cn.seecoder</groupId>
+        <version>0.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>codejudge-client</artifactId>
+
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>20.1.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.11.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jdk8</artifactId>
+            <version>2.11.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-parameter-names</artifactId>
+            <version>2.11.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.11.4</version>
+        </dependency>
+    </dependencies>
+
+    <properties>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+    </properties>
+
+</project>

+ 16 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/CodeJudgeApi.java

@@ -0,0 +1,16 @@
+package cn.seecoder.codejudge.client;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author kunduin
+ */
+public interface CodeJudgeApi {
+    /**
+     * 代码题判题
+     *
+     * @param judgeDTO 判题信息
+     * @return 判题结果
+     */
+    JudgeResult judge(@NotNull JudgeDTO judgeDTO);
+}

+ 140 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/CodeJudgeClient.java

@@ -0,0 +1,140 @@
+package cn.seecoder.codejudge.client;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
+import okhttp3.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.constraints.NotNull;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+/**
+ * @author kunduin
+ */
+public class CodeJudgeClient implements CodeJudgeApi {
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    private final OkHttpClient client;
+    private final ObjectMapper mapper;
+
+    private final String CONFIG_HOST;
+
+    /**
+     * 创建client
+     *
+     * @param host code judge 地址,示例:{@code "http://codejudge.seec.seecoder.cn"}
+     */
+    public CodeJudgeClient(String host) {
+        this.CONFIG_HOST = host;
+        client = new OkHttpClient().newBuilder().connectTimeout(60000, TimeUnit.MILLISECONDS).readTimeout(60000,TimeUnit.MILLISECONDS).build();
+        mapper = JsonMapper.builder()
+                .addModule(new ParameterNamesModule())
+                .addModule(new Jdk8Module())
+                .addModule(new JavaTimeModule())
+                .build();
+    }
+
+    /**
+     * 判题接口
+     *
+     * @param judgeDTO 判题信息
+     * @return 判题结果
+     */
+    @Override
+    public JudgeResult judge(@NotNull JudgeDTO judgeDTO) {
+        HttpUrl httpUrl = createUrlBuilder("/api/judge").build();
+        Response response = post(httpUrl, writeRequestBody(judgeDTO));
+        return getResponseBody(response, JudgeResult.class)
+                .map(judgeResult -> {
+                    if (judgeResult.getMessage() == null) {
+                        return judgeResult;
+                    } else {
+                        throw new CodeJudgeSystemException(judgeResult.getMessage());
+                    }
+                }).orElseThrow(() -> new CodeJudgeSystemException("UN_WRAP"));
+    }
+
+
+    private HttpUrl.Builder createUrlBuilder(final String path) {
+        return Objects.requireNonNull(HttpUrl.parse(CONFIG_HOST + path)).newBuilder();
+    }
+
+    private Response post(HttpUrl httpUrl, RequestBody requestBody) {
+        return requestWithMethod("POST", httpUrl, requestBody);
+    }
+
+    private Response requestWithMethod(String method, HttpUrl httpUrl, RequestBody requestBody) {
+        Request request = new Request.Builder().url(httpUrl).method(method, requestBody).build();
+        try {
+            return client.newCall(request).execute();
+        } catch (IOException e) {
+            logger.error("IOException.", e);
+            throw new CodeJudgeSystemException("IO_EXCEPTION");
+        }
+    }
+
+    private <T> Optional<T> getResponseBody(Response response, Class<T> tClass) {
+        return getResponseBody(
+                response,
+                bodyString -> {
+                    try {
+                        return mapper.readValue(bodyString, tClass);
+                    } catch (JsonProcessingException e) {
+                        logger.error("JsonProcessingException.", e);
+                        throw new CodeJudgeSystemException("JsonProcessingException");
+                    }
+                });
+    }
+
+    private <T> Optional<T> getResponseBody(Response response, TypeReference<T> typeReference) {
+        return getResponseBody(
+                response,
+                bodyString -> {
+                    try {
+                        return mapper.readValue(bodyString, typeReference);
+                    } catch (JsonProcessingException e) {
+                        logger.error("JsonProcessingException.", e);
+                        throw new CodeJudgeSystemException("JsonProcessingException");
+                    }
+                });
+    }
+
+    private <T> Optional<T> getResponseBody(Response response, Function<String, T> mapType) {
+        return Optional.ofNullable(response.body())
+                .map(body -> {
+                    try {
+                        String bodyString = body.string();
+                        return mapType.apply(bodyString);
+                    } catch (IOException e) {
+                        logger.error("IOException.", e);
+                        throw new CodeJudgeSystemException("IOException");
+                    }
+                });
+    }
+
+    private <T> RequestBody writeRequestBody(T obj) {
+        if (obj == null) {
+            return null;
+        }
+
+        try {
+            return RequestBody.create(CodeJudgeConstants.JSON, mapper.writeValueAsString(obj));
+        } catch (JsonProcessingException e) {
+            logger.error("JsonProcessingException.", e);
+            throw new CodeJudgeSystemException("JsonProcessingException");
+        }
+    }
+
+}

+ 13 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/CodeJudgeConstants.java

@@ -0,0 +1,13 @@
+package cn.seecoder.codejudge.client;
+
+import okhttp3.MediaType;
+
+/**
+ * @author kunduin
+ */
+public class CodeJudgeConstants {
+    public final static int PAGE_START = 0;
+
+    public static final MediaType JSON
+            = MediaType.parse("application/json; charset=utf-8");
+}

+ 27 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/CodeJudgeException.java

@@ -0,0 +1,27 @@
+package cn.seecoder.codejudge.client;
+
+
+/**
+ * @author kunduin
+ */
+public class CodeJudgeException extends RuntimeException {
+
+    public static final CodeJudgeException JSON_EXCEPTION = new CodeJudgeException("JSON exception", 101);
+
+    public static final CodeJudgeException IO_EXCEPTION = new CodeJudgeException("IO exception", 102);
+
+    public static final CodeJudgeException UNWRAP_EXCEPTION = new CodeJudgeException("Return false", 102);
+
+    public static final String BIZ_ERROR_CODE = "100";
+
+    private final int code;
+
+    public CodeJudgeException(String message, int code) {
+        super(message);
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}

+ 15 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/CodeJudgeSystemException.java

@@ -0,0 +1,15 @@
+package cn.seecoder.codejudge.client;
+
+/**
+ * @author kunduin
+ */
+public class CodeJudgeSystemException extends RuntimeException {
+
+    public CodeJudgeSystemException(String message) {
+        super(message);
+    }
+
+    public int getCode() {
+        return 500;
+    }
+}

+ 99 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/JudgeDTO.java

@@ -0,0 +1,99 @@
+package cn.seecoder.codejudge.client;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author kunduin
+ */
+public class JudgeDTO {
+    /**
+     * 源代码
+     */
+    private String code;
+
+    /**
+     * 编程语言 {cpp, java, c, python}
+     */
+    private String language;
+
+    /**
+     * 时间限制
+     */
+    private Integer timeLimit;
+
+    /**
+     * 内存限制
+     */
+    private Integer memoryLimit;
+
+    /**
+     * 输入表
+     */
+    private List<String> inputList;
+
+    /**
+     * 输出表
+     */
+    private List<String> outputList;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public Integer getTimeLimit() {
+        return timeLimit;
+    }
+
+    public void setTimeLimit(Integer timeLimit) {
+        this.timeLimit = timeLimit;
+    }
+
+    public Integer getMemoryLimit() {
+        return memoryLimit;
+    }
+
+    public void setMemoryLimit(Integer memoryLimit) {
+        this.memoryLimit = memoryLimit;
+    }
+
+    public List<String> getInputList() {
+        return inputList;
+    }
+
+    public void setInputList(List<String> inputList) {
+        this.inputList = inputList;
+    }
+
+    public List<String> getOutputList() {
+        return outputList;
+    }
+
+    public void setOutputList(List<String> outputList) {
+        this.outputList = outputList;
+    }
+
+    @Override
+    public String toString() {
+        return "JudgeDTO{" +
+                "code='" + code + '\'' +
+                ", language='" + language + '\'' +
+                ", timeLimit=" + timeLimit +
+                ", memoryLimit=" + memoryLimit +
+                ", inputList=" + inputList +
+                ", outputList=" + outputList +
+                '}';
+    }
+}

+ 90 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/JudgeResult.java

@@ -0,0 +1,90 @@
+package cn.seecoder.codejudge.client;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+/**
+ * @author kunduin
+ */
+public class JudgeResult {
+
+    private String message;
+
+    @JsonProperty("result_list")
+    private List<Item> resultList;
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public List<Item> getResultList() {
+        return resultList;
+    }
+
+    public void setResultList(List<Item> resultList) {
+        this.resultList = resultList;
+    }
+
+    @Override
+    public String toString() {
+        return "JudgeResult{" +
+                "message='" + message + '\'' +
+                ", resultList=" + resultList +
+                '}';
+    }
+
+    public static class Item {
+
+        private JudgeResultType result;
+
+        /**
+         * 单位毫秒
+         */
+        @JsonProperty("timeused")
+        private Integer timeUsed;
+
+        /**
+         * 单位kb
+         */
+        @JsonProperty("memoryused")
+        private Integer memoryUsed;
+
+        public JudgeResultType getResult() {
+            return result;
+        }
+
+        public void setResult(JudgeResultType result) {
+            this.result = result;
+        }
+
+        public Integer getTimeUsed() {
+            return timeUsed;
+        }
+
+        public void setTimeUsed(Integer timeUsed) {
+            this.timeUsed = timeUsed;
+        }
+
+        public Integer getMemoryUsed() {
+            return memoryUsed;
+        }
+
+        public void setMemoryUsed(Integer memoryUsed) {
+            this.memoryUsed = memoryUsed;
+        }
+
+        @Override
+        public String toString() {
+            return "Item{" +
+                    "result=" + result +
+                    ", timeUsed=" + timeUsed +
+                    ", memoryUsed=" + memoryUsed +
+                    '}';
+        }
+    }
+}

+ 38 - 0
codejudge-client/src/main/java/cn/seecoder/codejudge/client/JudgeResultType.java

@@ -0,0 +1,38 @@
+package cn.seecoder.codejudge.client;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author kunduin
+ */
+public enum JudgeResultType {
+    /**
+     * 正确
+     */
+    @JsonProperty("Accepted")
+    ACCEPT,
+
+    @JsonProperty("Presentation Error")
+    PRESENTATION_ERROR,
+
+    @JsonProperty("Time Limit Exceeded")
+    TIME_LIMIT_EXCEEDED,
+
+    @JsonProperty("Memory Limit Exceeded")
+    MEMORY_LIMIT_EXCEEDED,
+
+    @JsonProperty("Wrong Answer")
+    WRONG_ANSWER,
+
+    @JsonProperty("Runtime Error")
+    RUNTIME_ERROR,
+
+    @JsonProperty("Output Limit Exceeded")
+    OUTPUT_LIMIT_EXCEEDED,
+
+    @JsonProperty("Compile Error")
+    COMPILE_ERROR,
+
+    @JsonProperty("System Error")
+    SYSTEM_ERROR
+}

+ 1 - 0
pom.xml

@@ -5,6 +5,7 @@
     <modelVersion>4.0.0</modelVersion>
     <modules>
         <module>seec-oj-server</module>
+        <module>codejudge-client</module>
     </modules>
     <parent>
         <groupId>org.springframework.boot</groupId>

+ 17 - 11
seec-oj-server/pom.xml

@@ -32,17 +32,17 @@
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
         </dependency>
-        <dependency>
-            <groupId>cn.seecoder</groupId>
-            <artifactId>codejudge-client</artifactId>
-            <version>0.2.0</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.apache.logging.log4j</groupId>
-                    <artifactId>log4j-slf4j-impl</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>cn.seecoder</groupId>-->
+<!--            <artifactId>codejudge-client</artifactId>-->
+<!--            <version>0.2.0</version>-->
+<!--            <exclusions>-->
+<!--                <exclusion>-->
+<!--                    <groupId>org.apache.logging.log4j</groupId>-->
+<!--                    <artifactId>log4j-slf4j-impl</artifactId>-->
+<!--                </exclusion>-->
+<!--            </exclusions>-->
+<!--        </dependency>-->
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-core</artifactId>
@@ -93,6 +93,12 @@
             <groupId>net.sf.ehcache</groupId>
             <artifactId>ehcache</artifactId>
         </dependency>
+        <dependency>
+            <groupId>cn.seecoder</groupId>
+            <artifactId>codejudge-client</artifactId>
+            <version>0.1.0</version>
+            <scope>compile</scope>
+        </dependency>
 
     </dependencies>
 

+ 0 - 4
seec-oj-server/src/main/java/cn/seecoder/ojserver/manager/QuestionManager.java

@@ -4,10 +4,6 @@ import cn.seecoder.ojserver.dao.ProblemDAO;
 import cn.seecoder.ojserver.dao.entity.Problem;
 import cn.seecoder.ojserver.dao.entity.TestCase;
 import cn.seecoder.ojserver.dao.TestCaseDAO;
-import cn.seecoder.ojserver.exception.ThirdPartyServiceException;
-import cn.seecoder.ojserver.model.vo.CompleteQuestionVO;
-import cn.seecoder.ojserver.utils.thirdparty.QuestionThirdPartyService;
-import org.springframework.cache.annotation.CacheConfig;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 

+ 0 - 90
seec-oj-server/src/main/java/cn/seecoder/ojserver/model/vo/CompleteQuestionVO.java

@@ -1,90 +0,0 @@
-package cn.seecoder.ojserver.model.vo;
-
-import cn.seecoder.bok.common.QuestionType;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author mars
- */
-@AllArgsConstructor
-@NoArgsConstructor
-@Data
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class CompleteQuestionVO implements Serializable {
-    private String id;
-
-    /**
-     * 题干
-     */
-    private String stem;
-
-    /**
-     * 题目类型
-     */
-    private QuestionType type;
-
-    /**
-     * 选项
-     */
-    private Map<String, String> options;
-
-    /**
-     * 填空题 __1__ __2__
-     */
-//    private Map<String, String> blanks;
-
-    /**
-     * 答案
-     */
-    private String answer;
-
-    /**
-     * 关键点
-     */
-    private String keyPoints;
-
-    /**
-     * 分析
-     */
-    private String analysis;
-
-    /**
-     * 标签
-     */
-    private List<String> tags;
-
-    /**
-     * 知识点 id
-     */
-    private List<String> knowledgeId;
-
-    /**
-     * 输入输出的测试用例
-     */
-    private Map<String, String> inputOutputMapping;
-
-
-    /**
-     * 代码题目时间限制
-     */
-    private Integer millisecondLimit;
-
-    /**
-     * 代码空间限制
-     */
-    private Integer memoryLimit;
-
-
-    private Instant createdTime;
-
-    private Instant lastModifiedTime;
-
-}

+ 0 - 21
seec-oj-server/src/main/java/cn/seecoder/ojserver/utils/thirdparty/QuestionThirdPartyService.java

@@ -1,21 +0,0 @@
-package cn.seecoder.ojserver.utils.thirdparty;
-
-import cn.seecoder.ojserver.model.vo.CompleteQuestionVO;
-
-import java.util.List;
-import java.util.Optional;
-
-/**
- * 封装调用的从题库拿题的第三方服务
- * 参考 http://gogs.seec.seecoder.cn/SEEC-BOK/SEEC-BOK-CLIENT/src/master/seecoder-bok-client/src/main/java/cn/seecoder/bok/client 编写
- * @author mars
- */
-public interface QuestionThirdPartyService {
-    /**
-     * 根据id从题库系统获得题目
-     * @param id 题目id
-     * @return QuestionVO
-     * @see CompleteQuestionVO
-     */
-    Optional<CompleteQuestionVO> getQuestionById(String id);
-}

+ 0 - 39
seec-oj-server/src/main/java/cn/seecoder/ojserver/utils/thirdparty/impl/QuestionThirdPartyServiceImpl.java

@@ -1,39 +0,0 @@
-package cn.seecoder.ojserver.utils.thirdparty.impl;
-
-import cn.seecoder.bok.client.SeecoderBokClient;
-import cn.seecoder.bok.common.vo.QuestionVO;
-import cn.seecoder.ojserver.model.vo.CompleteQuestionVO;
-import cn.seecoder.ojserver.utils.thirdparty.QuestionThirdPartyService;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import java.util.Optional;
-
-/**
- * @author mars
- * 封装调用的题库的第三方服务
- */
-@Component
-public class QuestionThirdPartyServiceImpl implements QuestionThirdPartyService {
-    @Value("${seec-bok-client.host}")
-    private String host;
-
-    private SeecoderBokClient client;
-
-
-    @PostConstruct
-    public void init() {
-        client = new SeecoderBokClient(host);
-    }
-
-
-    @Override
-    public Optional<CompleteQuestionVO> getQuestionById(String id) {
-        Optional<QuestionVO> response = client.getQuestionById(id);
-        CompleteQuestionVO res = new CompleteQuestionVO();
-        response.ifPresent(questionVO -> BeanUtils.copyProperties(questionVO, res));
-        return Optional.of(res);
-    }
-}