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 Optional getResponseBody(Response response, Class tClass) { return getResponseBody( response, bodyString -> { try { return mapper.readValue(bodyString, tClass); } catch (JsonProcessingException e) { logger.error("JsonProcessingException.", e); throw new CodeJudgeSystemException("JsonProcessingException"); } }); } private Optional getResponseBody(Response response, TypeReference typeReference) { return getResponseBody( response, bodyString -> { try { return mapper.readValue(bodyString, typeReference); } catch (JsonProcessingException e) { logger.error("JsonProcessingException.", e); throw new CodeJudgeSystemException("JsonProcessingException"); } }); } private Optional getResponseBody(Response response, Function 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 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"); } } }