parent
f106919d74
commit
4f2e5d13d9
@ -0,0 +1,18 @@
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings/
|
||||
/target/
|
||||
/.idea
|
||||
*.iml
|
||||
.idea
|
||||
*.project
|
||||
*.classpath
|
||||
.metadata
|
||||
.settings
|
||||
**/**/target
|
||||
*.factorypath
|
||||
out/
|
||||
logs/
|
||||
*.DS_Store
|
||||
logs/
|
||||
log/
|
@ -0,0 +1,97 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.educoder</groupId>
|
||||
<artifactId>automated_evaluation</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<description>自动化评测接口异常通知</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.6</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<hutool.version>5.8.0.M2</hutool.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.47</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.79</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.22</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,29 @@
|
||||
package net.educoder;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description: 启动类
|
||||
*/
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
public class AutomatedEvaluationApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AutomatedEvaluationApplication.class, args);
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String hello() {
|
||||
return "hello";
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package net.educoder.common;
|
||||
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description: 钉钉机器人发消息.
|
||||
*/
|
||||
@Slf4j
|
||||
public class DingTalk {
|
||||
|
||||
private String token;
|
||||
private String secret;
|
||||
|
||||
public DingTalk(String token, String secret) {
|
||||
this.token = token;
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送钉钉消息.
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @return string
|
||||
*/
|
||||
public String sendMessage(String message) {
|
||||
String url = getUrl();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
//固定参数
|
||||
jsonObject.put("msgtype", "text");
|
||||
JSONObject content = new JSONObject();
|
||||
//此处message是你想要发送到钉钉的信息
|
||||
content.put("content", message);
|
||||
jsonObject.put("text", content);
|
||||
try {
|
||||
return HttpUtil.post(url, jsonObject.toJSONString());
|
||||
} catch (Exception e) {
|
||||
log.error("发送钉钉消息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getUrl() {
|
||||
|
||||
String baseUrl = "https://oapi.dingtalk.com/robot/send?access_token=";
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String stringToSign = timestamp + "\n" + secret;
|
||||
// MAC加密算法
|
||||
Mac mac = null;
|
||||
try {
|
||||
mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
||||
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||
return baseUrl + token + "×tamp=" + timestamp + "&sign=" +
|
||||
URLEncoder.encode(Base64.encode(signData), "UTF-8");
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package net.educoder.config;
|
||||
|
||||
import net.educoder.common.DingTalk;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description: 配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Autowired
|
||||
private PropertiesConfig propertiesConfig;
|
||||
|
||||
@Bean("dingTalkEvaluation")
|
||||
public DingTalk dingTalkEvaluation() {
|
||||
return new DingTalk(propertiesConfig.getToken(), propertiesConfig.getSecret());
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步线程池配置
|
||||
* @return
|
||||
*/
|
||||
@Bean("taskExecutor")
|
||||
public ThreadPoolTaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 设置核心线程数
|
||||
executor.setCorePoolSize(50);
|
||||
// 设置最大线程数
|
||||
executor.setMaxPoolSize(50);
|
||||
// 设置队列容量
|
||||
executor.setQueueCapacity(200);
|
||||
// 设置线程活跃时间(秒)
|
||||
executor.setKeepAliveSeconds(10);
|
||||
// 设置默认线程名称
|
||||
executor.setThreadNamePrefix("task-");
|
||||
// 设置拒绝策略
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
// 等待所有任务结束后再关闭线程池
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
return executor;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.educoder.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description:
|
||||
*/
|
||||
@Configuration
|
||||
public class PropertiesConfig {
|
||||
|
||||
@Value("${evaluation.token}")
|
||||
private String token;
|
||||
|
||||
@Value("${evaluation.secret}")
|
||||
private String secret;
|
||||
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package net.educoder.dao;
|
||||
|
||||
import net.educoder.model.AutoEvaParamConfig;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description:
|
||||
*/
|
||||
public interface AutoEvaParamConfigRepository extends JpaRepository<AutoEvaParamConfig,Long> {
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package net.educoder.model;
|
||||
|
||||
import org.hibernate.annotations.Table;
|
||||
|
||||
import javax.annotation.Generated;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import java.util.Date;
|
||||
|
||||
@Entity
|
||||
public class AutoEvaParamConfig {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private Integer type;
|
||||
|
||||
private String tpiId;
|
||||
|
||||
private String tpiGitUrl;
|
||||
|
||||
private String buildId;
|
||||
|
||||
private String testCases;
|
||||
|
||||
private String extras;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String codeFileContent;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Integer type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getTpiId() {
|
||||
return tpiId;
|
||||
}
|
||||
|
||||
public void setTpiId(String tpiId) {
|
||||
this.tpiId = tpiId == null ? null : tpiId.trim();
|
||||
}
|
||||
|
||||
public String getTpiGitUrl() {
|
||||
return tpiGitUrl;
|
||||
}
|
||||
|
||||
public void setTpiGitUrl(String tpiGitUrl) {
|
||||
this.tpiGitUrl = tpiGitUrl == null ? null : tpiGitUrl.trim();
|
||||
}
|
||||
|
||||
public String getBuildId() {
|
||||
return buildId;
|
||||
}
|
||||
|
||||
public void setBuildId(String buildId) {
|
||||
this.buildId = buildId == null ? null : buildId.trim();
|
||||
}
|
||||
|
||||
public String getTestCases() {
|
||||
return testCases;
|
||||
}
|
||||
|
||||
public void setTestCases(String testCases) {
|
||||
this.testCases = testCases == null ? null : testCases.trim();
|
||||
}
|
||||
|
||||
public String getExtras() {
|
||||
return extras;
|
||||
}
|
||||
|
||||
public void setExtras(String extras) {
|
||||
this.extras = extras == null ? null : extras.trim();
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getCodeFileContent() {
|
||||
return codeFileContent;
|
||||
}
|
||||
|
||||
public void setCodeFileContent(String codeFileContent) {
|
||||
this.codeFileContent = codeFileContent == null ? null : codeFileContent.trim();
|
||||
}
|
||||
|
||||
public static final Integer SX_EVA = 0;
|
||||
public static final Integer OJ_EVA = 1;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.educoder.service;
|
||||
|
||||
import net.educoder.dao.AutoEvaParamConfigRepository;
|
||||
import net.educoder.model.AutoEvaParamConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description:
|
||||
*/
|
||||
@Service
|
||||
public class AutoEvaParamConfigService {
|
||||
|
||||
@Autowired
|
||||
private AutoEvaParamConfigRepository autoEvaParamConfigRepository;
|
||||
|
||||
|
||||
public List<AutoEvaParamConfig> findAll() {
|
||||
return autoEvaParamConfigRepository.findAll();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package net.educoder.shedule;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.educoder.model.AutoEvaParamConfig;
|
||||
import net.educoder.service.AutoEvaParamConfigService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @Author: youys
|
||||
* @Date: 2022/4/2
|
||||
* @Description: 评测检查告警任务
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class EvaCheckWarningTask {
|
||||
|
||||
|
||||
@Value("${bridge.evaluation}")
|
||||
private String gameEvaluationUrl;
|
||||
|
||||
@Value("${bridge.ojEvaluation}")
|
||||
private String ojEvaluationUrl;
|
||||
|
||||
@Value("${bridge.callbackUrl}")
|
||||
private String callbackUrl;
|
||||
|
||||
|
||||
@Autowired
|
||||
private AutoEvaParamConfigService autoEvaParamConfigService;
|
||||
|
||||
@Async
|
||||
@Scheduled(initialDelay = 5 * 1000, fixedRate = 30 * 1000)
|
||||
public void check() {
|
||||
log.info("自动化评测接口告警检查---------start ");
|
||||
List<AutoEvaParamConfig> autoEvaParamConfigList = autoEvaParamConfigService.findAll();
|
||||
log.info(JSONObject.toJSONString(autoEvaParamConfigList));
|
||||
|
||||
for (AutoEvaParamConfig autoEvaParamConfig : autoEvaParamConfigList) {
|
||||
try {
|
||||
if (autoEvaParamConfig.getType() == 0) {
|
||||
String extras = autoEvaParamConfig.getExtras();
|
||||
if (!StringUtils.hasLength(extras)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
postEvaluation(autoEvaParamConfig);
|
||||
} else if (autoEvaParamConfig.getType() == 1) {
|
||||
|
||||
if (!StringUtils.hasLength(autoEvaParamConfig.getCodeFileContent())) {
|
||||
continue;
|
||||
}
|
||||
postOjEvaluation(autoEvaParamConfig);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("自动化评测接口告警检查任务异常", e);
|
||||
}
|
||||
}
|
||||
log.info("自动化评测接口告警检查 ---------end ");
|
||||
}
|
||||
|
||||
|
||||
private void postEvaluation(AutoEvaParamConfig autoEvaParamConfig) {
|
||||
JSONObject extrasObject = JSONObject.parseObject(autoEvaParamConfig.getExtras());
|
||||
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("isPublished", extrasObject.getInteger("isPublished"));
|
||||
param.put("trimBlank", extrasObject.getInteger("trimBlank"));
|
||||
param.put("containers", extrasObject.getString("containers"));
|
||||
param.put("instanceChallenge", extrasObject.getString("instanceChallenge"));
|
||||
param.put("tpmScript", extrasObject.getString("tpmScript"));
|
||||
param.put("timeLimit", extrasObject.getInteger("timeLimit"));
|
||||
param.put("times", extrasObject.getInteger("times"));
|
||||
param.put("resubmit", extrasObject.getInteger("resubmit"));
|
||||
param.put("podType", extrasObject.getInteger("podType"));
|
||||
param.put("content_modified", extrasObject.getInteger("content_modified"));
|
||||
param.put("tpiID", autoEvaParamConfig.getTpiId());
|
||||
param.put("testCases", autoEvaParamConfig.getTestCases());
|
||||
param.put("tpiGitURL", autoEvaParamConfig.getTpiGitUrl());
|
||||
param.put("buildID", autoEvaParamConfig.getBuildId());
|
||||
param.put("sec_key", UUID.randomUUID().toString());
|
||||
param.put("callBackUrl", callbackUrl);
|
||||
String result = HttpUtil.post(gameEvaluationUrl, param);
|
||||
JSONObject jsonResult = JSONObject.parseObject(result);
|
||||
log.info("实训评测接口返回:{},tpiId:{}", jsonResult, autoEvaParamConfig.getTpiId());
|
||||
}
|
||||
|
||||
private void postOjEvaluation(AutoEvaParamConfig autoEvaParamConfig) {
|
||||
Map<String, Object> param = new HashMap<>(8);
|
||||
param.put("tpiID", autoEvaParamConfig.getTpiId());
|
||||
param.put("testCases", autoEvaParamConfig.getTestCases());
|
||||
param.put("codeFileContent", autoEvaParamConfig.getCodeFileContent());
|
||||
param.put("sec_key", UUID.randomUUID().toString());
|
||||
param.put("callBackUrl", callbackUrl);
|
||||
String result = HttpUtil.post(ojEvaluationUrl, param);
|
||||
JSONObject jsonResult = JSONObject.parseObject(result);
|
||||
log.info("Oj评测接口返回:{},tpiId:{}", jsonResult, autoEvaParamConfig.getTpiId());
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
## 评测钉钉机器人配置
|
||||
evaluation:
|
||||
token: 1069c45d4dfab187bb95599faeaf3687b630f79eda0d6fff914a18ee9e25db6f
|
||||
secret: SEC7431097248ee9c19b9d7a2c61883e29082bea79c88c3e8f02e5fa121c2837dbc
|
||||
|
||||
bridge:
|
||||
evaluation: http://pre-bridge.educoder.net/bridge/game/gameEvaluate
|
||||
ojEvaluation: http://pre-bridge.educoder.net/bridge/ojs/evaluate
|
||||
callbackUrl: http://1c32-120-228-142-52.ngrok.io/callback/evaluation
|
@ -0,0 +1,9 @@
|
||||
## 评测钉钉机器人配置
|
||||
evaluation:
|
||||
token: 1069c45d4dfab187bb95599faeaf3687b630f79eda0d6fff914a18ee9e25db6f
|
||||
secret: SEC7431097248ee9c19b9d7a2c61883e29082bea79c88c3e8f02e5fa121c2837dbc
|
||||
|
||||
bridge:
|
||||
evaluation: https://www.educoder.net/bridge/game/gameEvaluate
|
||||
ojEvaluation: https://www.educoder.net/bridge/ojs/evaluate
|
||||
callbackUrl: https://1c32-120-228-142-52.ngrok.io/callback/evaluation
|
@ -0,0 +1,25 @@
|
||||
server:
|
||||
port: 8002
|
||||
servlet:
|
||||
context-path: /
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
# 数据库配置
|
||||
datasource:
|
||||
url: jdbc:mysql://rm-bp13v5020p7828r5rso.mysql.rds.aliyuncs.com:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
|
||||
username: testeducoder
|
||||
password: TEST@123
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
initialSize: 50
|
||||
minIdle: 50
|
||||
maxActive: 100
|
||||
validationQuery: SELECT 1
|
||||
# redis配置
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password:
|
||||
|
Loading…
Reference in new issue