new_educoder_dev merge dev
This commit is contained in:
commit
dd403ecc32
|
@ -8,5 +8,4 @@ target/
|
|||
.settings/
|
||||
*.log
|
||||
bin/
|
||||
src/test/
|
||||
src/main/java/test/
|
68
pom.xml
68
pom.xml
|
@ -128,6 +128,11 @@
|
|||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
|
@ -145,9 +150,20 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>4.3.6.RELEASE</version>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
|
@ -165,6 +181,12 @@
|
|||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-crypto-hash</artifactId>
|
||||
<version>1.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- logback -->
|
||||
<dependency>
|
||||
|
@ -212,7 +234,49 @@
|
|||
<artifactId>quartz-jobs</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
<version>4.1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore-nio</artifactId>
|
||||
<version>4.4.9</version>
|
||||
</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.1.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>5.1.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.educoder.bridge.alarm.constant;
|
||||
|
||||
public interface AlarmCsts {
|
||||
/**
|
||||
* 告警规则:启用
|
||||
*/
|
||||
String ALARM_RULE_ENABLE = "1";
|
||||
/**
|
||||
* 告警规则:停用
|
||||
*/
|
||||
String ALARM_RULE_DISABLE = "0";
|
||||
|
||||
/**
|
||||
* 消防警察:启用
|
||||
*/
|
||||
String FIRE_POLICE_ENABLE = "1";
|
||||
/**
|
||||
* 消防警察:停用
|
||||
*/
|
||||
String FIRE_POLICE_DISABLE = "0";
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.educoder.bridge.alarm.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.alarm.model.Alarm;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* 告警相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "告警", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/alarms")
|
||||
public class AlarmController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 获取告警列表
|
||||
*/
|
||||
@RequestMapping(path = "/list", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "获取告警列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<List<Alarm>> getAlarms() throws Exception {
|
||||
logger.info("获取告警列表");
|
||||
|
||||
ApiResult<List<Alarm>> result = new ApiResult<>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改告警
|
||||
*/
|
||||
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
|
||||
@ApiOperation(value = "修改告警", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<Alarm> updateAlarms(@PathVariable("id") String id, @RequestBody Alarm Alarm) throws Exception {
|
||||
logger.info("修改告警{}", id);
|
||||
|
||||
ApiResult<Alarm> result = new ApiResult<>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.educoder.bridge.alarm.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.alarm.model.AlarmRule;
|
||||
import com.educoder.bridge.alarm.service.AlarmService;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* 告警规则相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "告警规则", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/alarmrules")
|
||||
public class AlarmRuleController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
@Autowired
|
||||
private AlarmService alarmService;
|
||||
|
||||
/**
|
||||
* 获取告警规则列表
|
||||
*/
|
||||
@RequestMapping(path = "/list", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "获取告警规则列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<List<AlarmRule>> getAlarmRules(@RequestBody(required = false) Map<String, Object> param)
|
||||
throws Exception {
|
||||
logger.info("获取告警规则列表");
|
||||
|
||||
ApiResult<List<AlarmRule>> result = new ApiResult<>();
|
||||
List<AlarmRule> list = alarmService.getAlarmRules(param);
|
||||
result.setData(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建告警规则
|
||||
*/
|
||||
@RequestMapping(path = "", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "创建告警规则", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<AlarmRule> createAlarmRules(@RequestBody AlarmRule alarmRule) throws Exception {
|
||||
logger.info("创建告警规则[{}]阈值[{}]", alarmRule.getName(), alarmRule.getThreshold());
|
||||
|
||||
ApiResult<AlarmRule> result = new ApiResult<>();
|
||||
alarmRule = alarmService.createAlarmRule(alarmRule);
|
||||
result.setData(alarmRule);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改告警规则
|
||||
*/
|
||||
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
|
||||
@ApiOperation(value = "修改告警规则", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<AlarmRule> updateAlarmRules(@PathVariable("id") String id, @RequestBody AlarmRule alarmRule)
|
||||
throws Exception {
|
||||
logger.info("修改告警规则{}", id);
|
||||
|
||||
ApiResult<AlarmRule> result = new ApiResult<>();
|
||||
alarmRule.setId(Long.parseLong(id));
|
||||
alarmRule = alarmService.updateAlarmRule(alarmRule);
|
||||
result.setData(alarmRule);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.educoder.bridge.alarm.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.alarm.model.FirePolice;
|
||||
import com.educoder.bridge.alarm.service.FirePoliceService;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* 告警人员相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "告警人员", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/firepolices")
|
||||
public class FirePoliceController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
private FirePoliceService firePoliceService;
|
||||
|
||||
/**
|
||||
* 获取告警人员列表
|
||||
*/
|
||||
@RequestMapping(path = "/list", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "获取告警人员列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<List<FirePolice>> getFirePolices(@RequestBody(required = false) Map<String, Object> param)
|
||||
throws Exception {
|
||||
logger.info("获取告警人员列表");
|
||||
|
||||
ApiResult<List<FirePolice>> result = new ApiResult<>();
|
||||
List<FirePolice> list = firePoliceService.getFirePolices(param);
|
||||
result.setData(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建告警人员
|
||||
*/
|
||||
@RequestMapping(path = "", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "创建告警人员", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<FirePolice> createFirePolices(@RequestBody FirePolice firePolice) throws Exception {
|
||||
logger.info("创建告警人员");
|
||||
|
||||
ApiResult<FirePolice> result = new ApiResult<>();
|
||||
firePolice = firePoliceService.createFirePolice(firePolice);
|
||||
result.setData(firePolice);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改告警人员
|
||||
*/
|
||||
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
|
||||
@ApiOperation(value = "修改告警人员", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<FirePolice> updateFirePolices(@PathVariable("id") String id, @RequestBody FirePolice firePolice)
|
||||
throws Exception {
|
||||
logger.info("修改告警人员{}", id);
|
||||
|
||||
ApiResult<FirePolice> result = new ApiResult<>();
|
||||
firePolice.setId(Long.parseLong(id));
|
||||
firePolice = firePoliceService.updateFirePolice(firePolice);
|
||||
result.setData(firePolice);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.educoder.bridge.alarm.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.educoder.bridge.alarm.model.AlarmRule;
|
||||
|
||||
public interface AlarmRuleMapper {
|
||||
int deleteByPrimaryKey(Long id);
|
||||
|
||||
int insert(AlarmRule record);
|
||||
|
||||
int insertSelective(AlarmRule record);
|
||||
|
||||
AlarmRule selectByPrimaryKey(Long id);
|
||||
|
||||
int updateByPrimaryKeySelective(AlarmRule record);
|
||||
|
||||
int updateByPrimaryKey(AlarmRule record);
|
||||
|
||||
List<AlarmRule> selectAlarmRule(Map<String, Object> param);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.educoder.bridge.alarm.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.educoder.bridge.alarm.model.FirePolice;
|
||||
|
||||
public interface FirePoliceMapper {
|
||||
int deleteByPrimaryKey(Long id);
|
||||
|
||||
int insert(FirePolice record);
|
||||
|
||||
int insertSelective(FirePolice record);
|
||||
|
||||
FirePolice selectByPrimaryKey(Long id);
|
||||
|
||||
int updateByPrimaryKeySelective(FirePolice record);
|
||||
|
||||
int updateByPrimaryKey(FirePolice record);
|
||||
|
||||
List<FirePolice> selectFirePolice(Map<String, Object> param);
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.educoder.bridge.alarm.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "告警", description = "告警")
|
||||
public class Alarm {
|
||||
@ApiModelProperty(value = "告警id")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "告警名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "告警阈值")
|
||||
private String threshold;
|
||||
@ApiModelProperty(value = "告警方式")
|
||||
private AlarmWay alarmWay;
|
||||
|
||||
@ApiModelProperty(value = "告警值")
|
||||
private String val;
|
||||
|
||||
@ApiModelProperty(value = "规则创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty(value = "规则更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
@ApiModelProperty(value = "告警状态:0,创建; 1,发送成功; 2,处理成功")
|
||||
private String status;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(String threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public AlarmWay getAlarmWay() {
|
||||
return alarmWay;
|
||||
}
|
||||
|
||||
public void setAlarmWay(AlarmWay alarmWay) {
|
||||
this.alarmWay = alarmWay;
|
||||
}
|
||||
|
||||
public String getVal() {
|
||||
return val;
|
||||
}
|
||||
|
||||
public void setVal(String val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.educoder.bridge.alarm.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "告警规则", description = "告警规则")
|
||||
public class AlarmRule {
|
||||
@ApiModelProperty(value = "告警规则id")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "告警规则名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "告警阈值")
|
||||
private String threshold;
|
||||
@ApiModelProperty(value = "告警方式")
|
||||
private AlarmWay alarmWay;
|
||||
|
||||
@ApiModelProperty(value = "规则创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty(value = "规则更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty(value = "告警状态:0,停用; 1,启用.")
|
||||
private String status;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(String threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public AlarmWay getAlarmWay() {
|
||||
return alarmWay;
|
||||
}
|
||||
|
||||
public void setAlarmWay(AlarmWay alarmWay) {
|
||||
this.alarmWay = alarmWay;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.educoder.bridge.alarm.model;
|
||||
|
||||
public enum AlarmWay {
|
||||
|
||||
EMAIL, MOBILE;
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.educoder.bridge.alarm.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "消防警察", description = "消防警察")
|
||||
public class FirePolice {
|
||||
@ApiModelProperty(value = "告警规则id")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
private String email;
|
||||
@ApiModelProperty(value = "手机")
|
||||
private String mobile;
|
||||
|
||||
@ApiModelProperty(value = "规则创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty(value = "规则更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty(value = "告警状态:0,停用; 1,启用.")
|
||||
private String status;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.educoder.bridge.alarm.service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.alarm.constant.AlarmCsts;
|
||||
import com.educoder.bridge.alarm.dao.AlarmRuleMapper;
|
||||
import com.educoder.bridge.alarm.model.AlarmRule;
|
||||
|
||||
@Service
|
||||
public class AlarmService {
|
||||
|
||||
@Autowired
|
||||
private AlarmRuleMapper alarmRuleMapper;
|
||||
|
||||
public List<AlarmRule> getAlarmRules(Map<String,Object > param) {
|
||||
|
||||
return alarmRuleMapper.selectAlarmRule(param);
|
||||
}
|
||||
|
||||
public AlarmRule createAlarmRule(AlarmRule alarmRule) {
|
||||
alarmRule.setCreateTime(LocalDateTime.now());
|
||||
alarmRule.setUpdateTime(LocalDateTime.now());
|
||||
alarmRule.setStatus(AlarmCsts.ALARM_RULE_ENABLE);
|
||||
alarmRuleMapper.insert(alarmRule);
|
||||
return alarmRuleMapper.selectByPrimaryKey(alarmRule.getId());
|
||||
}
|
||||
|
||||
public AlarmRule updateAlarmRule(AlarmRule alarmRule) {
|
||||
alarmRule.setUpdateTime(LocalDateTime.now());
|
||||
alarmRuleMapper.updateByPrimaryKeySelective(alarmRule);
|
||||
return alarmRuleMapper.selectByPrimaryKey(alarmRule.getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.educoder.bridge.alarm.service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.alarm.constant.AlarmCsts;
|
||||
import com.educoder.bridge.alarm.dao.FirePoliceMapper;
|
||||
import com.educoder.bridge.alarm.model.FirePolice;
|
||||
|
||||
@Service
|
||||
public class FirePoliceService {
|
||||
|
||||
@Autowired
|
||||
private FirePoliceMapper FirePoliceMapper;
|
||||
|
||||
public List<FirePolice> getFirePolices(Map<String, Object> param) {
|
||||
|
||||
return FirePoliceMapper.selectFirePolice(param);
|
||||
}
|
||||
|
||||
public FirePolice createFirePolice(FirePolice firePolice) {
|
||||
firePolice.setCreateTime(LocalDateTime.now());
|
||||
firePolice.setUpdateTime(LocalDateTime.now());
|
||||
firePolice.setStatus(AlarmCsts.FIRE_POLICE_ENABLE);
|
||||
FirePoliceMapper.insert(firePolice);
|
||||
return FirePoliceMapper.selectByPrimaryKey(firePolice.getId());
|
||||
}
|
||||
|
||||
public FirePolice updateFirePolice(FirePolice firePolice) {
|
||||
firePolice.setUpdateTime(LocalDateTime.now());
|
||||
FirePoliceMapper.updateByPrimaryKeySelective(firePolice);
|
||||
return FirePoliceMapper.selectByPrimaryKey(firePolice.getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.educoder.bridge.common.constant;
|
||||
|
||||
public interface ApiResultCodeCsts {
|
||||
int SUCCESS = 0;
|
||||
int FAIL = -1;
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.educoder.bridge.common.constant;
|
||||
|
||||
public interface BuildResultCsts {
|
||||
|
||||
/**
|
||||
* 完整结果正则。
|
||||
*
|
||||
*/
|
||||
// \{ 匹配 { , [\s]* 匹配0-多个空白字符, "compileResult"[\s]*:匹配"compileResult":
|
||||
// [\s\S]*匹配0-多个任意字符, [\s\S]*"out"[\s]*:匹配"out": , [^}]*匹配除}之外的所有字符
|
||||
String FULL_RESULT_REG = "\\{[\\s]*\"compileResult\"[\\s]*:[\\s\\S]*\"out\"[\\s]*:[^}]*}";
|
||||
|
||||
/**
|
||||
* 文本消息前缀
|
||||
*/
|
||||
String TEXT_RESULT_PRE = "educoder:";
|
||||
|
||||
/**
|
||||
* 文本消息前缀长度
|
||||
*/
|
||||
int TEXT_RESULT_PRE_LEN = TEXT_RESULT_PRE.length();
|
||||
|
||||
String DOWNLOAD_STATUS = "downloadStatus";
|
||||
String DOWNLOAD_STATUS_SUCCESS = "1";
|
||||
String DOWNLOAD_STATUS_FAIL = "0";
|
||||
|
||||
String CREATE_POD_STATUS = "createPodStatus";
|
||||
String CREATE_POD_STATUS_SUCCESS = "1";
|
||||
String CREATE_POD_STATUS_FAIL = "0";
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package com.educoder.bridge.common.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
/**
|
||||
* @author lqk
|
||||
* @version 0.1
|
||||
*/
|
||||
public class BaseController {
|
||||
protected HttpServletRequest request;
|
||||
protected HttpServletResponse response;
|
||||
protected HttpSession session;
|
||||
protected final static Logger logger = LoggerFactory.getLogger(BaseController.class);
|
||||
|
||||
@ModelAttribute
|
||||
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.session = request.getSession();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.educoder.bridge.common.model;
|
||||
|
||||
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
|
||||
|
||||
public class ApiResult<T> {
|
||||
|
||||
private int code = ApiResultCodeCsts.SUCCESS;
|
||||
private String msg;
|
||||
|
||||
private T data;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.educoder.bridge.common.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
|
||||
public class BridgePage<T> {
|
||||
|
||||
private List<T> data;
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
private Long total;
|
||||
|
||||
public BridgePage(Page<T> page) {
|
||||
this.data = page.getResult();
|
||||
this.pageNum = page.getPageNum();
|
||||
this.pageSize = page.getPageSize();
|
||||
this.total = page.getTotal();
|
||||
}
|
||||
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<T> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,151 +11,154 @@ import org.springframework.context.annotation.PropertySource;
|
|||
@PropertySource("classpath:config_${spring.profiles.active}.properties")
|
||||
public class AppConfig {
|
||||
|
||||
@Value("${educoderURL}")
|
||||
private String educoderURL;
|
||||
@Value("${educoderURL}")
|
||||
private String educoderURL;
|
||||
|
||||
@Value("${workspace}")
|
||||
private String workspace;
|
||||
@Value("${simpileEducoderURL}")
|
||||
private String simpileEducoderURL;
|
||||
|
||||
@Value("${maxRunningPodNum}")
|
||||
private String maxRunningPodNum;
|
||||
@Value("${workspace}")
|
||||
private String workspace;
|
||||
|
||||
@Value("${defaultTimeLimit}")
|
||||
private String defaultTimeLimit;
|
||||
@Value("${maxRunningPodNum}")
|
||||
private String maxRunningPodNum;
|
||||
|
||||
@Value("${k8sServer}")
|
||||
private String k8sServer;
|
||||
@Value("${k8sUser}")
|
||||
private String k8sUser;
|
||||
@Value("${k8sPasswd}")
|
||||
private String k8sPasswd;
|
||||
@Value("${defaultTimeLimit}")
|
||||
private String defaultTimeLimit;
|
||||
|
||||
@Value("${dockerMaster}")
|
||||
private String dockerMaster;
|
||||
@Value("${dockerDeputies}")
|
||||
private String dockerDeputies;
|
||||
@Value("${registry}")
|
||||
private String registry;
|
||||
@Value("${k8sServer}")
|
||||
private String k8sServer;
|
||||
@Value("${k8sUser}")
|
||||
private String k8sUser;
|
||||
@Value("${k8sPasswd}")
|
||||
private String k8sPasswd;
|
||||
|
||||
@Value("${cpuAllocatable}")
|
||||
private String cpuAllocatable;
|
||||
@Value("${memAllocatable}")
|
||||
private String memAllocatable;
|
||||
@Value("${dockerMaster}")
|
||||
private String dockerMaster;
|
||||
@Value("${dockerDeputies}")
|
||||
private String dockerDeputies;
|
||||
@Value("${registry}")
|
||||
private String registry;
|
||||
|
||||
@Value("${gitIP}")
|
||||
private String gitIP;
|
||||
@Value("${cpuAllocatable}")
|
||||
private String cpuAllocatable;
|
||||
@Value("${memAllocatable}")
|
||||
private String memAllocatable;
|
||||
|
||||
@Value("${gitIP}")
|
||||
private String gitIP;
|
||||
|
||||
@Value("${gitBackUpIP}")
|
||||
private String gitBackUpIP;
|
||||
|
||||
@Value("${outputSize}")
|
||||
private String outputSize;
|
||||
|
||||
@Value("${secretKey}")
|
||||
private String secretKey;
|
||||
@Value("${secretKey}")
|
||||
private String secretKey;
|
||||
|
||||
@Value("${websocket.addr}")
|
||||
private String serverUrl;
|
||||
@Value("${websocket.addr}")
|
||||
private String serverUrl;
|
||||
|
||||
@Value("${gpuImage}")
|
||||
private String gpuImage;
|
||||
@Value("${gpuImage}")
|
||||
private String gpuImage;
|
||||
|
||||
@Value("${gitUsername}")
|
||||
private String gitUsername;
|
||||
@Value("${vncPort}")
|
||||
private Integer vncPort;
|
||||
|
||||
@Value("${gitPassword}")
|
||||
private String gitPassword;
|
||||
public String getServerUrl() {
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
public String getServerUrl() {
|
||||
return serverUrl;
|
||||
public void setServerUrl(String serverUrl) {
|
||||
this.serverUrl = serverUrl;
|
||||
}
|
||||
|
||||
public String getEducoderURL() {
|
||||
return educoderURL;
|
||||
}
|
||||
|
||||
public String getSimpileEducoderURL() {
|
||||
return simpileEducoderURL;
|
||||
}
|
||||
|
||||
public String getWorkspace() {
|
||||
return workspace;
|
||||
}
|
||||
|
||||
public String getMaxRunningPodNum() {
|
||||
return maxRunningPodNum;
|
||||
}
|
||||
|
||||
public String getDefaultTimeLimit() {
|
||||
return defaultTimeLimit;
|
||||
}
|
||||
|
||||
public String getK8sServer() {
|
||||
return k8sServer;
|
||||
}
|
||||
|
||||
public String getK8sUser() {
|
||||
return k8sUser;
|
||||
}
|
||||
|
||||
public String getK8sPasswd() {
|
||||
return k8sPasswd;
|
||||
}
|
||||
|
||||
public String getCpuAllocatable() {
|
||||
return cpuAllocatable;
|
||||
}
|
||||
|
||||
public String getMemAllocatable() {
|
||||
return memAllocatable;
|
||||
}
|
||||
|
||||
public String getGitBackUpIP() {
|
||||
return gitBackUpIP;
|
||||
}
|
||||
|
||||
public void setServerUrl(String serverUrl) {
|
||||
this.serverUrl = serverUrl;
|
||||
}
|
||||
public String getGitIP() {
|
||||
return gitIP;
|
||||
}
|
||||
|
||||
public String getEducoderURL() {
|
||||
return educoderURL;
|
||||
}
|
||||
public String getDockerMaster() {
|
||||
return dockerMaster;
|
||||
}
|
||||
|
||||
public String getWorkspace() {
|
||||
return workspace;
|
||||
}
|
||||
public String getDockerDeputies() {
|
||||
return dockerDeputies;
|
||||
}
|
||||
|
||||
public String getMaxRunningPodNum() {
|
||||
return maxRunningPodNum;
|
||||
}
|
||||
public String getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public String getDefaultTimeLimit() {
|
||||
return defaultTimeLimit;
|
||||
}
|
||||
public String getOutputSize() {
|
||||
return outputSize;
|
||||
}
|
||||
|
||||
public String getK8sServer() {
|
||||
return k8sServer;
|
||||
}
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public String getK8sUser() {
|
||||
return k8sUser;
|
||||
}
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getK8sPasswd() {
|
||||
return k8sPasswd;
|
||||
}
|
||||
public String getGpuImage() {
|
||||
return gpuImage;
|
||||
}
|
||||
|
||||
public String getCpuAllocatable() {
|
||||
return cpuAllocatable;
|
||||
}
|
||||
public void setGpuImage(String gpuImage) {
|
||||
this.gpuImage = gpuImage;
|
||||
}
|
||||
|
||||
public String getMemAllocatable() {
|
||||
return memAllocatable;
|
||||
}
|
||||
public Integer getVncPort() {
|
||||
return vncPort;
|
||||
}
|
||||
|
||||
public String getGitIP() {
|
||||
return gitIP;
|
||||
}
|
||||
|
||||
public String getDockerMaster() {
|
||||
return dockerMaster;
|
||||
}
|
||||
|
||||
public String getDockerDeputies() {
|
||||
return dockerDeputies;
|
||||
}
|
||||
|
||||
public String getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public String getOutputSize() {
|
||||
return outputSize;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getGpuImage() {
|
||||
return gpuImage;
|
||||
}
|
||||
|
||||
public void setGpuImage(String gpuImage) {
|
||||
this.gpuImage = gpuImage;
|
||||
}
|
||||
|
||||
public String getGitUsername() {
|
||||
return gitUsername;
|
||||
}
|
||||
|
||||
public void setGitUsername(String gitUsername) {
|
||||
this.gitUsername = gitUsername;
|
||||
}
|
||||
|
||||
public String getGitPassword() {
|
||||
return gitPassword;
|
||||
}
|
||||
|
||||
public void setGitPassword(String gitPassword) {
|
||||
this.gitPassword = gitPassword;
|
||||
}
|
||||
public void setVncPort(Integer vncPort) {
|
||||
this.vncPort = vncPort;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package com.educoder.bridge.common.settings;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
@Configuration
|
||||
public class DateConfig {
|
||||
|
||||
/** 默认日期时间格式 */
|
||||
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
/** 默认日期格式 */
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
/** 默认时间格式 */
|
||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
/**
|
||||
* LocalDate转换器,用于转换RequestParam和PathVariable参数
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, LocalDate> localDateConverter() {
|
||||
return new Converter<String, LocalDate>() {
|
||||
@Override
|
||||
public LocalDate convert(String source) {
|
||||
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDateTime转换器,用于转换RequestParam和PathVariable参数
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, LocalDateTime> localDateTimeConverter() {
|
||||
return new Converter<String, LocalDateTime>() {
|
||||
@Override
|
||||
public LocalDateTime convert(String source) {
|
||||
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalTime转换器,用于转换RequestParam和PathVariable参数
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, LocalTime> localTimeConverter() {
|
||||
return new Converter<String, LocalTime>() {
|
||||
@Override
|
||||
public LocalTime convert(String source) {
|
||||
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Date转换器,用于转换RequestParam和PathVariable参数
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, Date> dateConverter() {
|
||||
return new Converter<String, Date>() {
|
||||
@Override
|
||||
public Date convert(String source) {
|
||||
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
|
||||
try {
|
||||
return format.parse(source);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Json序列化和反序列化转换器,用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json
|
||||
*/
|
||||
@Bean("objectMapper")
|
||||
public ObjectMapper objectMapper(){
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
|
||||
|
||||
//LocalDateTime系列序列化和反序列化模块,继承自jsr310,我们在这里修改了日期格式
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
|
||||
|
||||
//Date序列化和反序列化
|
||||
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
|
||||
@Override
|
||||
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
|
||||
String formattedDate = formatter.format(date);
|
||||
jsonGenerator.writeString(formattedDate);
|
||||
}
|
||||
});
|
||||
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
|
||||
@Override
|
||||
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
|
||||
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
|
||||
String date = jsonParser.getText();
|
||||
try {
|
||||
return format.parse(date);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,23 +10,36 @@
|
|||
*/
|
||||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
/**
|
||||
* <一句话功能简述>
|
||||
* <功能详细描述>
|
||||
* @author liliy
|
||||
* @version [版本号,2017年6月13日]
|
||||
* @see [相关类/方法]
|
||||
* @since [产品/模块版本]
|
||||
*/
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class BeanFactory {
|
||||
static ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
|
||||
public static Object getObejct(String className){
|
||||
Object object = ctx.getBean(className);
|
||||
/**
|
||||
* <一句话功能简述> <功能详细描述>
|
||||
*
|
||||
* @author liliy
|
||||
* @version [版本号,2017年6月13日]
|
||||
* @see [相关类/方法]
|
||||
* @since [产品/模块版本]
|
||||
*/
|
||||
@Component
|
||||
public class BeanFactory implements ApplicationContextAware {
|
||||
private static ApplicationContext ctx = null;
|
||||
|
||||
public static Object getObejct(String name) {
|
||||
Object object = ctx.getBean(name);
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
public static <T> T getObejct(Class<T> requiredType) {
|
||||
return ctx.getBean(requiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
BeanFactory.ctx = applicationContext;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,70 +1,69 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.spotify.docker.client.DefaultDockerClient;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.ConfigBuilder;
|
||||
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.spotify.docker.client.DefaultDockerClient;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.ConfigBuilder;
|
||||
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
|
||||
/**
|
||||
* Created by zzx on 17/11/30.
|
||||
*/
|
||||
public class ClientUtil {
|
||||
private static KubernetesClient client;
|
||||
private static DockerClient docker;
|
||||
private static List<DockerClient> dockerDeputies = new ArrayList<>();
|
||||
private static volatile KubernetesClient client;
|
||||
private static volatile DockerClient docker;
|
||||
private static final List<DockerClient> dockerDeputies = new ArrayList<>();
|
||||
|
||||
public synchronized static KubernetesClient getClient() {
|
||||
if (client != null) {
|
||||
return client;
|
||||
}
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
Config config = new ConfigBuilder()
|
||||
.withMasterUrl(appConfig.getK8sServer())
|
||||
.withNamespace("default")
|
||||
.withTrustCerts(true)
|
||||
.withUsername(appConfig.getK8sUser())
|
||||
.withPassword(appConfig.getK8sPasswd())
|
||||
.build();
|
||||
try {
|
||||
client = new DefaultKubernetesClient(config);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return client;
|
||||
}
|
||||
public static KubernetesClient getClient() {
|
||||
if (client == null) {
|
||||
synchronized (ClientUtil.class) {
|
||||
if (client == null) {
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
Config config = new ConfigBuilder().withMasterUrl(appConfig.getK8sServer()).withNamespace("default")
|
||||
.withTrustCerts(true).withUsername(appConfig.getK8sUser())
|
||||
.withPassword(appConfig.getK8sPasswd()).build();
|
||||
client = new DefaultKubernetesClient(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
public synchronized static DockerClient getDocker() {
|
||||
if (docker != null) {
|
||||
return docker;
|
||||
}
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
try {
|
||||
docker = DefaultDockerClient.builder().uri(URI.create(appConfig.getDockerMaster())).build();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return docker;
|
||||
}
|
||||
public static DockerClient getDocker() {
|
||||
if (docker == null) {
|
||||
synchronized (ClientUtil.class) {
|
||||
if (docker == null) {
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
docker = DefaultDockerClient.builder().uri(URI.create(appConfig.getDockerMaster())).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static List<DockerClient> getDockerDeputies() {
|
||||
if (dockerDeputies != null && dockerDeputies.size() > 0) {
|
||||
return dockerDeputies;
|
||||
}
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
String deputies = appConfig.getDockerDeputies();
|
||||
String[] ips = deputies.split(";");
|
||||
// 为每一个节点返回一个docker客户端
|
||||
for (int i = 0; i < ips.length; i++) {
|
||||
dockerDeputies.add(DefaultDockerClient.builder().uri(URI.create(ips[i])).build());
|
||||
}
|
||||
return docker;
|
||||
}
|
||||
|
||||
return dockerDeputies;
|
||||
}
|
||||
public static List<DockerClient> getDockerDeputies() {
|
||||
if (dockerDeputies.size() == 0) {
|
||||
synchronized (ClientUtil.class) {
|
||||
if (dockerDeputies.size() == 0) {
|
||||
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
|
||||
String deputies = appConfig.getDockerDeputies();
|
||||
String[] ips = deputies.split(";");
|
||||
// 为每一个节点返回一个docker客户端
|
||||
for (int i = 0; i < ips.length; i++) {
|
||||
dockerDeputies.add(DefaultDockerClient.builder().uri(URI.create(ips[i])).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dockerDeputies;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -14,6 +7,14 @@ import java.time.LocalDateTime;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.constant.BuildResultCsts;
|
||||
|
||||
/**
|
||||
* 业务相关的字符串帮助类
|
||||
*
|
||||
|
@ -22,306 +23,335 @@ import java.util.regex.Pattern;
|
|||
**/
|
||||
public class GameHelper {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GameHelper.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(GameHelper.class);
|
||||
|
||||
/**
|
||||
* 通过gitURL获取版本库名字
|
||||
* @param gitURL 版本库地址
|
||||
* @return 版本库名字
|
||||
*/
|
||||
public static String getRepoName(String gitURL) {
|
||||
String repoName = gitURL.substring(gitURL.lastIndexOf("/") + 1, gitURL.lastIndexOf("."));
|
||||
return repoName;
|
||||
}
|
||||
/**
|
||||
* 通过gitURL获取版本库名字
|
||||
*
|
||||
* @param gitURL
|
||||
* 版本库地址
|
||||
* @return 版本库名字
|
||||
*/
|
||||
public static String getRepoName(String gitURL) {
|
||||
String repoName = gitURL.substring(gitURL.lastIndexOf("/") + 1, gitURL.lastIndexOf("."));
|
||||
return repoName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过gitUrl获取用户的identifier
|
||||
* @param gitURL
|
||||
* @return 用户identifier
|
||||
*/
|
||||
public static String getIdentifier(String gitURL) {
|
||||
String tmp = gitURL.substring(0, gitURL.lastIndexOf("/"));
|
||||
return tmp.substring(tmp.lastIndexOf("/") + 1);
|
||||
}
|
||||
/**
|
||||
* 通过gitUrl获取用户的identifier
|
||||
*
|
||||
* @param gitURL
|
||||
* @return 用户identifier
|
||||
*/
|
||||
public static String getIdentifier(String gitURL) {
|
||||
String tmp = gitURL.substring(0, gitURL.lastIndexOf("/"));
|
||||
return tmp.substring(tmp.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* tpmRepoName存在于tpi工作目录且tpiRepoName不存在,若tpmRepoName与tpiRepoName异名,则需将tpmRepoName改名
|
||||
*
|
||||
* @param tpiWorkSpace 工作目录
|
||||
* @param tpiRepoName tpi版本库名字
|
||||
* @param tpmRepoName tpm版本库名字
|
||||
* @return
|
||||
*/
|
||||
public static boolean ensurelocalRepoName(String tpiWorkSpace, String tpiRepoName, String tpmRepoName) {
|
||||
try {
|
||||
if (!tpiRepoName.equals(tpmRepoName)) {
|
||||
Files.move(Paths.get(tpiWorkSpace, tpmRepoName), Paths.get(tpiWorkSpace, tpiRepoName));
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("tpmRepoName: {}重命名为tpiRepoName: {}失败,路径为: {}", tpmRepoName, tpiRepoName, tpiWorkSpace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* tpmRepoName存在于tpi工作目录且tpiRepoName不存在,若tpmRepoName与tpiRepoName异名,则需将tpmRepoName改名
|
||||
*
|
||||
* @param tpiWorkSpace
|
||||
* 工作目录
|
||||
* @param tpiRepoName
|
||||
* tpi版本库名字
|
||||
* @param tpmRepoName
|
||||
* tpm版本库名字
|
||||
* @return
|
||||
*/
|
||||
public static boolean ensurelocalRepoName(String tpiWorkSpace, String tpiRepoName, String tpmRepoName) {
|
||||
try {
|
||||
if (!tpiRepoName.equals(tpmRepoName)) {
|
||||
Files.move(Paths.get(tpiWorkSpace, tpmRepoName), Paths.get(tpiWorkSpace, tpiRepoName));
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("tpmRepoName: {}重命名为tpiRepoName: {}失败,路径为: {}", tpmRepoName, tpiRepoName, tpiWorkSpace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取脚本执行结果中平台封装的结果格式
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String getRealResult(String src) {
|
||||
// \{ 匹配 { , [\s]* 匹配0-多个空白字符, "compileResult"[\s]*:匹配"compileResult":
|
||||
// [\s\S]*匹配0-多个任意字符, [\s\S]*"out"[\s]*:匹配"out": , [^}]*匹配除}之外的所有字符
|
||||
String regex = "\\{[\\s]*\"compileResult\"[\\s]*:[\\s\\S]*\"out\"[\\s]*:[^}]*}";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(src);
|
||||
if (m.find()) {
|
||||
return m.group(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 提取脚本执行结果中平台封装的结果格式
|
||||
*
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String getRealResult(String src) {
|
||||
Pattern p = Pattern.compile(BuildResultCsts.FULL_RESULT_REG);
|
||||
Matcher m = p.matcher(src);
|
||||
if (m.find()) {
|
||||
return m.group(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判段是否是合法的json字符串
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidJSON(String src) {
|
||||
try {
|
||||
JSONObject.parseObject(src);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 判段是否是合法的json字符串
|
||||
*
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidJSON(String src) {
|
||||
try {
|
||||
JSONObject.parseObject(src);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为图片文件
|
||||
*
|
||||
* @param pic
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPic(String pic) {
|
||||
String regex = ".+(.JPEG|.jpeg|.JPG|.jpg|.GIF|.gif|.BMP|.bmp|.PNG|.png)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(pic);
|
||||
/**
|
||||
* 判断是否为图片文件
|
||||
*
|
||||
* @param pic
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPic(String pic) {
|
||||
String regex = ".+(.JPEG|.jpeg|.JPG|.jpg|.GIF|.gif|.BMP|.bmp|.PNG|.png)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(pic);
|
||||
|
||||
return m.find();
|
||||
}
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为html
|
||||
*
|
||||
* @param html
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHtml(String html) {
|
||||
String regex = ".+(.html|.htm)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(html);
|
||||
return m.find();
|
||||
}
|
||||
/**
|
||||
* 判断是否为html
|
||||
*
|
||||
* @param html
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHtml(String html) {
|
||||
String regex = ".+(.html|.htm)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(html);
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为apk
|
||||
*
|
||||
* @param apk
|
||||
* @return
|
||||
*/
|
||||
public static boolean isApk(String apk) {
|
||||
String regex = ".+(.apk)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(apk);
|
||||
return m.find();
|
||||
}
|
||||
/**
|
||||
* 判断是否为apk
|
||||
*
|
||||
* @param apk
|
||||
* @return
|
||||
*/
|
||||
public static boolean isApk(String apk) {
|
||||
String regex = ".+(.apk)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(apk);
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为exe
|
||||
*
|
||||
* @param exe
|
||||
* @return
|
||||
*/
|
||||
public static boolean isExe(String exe) {
|
||||
String regex = ".+(.exe)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(exe);
|
||||
return m.find();
|
||||
}
|
||||
/**
|
||||
* 判断是否为exe
|
||||
*
|
||||
* @param exe
|
||||
* @return
|
||||
*/
|
||||
public static boolean isExe(String exe) {
|
||||
String regex = ".+(.exe)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(exe);
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为txt
|
||||
*
|
||||
* @param txt
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTxt(String txt) {
|
||||
String regex = ".+(.txt)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(txt);
|
||||
return m.find();
|
||||
}
|
||||
/**
|
||||
* 判断是否为txt
|
||||
*
|
||||
* @param txt
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTxt(String txt) {
|
||||
String regex = ".+(.txt)$";
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(txt);
|
||||
return m.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取生成的apk的文件名字
|
||||
*
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public static String getApkName(String dir) {
|
||||
String apkName = "";
|
||||
File file = new File(dir);
|
||||
if (file.exists() && file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File fileTmp : files) {
|
||||
String fileName = fileTmp.getName();
|
||||
if (GameHelper.isApk(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return apkName;
|
||||
}
|
||||
/**
|
||||
* 获取生成的apk的文件名字
|
||||
*
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
public static String getApkName(String dir) {
|
||||
String apkName = "";
|
||||
File file = new File(dir);
|
||||
if (file.exists() && file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File fileTmp : files) {
|
||||
String fileName = fileTmp.getName();
|
||||
if (GameHelper.isApk(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return apkName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除无关的文件
|
||||
*
|
||||
* @param dir
|
||||
*/
|
||||
public static void clearFiles(String dir) {
|
||||
GameHelper.deleteFiles(dir, "pic");
|
||||
GameHelper.deleteFiles(dir, "apk");
|
||||
GameHelper.deleteFiles(dir, "html");
|
||||
GameHelper.deleteFiles(dir, "exe");
|
||||
GameHelper.deleteFiles(dir, "txt");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除无关的文件
|
||||
* @param dir
|
||||
*/
|
||||
public static void clearFiles(String dir) {
|
||||
GameHelper.deleteFiles(dir, "pic");
|
||||
GameHelper.deleteFiles(dir, "apk");
|
||||
GameHelper.deleteFiles(dir, "html");
|
||||
GameHelper.deleteFiles(dir, "exe");
|
||||
GameHelper.deleteFiles(dir, "txt");
|
||||
}
|
||||
/**
|
||||
* 删除文件夹下某种类型的文件
|
||||
*
|
||||
* @param dir
|
||||
* @param fileType
|
||||
*/
|
||||
public static void deleteFiles(String dir, String fileType) {
|
||||
File file = new File(dir);
|
||||
if (file.exists() && file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File fileTmp : files) {
|
||||
String fileName = fileTmp.getName();
|
||||
try {
|
||||
if ("pic".equals(fileType) && GameHelper.isPic(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("apk".equals(fileType) && GameHelper.isApk(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("html".equals(fileType) && GameHelper.isHtml(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("exe".equals(fileType) && GameHelper.isExe(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("txt".equals(fileType) && GameHelper.isTxt(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除实训生成文件失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件夹下某种类型的文件
|
||||
*
|
||||
* @param dir
|
||||
* @param fileType
|
||||
*/
|
||||
public static void deleteFiles(String dir, String fileType) {
|
||||
File file = new File(dir);
|
||||
if (file.exists() && file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File fileTmp : files) {
|
||||
String fileName = fileTmp.getName();
|
||||
try {
|
||||
if ("pic".equals(fileType) && GameHelper.isPic(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("apk".equals(fileType) && GameHelper.isApk(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("html".equals(fileType) && GameHelper.isHtml(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("exe".equals(fileType) && GameHelper.isExe(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
if ("txt".equals(fileType) && GameHelper.isTxt(fileName)) {
|
||||
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
|
||||
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除实训生成文件失败: {}", e.getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 取得评测执行超时情况下的平台封装结果(限定时间内执行脚本尚未获得结果,脚本还在运行)
|
||||
*/
|
||||
public static String getTooManyTimesResult(int caseSize, int maxTimes) {
|
||||
String hint = "输出消息次数超限,最多输出%d次";
|
||||
hint = String.format(hint, maxTimes);
|
||||
|
||||
return getResult(hint, caseSize, null, null);
|
||||
}
|
||||
|
||||
public static String getResult(String hint, int caseSize, String downloadStatus, String createPodStatus) {
|
||||
hint = Base64Util.encode(hint);
|
||||
|
||||
/**
|
||||
* 取得评测执行超时情况下的平台封装结果(限定时间内执行脚本尚未获得结果,脚本还在运行)
|
||||
*/
|
||||
public static String getTimeOutResult(int caseSize, int timeLimit) {
|
||||
String hint = "代码评测超时!本关限定时间为:" + timeLimit + "s,请检查代码是否存在死循环或其他耗时操作";
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", hint);
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(hint);
|
||||
}
|
||||
result.put("out", out);
|
||||
result.put(BuildResultCsts.DOWNLOAD_STATUS, downloadStatus);
|
||||
result.put(BuildResultCsts.CREATE_POD_STATUS, createPodStatus);
|
||||
return result.toJSONString();
|
||||
}
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("compile successfully"));
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(Base64Util.encode(hint));
|
||||
}
|
||||
result.put("out", out);
|
||||
public static String getTextMsgResult(String textMsg) {
|
||||
return BuildResultCsts.TEXT_RESULT_PRE + textMsg;
|
||||
}
|
||||
|
||||
return result.toJSONString();
|
||||
}
|
||||
/**
|
||||
* 取得评测执行超时情况下的平台封装结果(限定时间内执行脚本尚未获得结果,脚本还在运行)
|
||||
*/
|
||||
public static String getTimeOutResult(int caseSize, int timeLimit) {
|
||||
String hint = "代码评测超时!本关限定时间为:" + timeLimit + "s,请检查代码是否存在死循环或其他耗时操作";
|
||||
|
||||
/**
|
||||
* 当脚本错误时,返回平台封装的结果
|
||||
*/
|
||||
public static String getShellErrorResult(int caseSize, String oriOut) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("评测脚本错误,请检查评测脚本设置。评测脚本返回的结果格式示例如下:\n" +
|
||||
"{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]},其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=,MzI=,MTIy分别为base64编码之后的编译和执行结果。\n" +
|
||||
"请保证您的评测脚本返回的是一个符合上述格式的有效json字符串\n您的输出:\n" + oriOut));
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(Base64Util.encode(""));
|
||||
}
|
||||
result.put("out", out);
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("compile successfully"));
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(Base64Util.encode(hint));
|
||||
}
|
||||
result.put("out", out);
|
||||
|
||||
return result.toJSONString();
|
||||
}
|
||||
return result.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 评测时候出现未知错误,报平台繁忙
|
||||
*/
|
||||
public static String getUnknowErrorResult(int caseSize) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("系统繁忙,请稍后重试"));
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(Base64Util.encode(""));
|
||||
}
|
||||
result.put("out", out);
|
||||
/**
|
||||
* 当脚本错误时,返回平台封装的结果
|
||||
*/
|
||||
public static String getShellErrorResult(int caseSize, String oriOut) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("评测脚本错误,请检查评测脚本设置。评测脚本返回的结果格式示例如下:\n"
|
||||
+ "{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]},其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=,MzI=,MTIy分别为base64编码之后的编译和执行结果。\n"
|
||||
+ "请保证您的评测脚本返回的是一个符合上述格式的有效json字符串\n您的输出:\n" + oriOut));
|
||||
|
||||
return result.toJSONString();
|
||||
}
|
||||
JSONArray out = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
out.add(Base64Util.encode(""));
|
||||
}
|
||||
result.put("out", out);
|
||||
|
||||
/**
|
||||
* 调试模式下,封装调试结果
|
||||
*/
|
||||
public static String getDebugOutPut(String result, String oriOut) {
|
||||
return "当前模式下为您展示脚本原始输出,供调试使用,您脚本的原始输出为:\n"
|
||||
+ oriOut +
|
||||
"\n在实训发布后平台将屏蔽调试输出,仅提取结果相关部分用于测评。\n" +
|
||||
"结果格式应如:{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]},其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=,MzI=,MTIy分别为base64编码之后的编译和执行结果。" +
|
||||
"\n以下是本次评测结果:\n" + result;
|
||||
return result.toJSONString();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 评测时候出现未知错误,报平台繁忙
|
||||
*/
|
||||
public static String getUnknowErrorResult(int caseSize) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("compileResult", Base64Util.encode("系统繁忙,请稍后重试"));
|
||||
JSONArray arr = new JSONArray(caseSize);
|
||||
for (int i = 0; i < caseSize; i++) {
|
||||
arr.add(Base64Util.encode(""));
|
||||
}
|
||||
result.put("out", arr);
|
||||
|
||||
/**
|
||||
* 设置TPI 本次build某一阶段消耗时间值
|
||||
* @param key timeCost:${tpiID}:${buildID}
|
||||
*/
|
||||
public static void setTimeCostInJedis(String key, String period, String cost) {
|
||||
JSONObject timeCost = JSONObject.parseObject(JedisUtil.get(key));
|
||||
return result.toJSONString();
|
||||
}
|
||||
|
||||
// 如果没有,是不是可以理解为速度太快,导致同步不及时
|
||||
// 那么设开始时间为现在的时间
|
||||
if (timeCost == null){
|
||||
timeCost = new JSONObject();
|
||||
String evaluateStartTime = LocalDateTime.now().toString();
|
||||
timeCost.put("evaluateStartTime", evaluateStartTime);
|
||||
}
|
||||
/**
|
||||
* 调试模式下,封装调试结果
|
||||
*/
|
||||
public static String getDebugOutPut(String result, String oriOut) {
|
||||
return "当前模式下为您展示脚本原始输出,供调试使用,您脚本的原始输出为:\n" + oriOut + "\n在实训发布后平台将屏蔽调试输出,仅提取结果相关部分用于测评。\n"
|
||||
+ "结果格式应如:{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]},其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=,MzI=,MTIy分别为base64编码之后的编译和执行结果。"
|
||||
+ "\n以下是本次评测结果:\n" + result;
|
||||
|
||||
timeCost.put(period, cost);
|
||||
JedisUtil.set(key, timeCost.toJSONString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置TPI 本次build某一阶段消耗时间值
|
||||
*
|
||||
* @param key
|
||||
* timeCost:${tpiID}:${buildID}
|
||||
*/
|
||||
public static JSONObject setTimeCostInJedis(String key, String period, String cost) {
|
||||
JSONObject timeCost = JSONObject.parseObject(JedisUtil.get(key));
|
||||
|
||||
// 如果没有,是不是可以理解为速度太快,导致同步不及时
|
||||
// 那么设开始时间为现在的时间
|
||||
if (timeCost == null) {
|
||||
timeCost = new JSONObject();
|
||||
String evaluateStartTime = LocalDateTime.now().toString();
|
||||
timeCost.put("evaluateStartTime", evaluateStartTime);
|
||||
}
|
||||
|
||||
timeCost.put(period, cost);
|
||||
JedisUtil.set(key, timeCost.toJSONString());
|
||||
|
||||
return timeCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取加权限的gitURL:
|
||||
* 加上超级用户的用户名密码
|
||||
* 形如:https://edugit:xinedugit@bdgit.educoder.net/educoder/mnf6b7z3.git
|
||||
*/
|
||||
public static String appendGitUrlWithUser(String gitUsername, String gitPassword, String gitUrl) {
|
||||
return new StringBuffer(gitUrl).insert(gitUrl.indexOf("//") + 2, gitUsername + ":" + gitPassword + "@").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
/**
|
||||
* Created by guange on 30/10/2016.
|
||||
*/
|
||||
|
@ -47,7 +49,9 @@ public class HttpHelper {
|
|||
Map<String, List<String>> map = connection.getHeaderFields();
|
||||
// 遍历所有的响应头字段
|
||||
for (String key : map.keySet()) {
|
||||
System.out.println(key + "--->" + map.get(key));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug((key + "--->" + map.get(key)));
|
||||
}
|
||||
}
|
||||
// 定义 BufferedReader输入流来读取URL的响应
|
||||
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
|
@ -65,6 +69,7 @@ public class HttpHelper {
|
|||
in.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
// ignore quietly
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -84,13 +89,11 @@ public class HttpHelper {
|
|||
PrintWriter out = null;
|
||||
BufferedReader in = null;
|
||||
String result = "";
|
||||
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
try {
|
||||
URL realUrl = new URL(url);
|
||||
// 打开和URL之间的连接
|
||||
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
|
||||
|
||||
// 设置通用的请求属性
|
||||
conn.setRequestProperty("Accept", "*/*");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
|
@ -100,7 +103,6 @@ public class HttpHelper {
|
|||
// 发送POST请求必须设置如下两行
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
for (Object key : param.keySet()) {
|
||||
stringBuffer.append(key + "=" + param.get(key));
|
||||
|
@ -108,26 +110,22 @@ public class HttpHelper {
|
|||
}
|
||||
String data = stringBuffer.toString();
|
||||
data = data.substring(0, data.length() - 1);
|
||||
|
||||
log.debug("POST: " + url + " DATA: " + data);
|
||||
|
||||
OutputStream outputStream = conn.getOutputStream();
|
||||
outputStream.write(data.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
log.info("结果返回时间0{}" , System.currentTimeMillis() - currentTimeMillis);
|
||||
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
|
||||
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("发送 POST 请求出现异常!" + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
finally {
|
||||
// System.out.println("发送 POST 请求出现异常!" + e);
|
||||
// e.printStackTrace();
|
||||
log.error("发送 POST 请求出现异常!", e);
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
|
@ -136,14 +134,14 @@ public class HttpHelper {
|
|||
in.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore quietly
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
log.info("结果返回时间1{},返回结果{}" , System.currentTimeMillis() - currentTimeMillis, result);
|
||||
log.info("结果返回时间1{},返回结果{}", System.currentTimeMillis() - currentTimeMillis, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送POST方法的请求
|
||||
*
|
||||
|
@ -157,13 +155,11 @@ public class HttpHelper {
|
|||
PrintWriter out = null;
|
||||
BufferedReader in = null;
|
||||
String result = "";
|
||||
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
try {
|
||||
URL realUrl = new URL(url);
|
||||
// 打开和URL之间的连接
|
||||
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
|
||||
|
||||
// 设置通用的请求属性
|
||||
conn.setRequestProperty("Accept", "*/*");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
|
@ -174,7 +170,6 @@ public class HttpHelper {
|
|||
// 发送POST请求必须设置如下两行
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
for (Object key : param.keySet()) {
|
||||
stringBuffer.append(key + "=" + param.get(key));
|
||||
|
@ -182,26 +177,22 @@ public class HttpHelper {
|
|||
}
|
||||
String data = stringBuffer.toString();
|
||||
data = data.substring(0, data.length() - 1);
|
||||
|
||||
log.debug("POST: " + url + " DATA: " + data);
|
||||
|
||||
OutputStream outputStream = conn.getOutputStream();
|
||||
outputStream.write(data.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
log.info("结果返回时间0{}" , System.currentTimeMillis() - currentTimeMillis);
|
||||
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
|
||||
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("发送 POST 请求出现异常!" + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
finally {
|
||||
// System.out.println("发送 POST 请求出现异常!" + e);
|
||||
// e.printStackTrace();
|
||||
log.error("发送 POST 请求出现异常!", e);
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
|
@ -210,10 +201,11 @@ public class HttpHelper {
|
|||
in.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore quietly
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
log.info("结果返回时间1{},返回结果{}" , System.currentTimeMillis() - currentTimeMillis, result);
|
||||
log.info("结果返回时间1{},返回结果{}", System.currentTimeMillis() - currentTimeMillis, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -254,8 +246,9 @@ public class HttpHelper {
|
|||
result += line;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("发送 POST 请求出现异常!" + e);
|
||||
e.printStackTrace();
|
||||
// System.out.println("发送 POST 请求出现异常!" + e);
|
||||
// e.printStackTrace();
|
||||
log.error("发送 POST 请求出现异常!", e);
|
||||
}
|
||||
// 使用finally块来关闭输出流、输入流
|
||||
finally {
|
||||
|
@ -267,10 +260,10 @@ public class HttpHelper {
|
|||
in.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
// ignore quietly
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,25 +1,27 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Set;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
/**
|
||||
* Created by zzx on 17/10/24.
|
||||
*/
|
||||
public class JedisUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(JedisUtil.class);
|
||||
|
||||
/**
|
||||
* 获取zset中元素个数
|
||||
*/
|
||||
public static int zlen(String key) {
|
||||
Jedis jedis = null;
|
||||
Jedis jedis = null;
|
||||
int len = 0;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
len = jedis.zcard(key).intValue();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -30,7 +32,7 @@ public class JedisUtil {
|
|||
* 获取元素在zset中的排名
|
||||
*/
|
||||
public static double zrank(String key, String value) {
|
||||
Jedis jedis = null;
|
||||
Jedis jedis = null;
|
||||
double rank = Double.MIN_VALUE;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
|
@ -40,7 +42,7 @@ public class JedisUtil {
|
|||
rank = jedis.zrank(key, value);
|
||||
} catch (Exception e) {
|
||||
rank = Double.MAX_VALUE;
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -51,7 +53,7 @@ public class JedisUtil {
|
|||
* 将zset中队首元素弹出,若zset中没有元素,则返回null
|
||||
*/
|
||||
public static String zpop(String key) {
|
||||
Jedis jedis = null;
|
||||
Jedis jedis = null;
|
||||
String element = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
|
@ -60,7 +62,7 @@ public class JedisUtil {
|
|||
jedis.zrem(key, element);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -82,7 +84,7 @@ public class JedisUtil {
|
|||
jedis.zadd(key, lastScore + 1, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -99,7 +101,7 @@ public class JedisUtil {
|
|||
jedis = RedisPool.getJedis();
|
||||
jedis.zincrby(key, 1, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -119,7 +121,7 @@ public class JedisUtil {
|
|||
jedis.zrem(key, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -135,7 +137,7 @@ public class JedisUtil {
|
|||
jedis = RedisPool.getJedis();
|
||||
has = jedis.zscore(key, value) != null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -151,7 +153,7 @@ public class JedisUtil {
|
|||
jedis = RedisPool.getJedis();
|
||||
jedis.hset(key, field, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -167,7 +169,7 @@ public class JedisUtil {
|
|||
jedis = RedisPool.getJedis();
|
||||
value = jedis.hget(key, field);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
|
@ -183,57 +185,57 @@ public class JedisUtil {
|
|||
jedis = RedisPool.getJedis();
|
||||
jedis.hdel(key, field);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* String: set
|
||||
*/
|
||||
public static void set(String key, String value) {
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
jedis.set(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
* String: set
|
||||
*/
|
||||
public static void set(String key, String value) {
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
jedis.set(key, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String: get
|
||||
*/
|
||||
public static String get(String key) {
|
||||
Jedis jedis = null;
|
||||
String value = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
value = jedis.get(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* String: get
|
||||
*/
|
||||
public static String get(String key) {
|
||||
Jedis jedis = null;
|
||||
String value = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
value = jedis.get(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* String: delete
|
||||
*/
|
||||
public static void del(String key) {
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
jedis.del(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* String: delete
|
||||
*/
|
||||
public static void del(String key) {
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
jedis = RedisPool.getJedis();
|
||||
jedis.del(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
RedisPool.returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.http.ConnectionClosedException;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.nio.client.BridgeHttpAsyncClientBuilder;
|
||||
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by guange on 30/10/2016.
|
||||
*/
|
||||
public class NioHttpClientUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(NioHttpClientUtils.class);
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送POST方法的请求
|
||||
*
|
||||
* @param url
|
||||
* 发送请求的 URL
|
||||
* @param param
|
||||
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendPost(String url, Map param) {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
String result = "";
|
||||
try {
|
||||
HttpPost request = new HttpPost(url);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object key : param.keySet()) {
|
||||
sb.append(key + "=" + param.get(key));
|
||||
sb.append("&");
|
||||
}
|
||||
String data = sb.toString();
|
||||
data = data.substring(0, data.length() - 1);
|
||||
|
||||
log.debug("POST: " + url + " DATA: " + data);
|
||||
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);
|
||||
StringEntity entity = new StringEntity(data, contentType);
|
||||
request.setEntity(entity);
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000) // 建立连接的超时时间,即三次握手的超时时间。
|
||||
.setSocketTimeout(10000) // 请求数据传输的超时时间。
|
||||
.setConnectionRequestTimeout(1000) // 从连接池获取连接的超时时间。
|
||||
.build();
|
||||
CloseableHttpAsyncClient httpclient = BridgeHttpAsyncClientBuilder.create()
|
||||
.setDefaultRequestConfig(requestConfig).setBodyLength(entity.getContentLength()).build();
|
||||
httpclient.start();
|
||||
Future<HttpResponse> future = httpclient.execute(request, new FutureCallback<HttpResponse>() {
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
if (ex instanceof ConnectionClosedException) {
|
||||
|
||||
} else {
|
||||
log.error("请求发送失败");
|
||||
}
|
||||
close(httpclient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(HttpResponse resp) {
|
||||
close(httpclient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
close(httpclient);
|
||||
}
|
||||
});
|
||||
// HttpResponse res = future.get();
|
||||
// result = EntityUtils.toString(res.getEntity());
|
||||
while (httpclient.isRunning()) {
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送 POST 请求出现异常!", e);
|
||||
}
|
||||
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private static void close(CloseableHttpAsyncClient httpclient) {
|
||||
try {
|
||||
httpclient.close();
|
||||
} catch (IOException e) {
|
||||
// ignore quietly
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送POST方法的请求
|
||||
*
|
||||
* @param url
|
||||
* 发送请求的 URL
|
||||
* @param param
|
||||
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
||||
* @return 所代表远程资源的响应结果
|
||||
*/
|
||||
public static String sendPost(String url, Map param, int readTimeOut) {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
String result = "";
|
||||
try {
|
||||
HttpPost request = new HttpPost(url);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object key : param.keySet()) {
|
||||
sb.append(key + "=" + param.get(key));
|
||||
sb.append("&");
|
||||
}
|
||||
String data = sb.toString();
|
||||
data = data.substring(0, data.length() - 1);
|
||||
|
||||
log.debug("POST: " + url + " DATA: " + data);
|
||||
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);
|
||||
StringEntity entity = new StringEntity(data, contentType);
|
||||
request.setEntity(entity);
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000) // 建立连接的超时时间,即三次握手的超时时间。
|
||||
.setSocketTimeout(10000) // 请求数据传输的超时时间。
|
||||
.setConnectionRequestTimeout(1000) // 从连接池获取连接的超时时间。
|
||||
.build();
|
||||
CloseableHttpAsyncClient httpclient = BridgeHttpAsyncClientBuilder.create()
|
||||
.setDefaultRequestConfig(requestConfig).setBodyLength(entity.getContentLength()).build();
|
||||
httpclient.start();
|
||||
Future<HttpResponse> future = httpclient.execute(request, new FutureCallback<HttpResponse>() {
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
if (ex instanceof ConnectionClosedException) {
|
||||
|
||||
} else {
|
||||
log.error("请求发送失败");
|
||||
}
|
||||
close(httpclient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(HttpResponse resp) {
|
||||
close(httpclient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
close(httpclient);
|
||||
}
|
||||
});
|
||||
|
||||
// future.get();
|
||||
while (httpclient.isRunning()) {
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送 POST 请求出现异常!", e);
|
||||
}
|
||||
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -7,17 +7,17 @@ import java.net.ServerSocket;
|
|||
* Created by zzx on 17/10/30.
|
||||
*/
|
||||
public class PortUtil {
|
||||
public static int getPort() {
|
||||
int port;
|
||||
while(true) {
|
||||
port = (int) (20000 * Math.random() + 40000);
|
||||
try {
|
||||
new ServerSocket(port).close();
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
public static int getPort() {
|
||||
int port;
|
||||
while (true) {
|
||||
port = (int) (20000 * Math.random() + 40000);
|
||||
try {
|
||||
new ServerSocket(port).close();// TODO 端口可能冲突
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mm
|
||||
*
|
||||
*/
|
||||
public final class ProcessStatusUtil {
|
||||
|
||||
/**
|
||||
* 执行shell命令并获取输出
|
||||
*/
|
||||
public static boolean isTimeout(int exitStatus) {
|
||||
return exitStatus == 124 || exitStatus == (128 + 9);
|
||||
}
|
||||
|
||||
public static boolean isError(int exitStatus) {
|
||||
return exitStatus == -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,70 +1,74 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.exceptions.JedisException;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
public final class RedisPool {
|
||||
private static final Logger log = LoggerFactory.getLogger(JedisUtil.class);
|
||||
|
||||
//可用连接实例的最大数目,默认为8;
|
||||
//如果赋值为-1,则表示不限制,如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)
|
||||
private static Integer MAX_TOTAL = 1024;
|
||||
//控制一个pool最多有多少个状态为idle(空闲)的jedis实例,默认值是8
|
||||
private static Integer MAX_IDLE = 200;
|
||||
//等待可用连接的最大时间,单位是毫秒,默认值为-1,表示永不超时。
|
||||
//如果超过等待时间,则直接抛出JedisConnectionException
|
||||
private static Integer MAX_WAIT_MILLIS = 10000;
|
||||
private static Integer TIMEOUT = 10000;
|
||||
//在borrow(用)一个jedis实例时,是否提前进行validate(验证)操作;
|
||||
//如果为true,则得到的jedis实例均是可用的
|
||||
private static Boolean TEST_ON_BORROW = true;
|
||||
private static JedisPool jedisPool = null;
|
||||
// 可用连接实例的最大数目,默认为8;
|
||||
// 如果赋值为-1,则表示不限制,如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)
|
||||
private static Integer MAX_TOTAL = 1024;
|
||||
// 控制一个pool最多有多少个状态为idle(空闲)的jedis实例,默认值是8
|
||||
private static Integer MAX_IDLE = 200;
|
||||
// 等待可用连接的最大时间,单位是毫秒,默认值为-1,表示永不超时。
|
||||
// 如果超过等待时间,则直接抛出JedisConnectionException
|
||||
private static Integer MAX_WAIT_MILLIS = 10000;
|
||||
private static Integer TIMEOUT = 10000;
|
||||
// 在borrow(用)一个jedis实例时,是否提前进行validate(验证)操作;
|
||||
// 如果为true,则得到的jedis实例均是可用的
|
||||
private static Boolean TEST_ON_BORROW = true;
|
||||
private static JedisPool jedisPool = null;
|
||||
|
||||
// 静态块,初始化Redis连接池
|
||||
static {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
String active = System.getProperty("spring.profiles.active");
|
||||
prop.load(RedisPool.class.getClassLoader().getResourceAsStream("config_" + active + ".properties"));
|
||||
// 静态块,初始化Redis连接池
|
||||
static {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
String active = System.getProperty("spring.profiles.active");
|
||||
prop.load(RedisPool.class.getClassLoader().getResourceAsStream("config_" + active + ".properties"));
|
||||
|
||||
String ADDR = prop.getProperty("redisAddress");
|
||||
int PORT = Integer.parseInt(prop.getProperty("redisPort"));
|
||||
String AUTH = prop.getProperty("redisAuth");
|
||||
String ADDR = prop.getProperty("redisAddress");
|
||||
int PORT = Integer.parseInt(prop.getProperty("redisPort"));
|
||||
String AUTH = prop.getProperty("redisAuth");
|
||||
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxTotal(MAX_TOTAL);
|
||||
config.setMaxIdle(MAX_IDLE);
|
||||
config.setMaxWaitMillis(MAX_WAIT_MILLIS);
|
||||
config.setTestOnBorrow(TEST_ON_BORROW);
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxTotal(MAX_TOTAL);
|
||||
config.setMaxIdle(MAX_IDLE);
|
||||
config.setMaxWaitMillis(MAX_WAIT_MILLIS);
|
||||
config.setTestOnBorrow(TEST_ON_BORROW);
|
||||
|
||||
jedisPool = AUTH.equals("") ? new JedisPool(config, ADDR, PORT, TIMEOUT) :
|
||||
new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
jedisPool = AUTH.equals("") ? new JedisPool(config, ADDR, PORT, TIMEOUT)
|
||||
: new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Jedis实例
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized static Jedis getJedis() {
|
||||
return jedisPool.getResource();
|
||||
}
|
||||
/**
|
||||
* 获取Jedis实例
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized static Jedis getJedis() {
|
||||
return jedisPool.getResource();
|
||||
}
|
||||
|
||||
public static void returnResource(final Jedis jedis) {
|
||||
if (jedis != null) {
|
||||
// jedis.close()取代jedisPool.returnResource(jedis)方法将3.0版本开始
|
||||
try {
|
||||
jedis.close();
|
||||
} catch (JedisException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void returnResource(final Jedis jedis) {
|
||||
if (jedis != null) {
|
||||
// jedis.close()取代jedisPool.returnResource(jedis)方法将3.0版本开始
|
||||
try {
|
||||
jedis.close();
|
||||
} catch (JedisException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,124 +1,133 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* Created by guange on 26/02/2017.
|
||||
*/
|
||||
public class ShellUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class);
|
||||
|
||||
private static ExecutorService executor;
|
||||
private static volatile ExecutorService executor;
|
||||
|
||||
/**
|
||||
* 执行shell命令并获取输出
|
||||
*/
|
||||
public static String execute(String command) {
|
||||
return executeAndGetExitStatus(command).getString("out");
|
||||
}
|
||||
/**
|
||||
* 执行shell命令并获取输出
|
||||
*/
|
||||
public static String execute(String command) {
|
||||
return executeAndGetExitStatus(command).getString("out");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行shell命令并获得输出及退出码,失败重试 共尝试retryTimes次
|
||||
*/
|
||||
public static JSONObject executeAndGetExitStatus(String command, int retryTimes) {
|
||||
JSONObject result = new JSONObject();
|
||||
/**
|
||||
* 执行shell命令并获得输出及退出码,失败重试 共尝试retryTimes次
|
||||
*/
|
||||
public static JSONObject executeAndGetExitStatus(String command, int retryTimes) {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
result = executeAndGetExitStatus(command);
|
||||
if (result.getInteger("exitStatus") != 0) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
result = executeAndGetExitStatus(command);
|
||||
if (result.getInteger("exitStatus") != 0) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令并获得输出以及退出码
|
||||
*/
|
||||
public static JSONObject executeAndGetExitStatus(String command) {
|
||||
JSONObject result = new JSONObject();
|
||||
/**
|
||||
* 执行命令并获得输出以及退出码
|
||||
*/
|
||||
public static JSONObject executeAndGetExitStatus(String command) {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
StringBuffer out = new StringBuffer();
|
||||
Integer exitStatus = -1;
|
||||
StringBuffer out = new StringBuffer();
|
||||
Integer exitStatus = -1;
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/sh", "-c", command});
|
||||
pb.redirectErrorStream(true);
|
||||
try {
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
out.append(line);
|
||||
out.append(System.getProperty("line.separator"));
|
||||
}
|
||||
exitStatus = process.waitFor();
|
||||
ProcessBuilder pb = new ProcessBuilder(new String[] { "/bin/sh", "-c", command });
|
||||
pb.redirectErrorStream(true);
|
||||
try {
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
out.append(line);
|
||||
out.append(System.getProperty("line.separator"));
|
||||
}
|
||||
exitStatus = process.waitFor();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.info("executeAndGetExitStatus: {}", command);
|
||||
logger.error("executeAndGetExitStatus: ",e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info("executeAndGetExitStatus: {}", command);
|
||||
logger.error("executeAndGetExitStatus: ", e);
|
||||
}
|
||||
|
||||
result.put("out", out.toString().trim());
|
||||
result.put("exitStatus", exitStatus);
|
||||
result.put("out", out.toString().trim());
|
||||
result.put("exitStatus", exitStatus);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行shell命令,设定时间限制为${timeLimit} s
|
||||
*/
|
||||
public static JSONObject executeInLimitTime(String command, long timeLimit) throws TimeoutException {
|
||||
JSONObject result = new JSONObject();
|
||||
/**
|
||||
* 执行shell命令,设定时间限制为${timeLimit} s
|
||||
*/
|
||||
public static JSONObject executeInLimitTime(String command, long timeLimit) throws TimeoutException {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
if (executor == null) {
|
||||
executor = Executors.newCachedThreadPool();
|
||||
}
|
||||
if (executor == null) {
|
||||
synchronized (ShellUtil.class) {
|
||||
if (executor == null) {
|
||||
executor = Executors.newCachedThreadPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Future<JSONObject> future = executor.submit(() -> executeAndGetExitStatus(command));
|
||||
result = future.get(timeLimit, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
logger.debug("执行shell命令超时:command: {}", command);
|
||||
try {
|
||||
Future<JSONObject> future = executor.submit(() -> executeAndGetExitStatus(command));
|
||||
result = future.get(timeLimit, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
logger.debug("执行shell命令超时:command: {}", command);
|
||||
|
||||
// 删除任务
|
||||
killProcess(command);
|
||||
// 删除任务
|
||||
killProcess(command);
|
||||
|
||||
throw new TimeoutException("执行命令超时");
|
||||
} catch (Exception e) {
|
||||
logger.debug("执行shell命令失败,未知错误:command: {}", command);
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new TimeoutException("执行命令超时");
|
||||
} catch (Exception e) {
|
||||
logger.debug("执行shell命令失败,未知错误:command: {}", command);
|
||||
logger.error("执行shell命令失败,未知错误", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 杀掉一个shell进程
|
||||
*
|
||||
* @param commandToKill 源命令
|
||||
*/
|
||||
public static void killProcess(String commandToKill) {
|
||||
// 原型:kill -9 `ps -ef | grep "haha.sh" |grep -v grep | awk -F' ' '{print $2}'`
|
||||
logger.debug("ExecuteShellCommand: killProcess: " + commandToKill);
|
||||
/**
|
||||
* 杀掉一个shell进程
|
||||
*
|
||||
* @param commandToKill
|
||||
* 源命令
|
||||
*/
|
||||
public static void killProcess(String commandToKill) {
|
||||
// 原型:kill -9 `ps -ef | grep "haha.sh" |grep -v grep | awk -F' ' '{print $2}'`
|
||||
logger.debug("ExecuteShellCommand: killProcess: " + commandToKill);
|
||||
|
||||
String command = "kill -9 `ps -ef | grep \"" + commandToKill + "\" | grep -v grep | awk -F' ' '{print $2}'`";
|
||||
String command = "kill -9 `ps -ef | grep \"" + commandToKill + "\" | grep -v grep | awk -F' ' '{print $2}'`";
|
||||
|
||||
try {
|
||||
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try {
|
||||
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command });
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public class ThreadPoolUtil {
|
||||
|
||||
/**
|
||||
* 获取线程池信息
|
||||
* @return
|
||||
*/
|
||||
public static JSONObject getPoolInfo(ThreadPoolExecutor executor) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("taskCount", executor.getTaskCount());
|
||||
result.put("activeTaskCount", executor.getActiveCount());
|
||||
result.put("completedCount", executor.getCompletedTaskCount());
|
||||
|
||||
result.put("coreSize", executor.getCorePoolSize());
|
||||
result.put("maxSize", executor.getMaximumPoolSize());
|
||||
result.put("poolSize", executor.getPoolSize());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Runnable r : executor.getQueue()) {
|
||||
sb.append(r.toString() + " ");
|
||||
}
|
||||
result.put("queue", sb.toString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.educoder.bridge.common.utils;
|
||||
import java.io.File;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
/**
|
||||
*
|
||||
* @author mm
|
||||
*
|
||||
*/
|
||||
public abstract class TpUtils {
|
||||
private TpUtils() {
|
||||
}
|
||||
public static String buildTpiWorkspace(String basePath, String tpiID) {
|
||||
return basePath + File.separator + "myshixun_" + tpiID;
|
||||
}
|
||||
/**
|
||||
* 转化评测pod类型
|
||||
*
|
||||
* @param podType
|
||||
* @return
|
||||
*/
|
||||
public static String cvtEvaPodType(Integer podType) {
|
||||
return podType != 2 ? "evaluate" : "evassh";
|
||||
}
|
||||
/**
|
||||
* 转化ssh pod类型
|
||||
*
|
||||
* @param podType
|
||||
* @return
|
||||
*/
|
||||
public static String cvtSshPodType(Integer podType) {
|
||||
return podType != 2 ? "webssh" : "evassh";
|
||||
}
|
||||
/**
|
||||
* 若 pod 共享,返回true,否则返回false
|
||||
*
|
||||
* @param podName
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSharedPod(String podName) {
|
||||
return podName.startsWith("evaluate");
|
||||
}
|
||||
/**
|
||||
* 若 pod 共享,返回true,否则返回false
|
||||
*
|
||||
* @param podType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSharedPod(Integer podType) {
|
||||
String type = cvtEvaPodType(podType);
|
||||
return "evaluate".equals(type);
|
||||
}
|
||||
/**
|
||||
* 共享pod名称构成:evaluate_tpID_xxx
|
||||
*
|
||||
* @param podName
|
||||
* @return
|
||||
*/
|
||||
public static String getSharePodTpID(String podName) {
|
||||
int beginIndex = "evaluate_".length();
|
||||
int endIndex = podName.lastIndexOf("_");
|
||||
String str = podName.substring(beginIndex - 1, endIndex);
|
||||
return str;
|
||||
}
|
||||
public static boolean isSharePod(Pod pod) {
|
||||
String type = pod.getMetadata().getLabels().get("type");
|
||||
return "evaluate".equals(type);
|
||||
}
|
||||
/**
|
||||
* 获取redis中共享pod的任务集合的名称
|
||||
*
|
||||
* @param podName
|
||||
* evaluate-课程ID-xxx
|
||||
* @return task-evaluate-课程ID
|
||||
*/
|
||||
public static String getShareSetName(String podName) {
|
||||
int index = podName.lastIndexOf("-");
|
||||
return "task-" + podName.substring(0, index);
|
||||
}
|
||||
}
|
|
@ -1,93 +1,96 @@
|
|||
package com.educoder.bridge.docker.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.controller.BaseController;
|
||||
import com.educoder.bridge.common.utils.ClientUtil;
|
||||
import com.educoder.bridge.docker.service.DockerService;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
import com.spotify.docker.client.exceptions.DockerException;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.ClientUtil;
|
||||
import com.educoder.bridge.docker.service.DockerService;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
import com.spotify.docker.client.exceptions.DockerException;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
|
||||
@Api(value = "镜像管理", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/docker")
|
||||
public class DockerController extends BaseController {
|
||||
@Autowired
|
||||
private DockerService dockerService;
|
||||
public class DockerController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DockerController.class);
|
||||
@Autowired
|
||||
private DockerService dockerService;
|
||||
|
||||
@RequestMapping(path = "/images")
|
||||
@ApiOperation(value = "获取全部实训镜像", httpMethod = "GET")
|
||||
public JSONObject getImages() throws DockerException, InterruptedException {
|
||||
logger.info("收到获取镜像请求");
|
||||
@RequestMapping(path = "/images")
|
||||
@ApiOperation(value = "获取全部实训镜像", httpMethod = "GET")
|
||||
public JSONObject getImages() throws DockerException, InterruptedException {
|
||||
logger.info("收到获取镜像请求");
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
// 获取主节点全部镜像
|
||||
DockerClient docker = ClientUtil.getDocker();
|
||||
List<String> imageList = dockerService.getImageList(docker);
|
||||
result.put("images", imageList);
|
||||
JSONObject result = new JSONObject();
|
||||
// 获取主节点全部镜像
|
||||
DockerClient docker = ClientUtil.getDocker();
|
||||
List<String> imageList = dockerService.getImageList(docker);
|
||||
result.put("images", imageList);
|
||||
|
||||
// 获取未同步的镜像
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
List<String> imageDiff = dockerService.imageDiff(imageList, dockerDeputies);
|
||||
result.put("imagesNotSync", imageDiff);
|
||||
// 获取未同步的镜像
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
List<String> imageDiff = dockerService.imageDiff(imageList, dockerDeputies);
|
||||
result.put("imagesNotSync", imageDiff);
|
||||
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
}
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/syncImage")
|
||||
@ApiOperation(value = "同步镜像", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject syncImage(
|
||||
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName)
|
||||
throws DockerException, InterruptedException {
|
||||
logger.info("同步镜像,imageName: {}", imageName);
|
||||
@RequestMapping(path = "/syncImage")
|
||||
@ApiOperation(value = "同步镜像", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject syncImage(
|
||||
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName)
|
||||
throws DockerException, InterruptedException {
|
||||
logger.info("同步镜像,imageName: {}", imageName);
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
DockerClient dockerMaster = ClientUtil.getDocker();
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
DockerClient dockerMaster = ClientUtil.getDocker();
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
|
||||
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
|
||||
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
|
||||
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/updateImage")
|
||||
@ApiOperation(value = "镜像有更新", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject updateImage(
|
||||
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName,
|
||||
@ApiParam(name = "imageID", required = true, value = "旧的镜像ID") @RequestParam String imageID,
|
||||
@ApiParam(name = "flag", required = true, value = "更新行为选择,0更新 1回退") @RequestParam Integer flag)
|
||||
throws DockerException, InterruptedException {
|
||||
logger.info("更新镜像,imageName: {}, imageID: {}, flag: {}", imageName, imageID, flag);
|
||||
@RequestMapping(path = "/updateImage")
|
||||
@ApiOperation(value = "镜像有更新", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject updateImage(
|
||||
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName,
|
||||
@ApiParam(name = "imageID", required = true, value = "旧的镜像ID") @RequestParam String imageID,
|
||||
@ApiParam(name = "flag", required = true, value = "更新行为选择,0更新 1回退") @RequestParam Integer flag)
|
||||
throws DockerException, InterruptedException {
|
||||
logger.info("更新镜像,imageName: {}, imageID: {}, flag: {}", imageName, imageID, flag);
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
DockerClient dockerMaster = ClientUtil.getDocker();
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
DockerClient dockerMaster = ClientUtil.getDocker();
|
||||
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
|
||||
|
||||
if (flag == 0) {
|
||||
// 选择更新
|
||||
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
|
||||
} else {
|
||||
// 选择回退
|
||||
dockerService.resetImage(dockerMaster, imageID, imageName);
|
||||
}
|
||||
if (flag == 0) {
|
||||
// 选择更新
|
||||
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
|
||||
} else {
|
||||
// 选择回退
|
||||
dockerService.resetImage(dockerMaster, imageID, imageName);
|
||||
}
|
||||
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
}
|
||||
result.put("code", 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,54 +3,55 @@
|
|||
*/
|
||||
package com.educoder.bridge.docker.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.controller.BaseController;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* Created by liqiankun on 2017/11/16 0016
|
||||
* Description:
|
||||
* Created by liqiankun on 2017/11/16 0016 Description:
|
||||
*/
|
||||
@Api(value = "资源监控", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/monitor")
|
||||
public class MonitorController extends BaseController {
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
public class MonitorController {
|
||||
|
||||
/**
|
||||
* 简单地获取集群中的Pod总量及各个节点上的Pod分布
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(path = "/getPodsInfo")
|
||||
@ApiOperation(value = "获取集群中某个节点的信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject podsInfo() throws Exception {
|
||||
int podSum = k8sService.getPodSum();
|
||||
List<String> nodeIP = k8sService.getNodesIP();
|
||||
//生成Json格式的返回结果
|
||||
StringBuffer jsonResult = new StringBuffer("[");
|
||||
for (String ip : nodeIP) {
|
||||
int num = k8sService.getPodNum(ip);
|
||||
jsonResult.append("{\"ip\":" + "\"" + ip + "\"," + "\"num\":" + "\"" + num + "\"},");
|
||||
}
|
||||
int length = jsonResult.length() - 1;
|
||||
jsonResult.deleteCharAt(length);
|
||||
jsonResult.append("]");
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("sum", podSum);
|
||||
response.put("distr", jsonResult);
|
||||
response.put("code", 0);
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* 简单地获取集群中的Pod总量及各个节点上的Pod分布
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(path = "/getPodsInfo")
|
||||
@ApiOperation(value = "获取集群中某个节点的信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject podsInfo() throws Exception {
|
||||
int podSum = k8sService.getPodSum();
|
||||
List<String> nodeIP = k8sService.getNodesIP();
|
||||
// 生成Json格式的返回结果
|
||||
StringBuffer jsonResult = new StringBuffer("[");
|
||||
for (String ip : nodeIP) {
|
||||
int num = k8sService.getPodNum(ip);
|
||||
jsonResult.append("{\"ip\":" + "\"" + ip + "\"," + "\"num\":" + "\"" + num + "\"},");
|
||||
}
|
||||
int length = jsonResult.length() - 1;
|
||||
jsonResult.deleteCharAt(length);
|
||||
jsonResult.append("]");
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("sum", podSum);
|
||||
response.put("distr", jsonResult);
|
||||
response.put("code", 0);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,162 +1,168 @@
|
|||
package com.educoder.bridge.docker.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
import com.spotify.docker.client.exceptions.DockerException;
|
||||
import com.spotify.docker.client.messages.Image;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.docker.controller.DockerController;
|
||||
import com.spotify.docker.client.DockerClient;
|
||||
import com.spotify.docker.client.exceptions.DockerException;
|
||||
import com.spotify.docker.client.messages.Image;
|
||||
|
||||
@Service("DockerService")
|
||||
public class DockerService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DockerController.class);
|
||||
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
|
||||
/**
|
||||
* 返回小洞洞做的实训镜像名称列表
|
||||
*
|
||||
* @param docker
|
||||
* @return
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<String> getImageList(DockerClient docker) throws DockerException, InterruptedException {
|
||||
List<String> imageList = new ArrayList<>();
|
||||
List<Image> images = docker.listImages(DockerClient.ListImagesParam.byName("*:v1.0"));
|
||||
for (Image image : images) {
|
||||
for (String imageName : image.repoTags()) {
|
||||
JSONObject jsonObject = new JSONObject(true);
|
||||
jsonObject.put("imageID", image.id().substring(7, 19));
|
||||
jsonObject.put("imageName", imageName);
|
||||
imageList.add(jsonObject.toJSONString());
|
||||
}
|
||||
}
|
||||
return imageList;
|
||||
}
|
||||
/**
|
||||
* 返回小洞洞做的实训镜像名称列表
|
||||
*
|
||||
* @param docker
|
||||
* @return
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<String> getImageList(DockerClient docker) throws DockerException, InterruptedException {
|
||||
List<String> imageList = new ArrayList<>();
|
||||
List<Image> images = docker.listImages(DockerClient.ListImagesParam.byName("*:v1.0"));
|
||||
for (Image image : images) {
|
||||
for (String imageName : image.repoTags()) {
|
||||
JSONObject jsonObject = new JSONObject(true);
|
||||
jsonObject.put("imageID", image.id().substring(7, 19));
|
||||
jsonObject.put("imageName", imageName);
|
||||
imageList.add(jsonObject.toJSONString());
|
||||
}
|
||||
}
|
||||
return imageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主节点镜像同步至子节点
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param dockerDeputies
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void checkNodeImages(DockerClient dockerMaster, List<DockerClient> dockerDeputies)
|
||||
throws DockerException, InterruptedException {
|
||||
// 主节点上的所有镜像列表
|
||||
List<String> images = getImageList(dockerMaster);
|
||||
/**
|
||||
* 主节点镜像同步至子节点
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param dockerDeputies
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void checkNodeImages(DockerClient dockerMaster, List<DockerClient> dockerDeputies)
|
||||
throws DockerException, InterruptedException {
|
||||
// 主节点上的所有镜像列表
|
||||
List<String> images = getImageList(dockerMaster);
|
||||
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
List<String> allImages = new ArrayList<>(images);
|
||||
List<String> deputyImages = getImageList(dockerDeputy);
|
||||
// 取差集,获取多出来的镜像
|
||||
allImages.removeAll(deputyImages);
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
List<String> allImages = new ArrayList<>(images);
|
||||
List<String> deputyImages = getImageList(dockerDeputy);
|
||||
// 取差集,获取多出来的镜像
|
||||
allImages.removeAll(deputyImages);
|
||||
|
||||
for (String image : allImages) {
|
||||
JSONObject imageInfo = JSONObject.parseObject(image);
|
||||
String imageName = imageInfo.getString("imageName");
|
||||
try {
|
||||
// 主节点推,子节点拉
|
||||
dockerPush(dockerMaster, imageName);
|
||||
dockerPull(dockerDeputy, imageName);
|
||||
for (String image : allImages) {
|
||||
JSONObject imageInfo = JSONObject.parseObject(image);
|
||||
String imageName = imageInfo.getString("imageName");
|
||||
try {
|
||||
// 主节点推,子节点拉
|
||||
dockerPush(dockerMaster, imageName);
|
||||
dockerPull(dockerDeputy, imageName);
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 从主节点同步一个镜像到子节点
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param dockerDeputies
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void syncImage(DockerClient dockerMaster, List<DockerClient> dockerDeputies, String imageName)
|
||||
throws DockerException, InterruptedException {
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
dockerPush(dockerMaster, imageName);
|
||||
dockerPull(dockerDeputy, imageName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从主节点同步一个镜像到子节点
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param dockerDeputies
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void syncImage(DockerClient dockerMaster, List<DockerClient> dockerDeputies, String imageName)
|
||||
throws DockerException, InterruptedException {
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
dockerPush(dockerMaster, imageName);
|
||||
dockerPull(dockerDeputy, imageName);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 回退镜像
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param imageID
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void resetImage(DockerClient dockerMaster, String imageID, String imageName)
|
||||
throws DockerException, InterruptedException {
|
||||
dockerMaster.tag(imageID, imageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退镜像
|
||||
*
|
||||
* @param dockerMaster
|
||||
* @param imageID
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void resetImage(DockerClient dockerMaster, String imageID, String imageName) throws DockerException, InterruptedException {
|
||||
dockerMaster.tag(imageID, imageName);
|
||||
}
|
||||
/**
|
||||
* 拉镜像
|
||||
*
|
||||
* @param docker
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void dockerPull(DockerClient docker, String imageName) throws DockerException, InterruptedException {
|
||||
String imageNew = appConfig.getRegistry() + "/" + imageName;
|
||||
docker.pull(imageNew);
|
||||
docker.tag(imageNew, imageName);
|
||||
docker.removeImage(imageNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉镜像
|
||||
*
|
||||
* @param docker
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void dockerPull(DockerClient docker, String imageName) throws DockerException, InterruptedException {
|
||||
String imageNew = appConfig.getRegistry() + "/" + imageName;
|
||||
docker.pull(imageNew);
|
||||
docker.tag(imageNew, imageName);
|
||||
docker.removeImage(imageNew);
|
||||
}
|
||||
/**
|
||||
* 推镜像
|
||||
*
|
||||
* @param docker
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void dockerPush(DockerClient docker, String imageName) throws DockerException, InterruptedException {
|
||||
String imageNew = appConfig.getRegistry() + "/" + imageName;
|
||||
docker.tag(imageName, imageNew);
|
||||
docker.push(imageNew);
|
||||
docker.removeImage(imageNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推镜像
|
||||
*
|
||||
* @param docker
|
||||
* @param imageName
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void dockerPush(DockerClient docker, String imageName) throws DockerException, InterruptedException {
|
||||
String imageNew = appConfig.getRegistry() + "/" + imageName;
|
||||
docker.tag(imageName, imageNew);
|
||||
docker.push(imageNew);
|
||||
docker.removeImage(imageNew);
|
||||
}
|
||||
/**
|
||||
* 找出主节点镜像中,那些没有同步到每个子节点的镜像
|
||||
*
|
||||
* @param images
|
||||
* @param dockerDeputies
|
||||
* @return
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<String> imageDiff(List<String> images, List<DockerClient> dockerDeputies)
|
||||
throws DockerException, InterruptedException {
|
||||
List<String> diffImages = new ArrayList<>();
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
List<String> masterImages = new ArrayList<>(images);
|
||||
List<String> deputyImages = getImageList(dockerDeputy);
|
||||
|
||||
/**
|
||||
* 找出主节点镜像中,那些没有同步到每个子节点的镜像
|
||||
*
|
||||
* @param images
|
||||
* @param dockerDeputies
|
||||
* @return
|
||||
* @throws DockerException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public List<String> imageDiff(List<String> images, List<DockerClient> dockerDeputies)
|
||||
throws DockerException, InterruptedException {
|
||||
List<String> diffImages = new ArrayList<>();
|
||||
for (DockerClient dockerDeputy : dockerDeputies) {
|
||||
List<String> masterImages = new ArrayList<>(images);
|
||||
List<String> deputyImages = getImageList(dockerDeputy);
|
||||
masterImages.removeAll(deputyImages);
|
||||
masterImages.removeAll(diffImages);
|
||||
diffImages.addAll(masterImages);
|
||||
|
||||
masterImages.removeAll(deputyImages);
|
||||
masterImages.removeAll(diffImages);
|
||||
diffImages.addAll(masterImages);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return diffImages;
|
||||
}
|
||||
return diffImages;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.io.File;
|
|||
import java.time.LocalDateTime;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
@ -13,20 +15,17 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.controller.BaseController;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import com.educoder.bridge.common.utils.ShellUtil;
|
||||
import com.educoder.bridge.common.utils.TimeHelper;
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.game.thread.BuildThread;
|
||||
import com.educoder.bridge.game.thread.BuildThreadPersistence;
|
||||
import com.educoder.bridge.k8s.model.BridgePod;
|
||||
import com.educoder.bridge.k8s.service.BridgePodService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
@ -40,15 +39,19 @@ import io.swagger.annotations.ApiParam;
|
|||
@Api(value = "game控制器", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/game")
|
||||
public class GameController extends BaseController {
|
||||
public class GameController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GameController.class);
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
@Autowired
|
||||
private BridgePodService bridgePodService;
|
||||
|
||||
@Autowired
|
||||
@Autowired
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
|
||||
/**
|
||||
|
@ -70,7 +73,6 @@ public class GameController extends BaseController {
|
|||
|
||||
// 对当前TPI,从TPM clone 版本库
|
||||
tpmGitURL = Base64Util.decode(tpmGitURL);
|
||||
tpmGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpmGitURL);
|
||||
gameService.gitClone(tpiWorkSpace, tpmGitURL, "remote_origin", tpiRepoName);
|
||||
|
||||
response.put("code", 0);
|
||||
|
@ -100,26 +102,27 @@ public class GameController extends BaseController {
|
|||
@ApiParam(name = "podType", required = true, value = "pod类型(0.evaluate,1.webssh,2.evassh)") @RequestParam Integer podType,
|
||||
@ApiParam(name = "file", required = false, value = "需要传文件的实训,给出文件存放路径(一个目录)及文件类型") String file,
|
||||
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers,
|
||||
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified)
|
||||
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified,
|
||||
@ApiParam(name = "sec_key", required = false, value = "每一次评测的唯一标识") String sec_key)
|
||||
throws Exception {
|
||||
logger.info(
|
||||
"评测:tpiID: {}, tpiGitURL: {}, buildID: {}, isPublished: {}, instanceChallenge: {}, "
|
||||
+ "testCases: {}, tpmScript: {}, timeLimit: {}, resubmit: {}, "
|
||||
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}",
|
||||
tpiID, tpiGitURL, buildID, isPublished, instanceChallenge, testCases, tpmScript, timeLimit, resubmit, times,
|
||||
needPortMapping, podType, file, containers, content_modified);
|
||||
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}, sec_key: {}",
|
||||
tpiID, tpiGitURL, buildID, isPublished, instanceChallenge, testCases, tpmScript, timeLimit, resubmit,
|
||||
times, needPortMapping, podType, file, containers, content_modified, sec_key);
|
||||
|
||||
// 记录开始时间
|
||||
String evaluateStartTime = LocalDateTime.now().toString();
|
||||
LocalDateTime requestTime = LocalDateTime.now();
|
||||
String evaluateStartTime = requestTime.toString();
|
||||
JSONObject cost = new JSONObject();
|
||||
cost.put("evaluateStartTime", evaluateStartTime);
|
||||
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
|
||||
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
// 参数处理
|
||||
tpiGitURL = Base64Util.decode(tpiGitURL);
|
||||
tpiGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpiGitURL);
|
||||
needPortMapping = needPortMapping == null ? 0 : needPortMapping;
|
||||
timeLimit = timeLimit == null ? Integer.parseInt(appConfig.getDefaultTimeLimit()) : timeLimit;
|
||||
testCases = Base64Util.decode(testCases);
|
||||
|
@ -135,7 +138,7 @@ public class GameController extends BaseController {
|
|||
buildParams.put("tpiID", tpiID);
|
||||
buildParams.put("tpiGitURL", tpiGitURL);
|
||||
buildParams.put("buildID", buildID);
|
||||
buildParams.put("isPublished", isPublished);
|
||||
buildParams.put("isPublished", isPublished);
|
||||
buildParams.put("instanceChallenge", instanceChallenge);
|
||||
buildParams.put("testCases", testCases);
|
||||
buildParams.put("timeLimit", timeLimit);
|
||||
|
@ -145,6 +148,7 @@ public class GameController extends BaseController {
|
|||
buildParams.put("containers", containers);
|
||||
buildParams.put("contentModified", content_modified);
|
||||
buildParams.put("executeTime", executeTime);
|
||||
buildParams.put("sec_key", sec_key);
|
||||
|
||||
// 若实训生成文件 todo:这个处理方式好2b,扩展性极差
|
||||
if (!StringUtils.isEmpty(file)) {
|
||||
|
@ -157,6 +161,9 @@ public class GameController extends BaseController {
|
|||
|
||||
// podName
|
||||
String podName = podType != 2 ? "evaluate-" + tpiID : "evassh-" + tpiID;
|
||||
|
||||
BridgePod bridgePod = bridgePodService.createBridgePod(podName, tpiID, requestTime, sec_key);
|
||||
buildParams.put("bridgePodId", bridgePod.getId());
|
||||
|
||||
// 若需要端口映射服务,则分配端口,将podName-port键值对存储于redis
|
||||
String port = "-1";
|
||||
|
@ -172,8 +179,10 @@ public class GameController extends BaseController {
|
|||
String task = buildParams.toJSONString();
|
||||
// 最大running pod数量
|
||||
int maxRunningPodNum = Integer.parseInt(appConfig.getMaxRunningPodNum());
|
||||
|
||||
// 此次请求只为轮询时间,只返回轮询的时间结果
|
||||
if (times != 1) {
|
||||
logger.debug("轮询,times: {}", times);
|
||||
double buildRank;
|
||||
|
||||
try {
|
||||
|
@ -208,12 +217,14 @@ public class GameController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
// 获取Running状态的pod数
|
||||
int runningPodNum = k8sService.getRunningPodNum();
|
||||
// 判断是否可以立即执行(若pod已经存在,或是,pod不存在但是此时可以创建pod)
|
||||
boolean executeImmediately = k8sService.isPodRunning("tpiID", tpiID)
|
||||
|| (runningPodNum < maxRunningPodNum && k8sService.ableToEvaluate());
|
||||
|
||||
boolean executeImmediately = k8sService.isPodRunning("tpiID", tpiID);
|
||||
if(!executeImmediately) {
|
||||
// 获取Running状态的pod数
|
||||
int runningPodNum = k8sService.getRunningPodNum();
|
||||
boolean able = true; // k8sService.ableToEvaluate();
|
||||
executeImmediately = (runningPodNum < maxRunningPodNum && able);
|
||||
}
|
||||
if (executeImmediately) {
|
||||
// 直接执行任务
|
||||
BuildThread buildThread = gameService.getBuildThread(buildParams);
|
||||
|
@ -244,159 +255,6 @@ public class GameController extends BaseController {
|
|||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 评测: 对每一次评测请求,调用持续化pods进行处理,不需要排队
|
||||
*/
|
||||
@RequestMapping(path = "/persistence/gameEvaluate")
|
||||
@ApiOperation(value = "持续评测", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject persistenceGameEvaluate(
|
||||
@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
|
||||
@ApiParam(name = "tpiGitURL", required = true, value = "学员对应当前实训的版本库地址,需要base64编码") @RequestParam String tpiGitURL,
|
||||
@ApiParam(name = "buildID", required = true, value = "本次评测ID") @RequestParam String buildID,
|
||||
@ApiParam(name = "instanceChallenge", required = true, value = "当前处在第几关") @RequestParam String instanceChallenge,
|
||||
@ApiParam(name = "testCases", required = true, value = "测试用例") @RequestParam String testCases,
|
||||
@ApiParam(name = "tpmScript", required = true, value = "tpm评测脚本,需要base64编码") @RequestParam String tpmScript,
|
||||
@ApiParam(name = "timeLimit", required = false, value = "时间限制") Integer timeLimit,
|
||||
@ApiParam(name = "resubmit", required = true, value = "是否是重复评测") @RequestParam String resubmit,
|
||||
@ApiParam(name = "times", required = true, value = "是否是时间轮询请求") @RequestParam Integer times,
|
||||
@ApiParam(name = "needPortMapping", required = false, value = "容器中需要被映射的端口") Integer needPortMapping,
|
||||
@ApiParam(name = "podType", required = true, value = "pod类型(0.evaluate,1.webssh,2.evassh)") @RequestParam Integer podType,
|
||||
@ApiParam(name = "file", required = false, value = "需要传文件的实训,给出文件存放路径(一个目录)及文件类型") String file,
|
||||
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers,
|
||||
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified,
|
||||
@ApiParam(name = "persistenceName", required = true, value = "持续pods名称") @RequestParam String persistenceName)
|
||||
throws Exception {
|
||||
logger.info(
|
||||
"评测:tpiID: {}, tpiGitURL: {}, buildID: {}, instanceChallenge: {}, "
|
||||
+ "testCases: {}, tpmScript: {}, timeLimit: {}, resubmit: {}, "
|
||||
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}",
|
||||
tpiID, tpiGitURL, buildID, instanceChallenge, testCases, tpmScript, timeLimit, resubmit, times,
|
||||
needPortMapping, podType, file, containers, content_modified);
|
||||
|
||||
|
||||
// 记录开始时间
|
||||
String evaluateStartTime = LocalDateTime.now().toString();
|
||||
JSONObject cost = new JSONObject();
|
||||
cost.put("evaluateStartTime", evaluateStartTime);
|
||||
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
// 参数处理
|
||||
tpiGitURL = Base64Util.decode(tpiGitURL);
|
||||
needPortMapping = needPortMapping == null ? 0 : needPortMapping;
|
||||
timeLimit = timeLimit == null ? Integer.parseInt(appConfig.getDefaultTimeLimit()) : timeLimit - 10;
|
||||
testCases = Base64Util.decode(testCases);
|
||||
containers = Base64Util.decode(containers);
|
||||
|
||||
// 每次评测均生成新TPI评测脚本
|
||||
tpmScript = Base64Util.decode(tpmScript);
|
||||
String tpiWorkspace = appConfig.getWorkspace() + File.separator + "myshixun_" + tpiID;
|
||||
String tpiRepoName = GameHelper.getRepoName(tpiGitURL);
|
||||
gameService.generateTpiEvaluateShellScript(tpmScript, tpiWorkspace, tpiRepoName);
|
||||
|
||||
JSONObject buildParams = new JSONObject(true);
|
||||
buildParams.put("tpiID", tpiID);
|
||||
buildParams.put("tpiGitURL", tpiGitURL);
|
||||
buildParams.put("buildID", buildID);
|
||||
buildParams.put("instanceChallenge", instanceChallenge);
|
||||
buildParams.put("testCases", testCases);
|
||||
buildParams.put("timeLimit", timeLimit);
|
||||
buildParams.put("resubmit", resubmit);
|
||||
buildParams.put("needPortMapping", needPortMapping);
|
||||
buildParams.put("podType", podType);
|
||||
buildParams.put("containers", containers);
|
||||
buildParams.put("contentModified", content_modified);
|
||||
buildParams.put("persistenceName", persistenceName);
|
||||
// 若实训生成文件 todo:这个处理方式好2b,扩展性极差
|
||||
if (!StringUtils.isEmpty(file)) {
|
||||
file = Base64Util.decode(file);
|
||||
buildParams.put("file", file);
|
||||
// 清空目标文件夹以防止影响此次评测结果
|
||||
GameHelper.clearFiles(tpiWorkspace + File.separator + tpiRepoName + File.separator
|
||||
+ JSONObject.parseObject(file).getString("path"));
|
||||
}
|
||||
|
||||
// podName
|
||||
String podName = podType != 2 ? "evaluate-" + tpiID : "evassh-" + tpiID;
|
||||
|
||||
// 若需要端口映射服务,则分配端口,将podName-port键值对存储于redis
|
||||
String port = "-1";
|
||||
if (needPortMapping != -1) {
|
||||
port = JedisUtil.hget("port", podName);
|
||||
if (port == null) {
|
||||
port = PortUtil.getPort() + "";
|
||||
JedisUtil.hset("port", podName, port);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建任务字符串,便于redis存储
|
||||
String task = buildParams.toJSONString();
|
||||
// 最大running pod数量
|
||||
int maxRunningPodNum = Integer.parseInt(appConfig.getMaxRunningPodNum());
|
||||
// 此次请求只为轮询时间,只返回轮询的时间结果
|
||||
if (times != 1) {
|
||||
double buildRank;
|
||||
|
||||
try {
|
||||
buildRank = JedisUtil.zrank("task", task);
|
||||
} catch (Exception e) {
|
||||
response.put("ableToCreate", 0);
|
||||
response.put("waitNum", maxRunningPodNum + JedisUtil.zlen("task"));
|
||||
response.put("code", 0);
|
||||
response.put("msg", "等待评测");
|
||||
return response;
|
||||
}
|
||||
|
||||
if (buildRank != Double.MIN_VALUE) {
|
||||
logger.debug("任务:{} : 还在等待队列中!", task);
|
||||
|
||||
response.put("ableToCreate", 0);
|
||||
response.put("waitNum", buildRank == Double.MAX_VALUE ? maxRunningPodNum + JedisUtil.zlen("task")
|
||||
: buildRank + maxRunningPodNum);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "等待评测");
|
||||
return response;
|
||||
} else {
|
||||
// 轮询时间请求,发现目标任务不在队列,就直接认为其正在运行
|
||||
logger.debug("任务:{} : 正在执行中!", task);
|
||||
|
||||
response.put("ableToCreate", 1);
|
||||
response.put("waitNum", 0);
|
||||
response.put("code", 0);
|
||||
response.put("port", Integer.parseInt(port));
|
||||
response.put("msg", "正在评测");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
// 持续化pods直接处理任务
|
||||
BuildThreadPersistence buildThreadPersistence = (BuildThreadPersistence) BeanFactory
|
||||
.getObejct("BuildThreadPersistence");
|
||||
buildThreadPersistence.setBuildParams(buildParams, Thread.currentThread());
|
||||
threadPoolTaskExecutor.execute(buildThreadPersistence);
|
||||
try {
|
||||
// 主线程等待1秒
|
||||
Thread.sleep(1000);
|
||||
//如果是自己醒来,设置同步返回失败
|
||||
buildThreadPersistence.setSyncSuccess(false);
|
||||
} catch (InterruptedException e) {
|
||||
logger.info("当前容器同步返回数据成功,tpiID:{}, 总消耗时间{}", tpiID, // 评测总时间(除回传结果给educoder之外的总时间)
|
||||
// 当前时间 -
|
||||
// 存储在redis中的开始时间
|
||||
(System.currentTimeMillis() - TimeHelper.convertTimeToMillis(evaluateStartTime)));
|
||||
}
|
||||
response.put("syncResult", buildThreadPersistence.getSyncResult());
|
||||
response.put("ableToCreate", 1);
|
||||
response.put("costTime", System.currentTimeMillis() - TimeHelper.convertTimeToMillis(evaluateStartTime));
|
||||
response.put("waitNum", 0);
|
||||
response.put("code", 0);
|
||||
response.put("port", port);
|
||||
response.put("msg", "评测完成");
|
||||
logger.debug("直接执行任务!task: {}, tpi: {}", response, tpiID);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm版本库已更新,同步
|
||||
*/
|
||||
|
@ -413,25 +271,17 @@ public class GameController extends BaseController {
|
|||
JSONObject response = new JSONObject();
|
||||
|
||||
tpiGitURL = Base64Util.decode(tpiGitURL);
|
||||
tpiGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpiGitURL);
|
||||
tpmGitURL = Base64Util.decode(tpmGitURL);
|
||||
tpmGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpmGitURL);
|
||||
String tpiRepoName = GameHelper.getRepoName(tpiGitURL);
|
||||
String path = appConfig.getWorkspace() + File.separator + "myshixun_" + tpiID;
|
||||
|
||||
try {
|
||||
// 从tpm远程库拉取代码到myshixun版本库然后强推到tpi远程库
|
||||
gameService.gitPullFromTpm(path, tpmGitURL, tpiRepoName);
|
||||
gameService.gitPushToTpi(path, tpiGitURL, identifier);
|
||||
// 从tpm远程库拉取代码到myshixun版本库然后强推到tpi远程库
|
||||
gameService.gitPullFromTpm(path, tpmGitURL, tpiRepoName, tpiID);
|
||||
gameService.gitPushToTpi(path, tpiGitURL, identifier, tpiID);
|
||||
|
||||
logger.debug("tpm库更新内容已同步,tpiID:{}", tpiID);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "版本库更新成功");
|
||||
} catch (GameException e) {
|
||||
logger.error("tpm库更新内容同步失败, tpiID:{}", tpiID);
|
||||
response.put("code", -1);
|
||||
response.put("msg", "版本库同步失败!");
|
||||
}
|
||||
logger.debug("tpm库更新内容已同步,tpiID:{}", tpiID);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "版本库更新成功");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
@ -452,5 +302,4 @@ public class GameController extends BaseController {
|
|||
tpiGitURL = Base64Util.decode(tpiGitURL);
|
||||
return gameService.check(tpiID, tpiGitURL);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,52 +1,88 @@
|
|||
package com.educoder.bridge.game.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.controller.BaseController;
|
||||
import com.educoder.bridge.game.service.VncService;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import com.educoder.bridge.game.service.VncService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
|
||||
@Api(value = "vnc控制器", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/vnc")
|
||||
public class VncController extends BaseController {
|
||||
public class VncController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(VncController.class);
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
|
||||
@Autowired
|
||||
private VncService vncService;
|
||||
@Autowired
|
||||
private VncService vncService;
|
||||
|
||||
@RequestMapping(path = "/getvnc")
|
||||
@ApiOperation(value = "图形界面", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject getvnc(
|
||||
@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
|
||||
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers)
|
||||
throws Exception{
|
||||
logger.info("获取vnc图形界面端口,tpiID: {}, containers: {}", tpiID, containers);
|
||||
@RequestMapping(path = "/getvnc")
|
||||
@ApiOperation(value = "图形界面", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public JSONObject getvnc(@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
|
||||
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers)
|
||||
throws Exception {
|
||||
logger.info("获取vnc图形界面端口,tpiID: {}, containers: {}", tpiID, containers);
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
String podName = "vnc-" + tpiID;
|
||||
containers = Base64Util.decode(containers);
|
||||
String podName = "vnc-" + tpiID;
|
||||
containers = Base64Util.decode(containers);
|
||||
|
||||
// 为vnc分配port
|
||||
String port = JedisUtil.hget("port", podName);
|
||||
if (port == null) {
|
||||
port = PortUtil.getPort() + "";
|
||||
JedisUtil.hset("port", podName, port);
|
||||
}
|
||||
// 为vnc分配port
|
||||
String port = JedisUtil.hget("port-vnc", podName);
|
||||
if (port == null) {
|
||||
port = PortUtil.getPort() + "";
|
||||
JedisUtil.hset("port-vnc", podName, port);
|
||||
}
|
||||
|
||||
vncService.getvnc(tpiID, containers);
|
||||
vncService.getVnc(tpiID, containers);
|
||||
|
||||
response.put("code", 0);
|
||||
response.put("port", port);
|
||||
return response;
|
||||
}
|
||||
response.put("code", 0);
|
||||
response.put("port", port);
|
||||
return response;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除tpiID对应的VNC类型的pod", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@RequestMapping(path = "/delete")
|
||||
public JSONObject delete(@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
|
||||
@ApiParam(name = "digestKey", required = true, value = "签名") @RequestParam String digestKey,
|
||||
@ApiParam(name = "identifier", required = true, value = "game的标示") @RequestParam String identifier)
|
||||
throws Exception {
|
||||
logger.info("前端主动调用vnc删除命令,tpiID: {}", tpiID);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
// 用identifier与私钥拼接与digestKey比较,相等响应,不想等拒绝
|
||||
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
|
||||
if (digestKey.equals(serverDigestKey)) {
|
||||
try {
|
||||
vncService.deleteNow(tpiID);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "成功发起删除命令");
|
||||
} catch (Exception e) {
|
||||
logger.error("主动删除pod失败", e);
|
||||
response.put("code", -1);
|
||||
response.put("msg", "删除pod失败");
|
||||
}
|
||||
} else {
|
||||
response.put("code", -1);
|
||||
response.put("msg", "认证不通过,服务端拒绝连接");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package com.educoder.bridge.game.exception;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* 异常处理类
|
||||
*
|
||||
|
@ -14,28 +19,32 @@ import org.springframework.web.context.request.WebRequest;
|
|||
|
||||
@ControllerAdvice
|
||||
public class ControllerExceptionHandler {
|
||||
@ExceptionHandler(GameException.class)
|
||||
@ResponseBody
|
||||
public JSONObject handleGameExceptions(GameException e, WebRequest request) {
|
||||
JSONObject response = new JSONObject();
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
response.put("code", e.getCode());
|
||||
response.put("msg", e.getMsg());
|
||||
@ExceptionHandler(GameException.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity<JSONObject> handleGameExceptions(GameException e, WebRequest request) {
|
||||
logger.error("捕获到GameException", e);
|
||||
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonObj = new JSONObject();
|
||||
jsonObj.put("code", e.getCode());
|
||||
jsonObj.put("msg", e.getMsg());
|
||||
|
||||
@ExceptionHandler(Throwable.class)
|
||||
@ResponseBody
|
||||
public JSONObject handleOtherExceptions(Throwable e, WebRequest request) {
|
||||
JSONObject response = new JSONObject();
|
||||
ResponseEntity<JSONObject> res = new ResponseEntity<>(jsonObj, HttpStatus.OK);
|
||||
return res;
|
||||
}
|
||||
|
||||
e.printStackTrace();
|
||||
@ExceptionHandler(Throwable.class)
|
||||
@ResponseBody
|
||||
public ResponseEntity<JSONObject> handleOtherExceptions(Throwable e, WebRequest request) {
|
||||
logger.error("捕获到Throwable", e);
|
||||
|
||||
response.put("code", -1);
|
||||
response.put("msg", "未知错误!" + e.getMessage());
|
||||
JSONObject jsonObj = new JSONObject();
|
||||
jsonObj.put("code", -1);
|
||||
jsonObj.put("msg", "未知错误!" + e.getMessage());
|
||||
|
||||
return response;
|
||||
}
|
||||
ResponseEntity<JSONObject> res = new ResponseEntity<>(jsonObj, HttpStatus.OK);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,11 +20,13 @@ public class GameException extends Exception {
|
|||
}
|
||||
|
||||
public GameException(int code, String msg) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public GameException(String msg) {
|
||||
super(msg);
|
||||
this.code = -1;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
|
|
@ -3,38 +3,31 @@
|
|||
*/
|
||||
package com.educoder.bridge.game.exception;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.game.thread.AftermathException;
|
||||
|
||||
/**
|
||||
* 未经捕获的异常处理
|
||||
*
|
||||
* @author weishao
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class UncaughtBridgeExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
private static Logger logger = LoggerFactory.getLogger(UncaughtBridgeExceptionHandler.class);
|
||||
|
||||
private JSONObject buildParams;
|
||||
private Logger logger = LoggerFactory.getLogger(UncaughtBridgeExceptionHandler.class);
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
// 此处只处理善后异常,其它已经在善后处理中解决
|
||||
if (e instanceof AftermathException) {
|
||||
AftermathException ae = (AftermathException) e;
|
||||
JSONObject buildParams = ae.getBuildParams();
|
||||
logger.error("评测线程" + buildParams.getString("tpiID") + "出错,善后异常", e);
|
||||
}
|
||||
|
||||
public UncaughtBridgeExceptionHandler (JSONObject buildParams) {
|
||||
this.buildParams = buildParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
logger.error("评测线程抛出异常:", e);
|
||||
e.printStackTrace();
|
||||
|
||||
String testCases = buildParams.getString("testCases");
|
||||
// 回传错误信息到前台
|
||||
gameService.encapsulateBuildResult(GameHelper.getUnknowErrorResult(JSONObject.parseObject(testCases).size()), buildParams, testCases);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.educoder.bridge.game.filter;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 为每一条日志增加sec_key
|
||||
*/
|
||||
public class LogbackFilter implements Filter {
|
||||
|
||||
// 每一次评测的唯一标识
|
||||
private static final String SEC_KEY = "sec_key";
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
MDC.put(SEC_KEY, request.getParameter("sec_key"));
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
MDC.remove(SEC_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,8 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 评测结果
|
||||
* @author liliy
|
||||
*
|
||||
* @author liliy
|
||||
*/
|
||||
|
||||
public class BuildResult {
|
||||
|
@ -14,6 +15,25 @@ public class BuildResult {
|
|||
private List<Case> msg;
|
||||
private String resubmit;
|
||||
private String compileSuccess;
|
||||
private String createPodStatus;
|
||||
private String downloadStatus;
|
||||
private String sec_key;
|
||||
/**
|
||||
* 步骤。输出分步输出时的步骤
|
||||
*/
|
||||
private String step;
|
||||
/**
|
||||
* 输出存文本
|
||||
*/
|
||||
private String textMsg;
|
||||
|
||||
public String getSec_key() {
|
||||
return sec_key;
|
||||
}
|
||||
|
||||
public void setSec_key(String sec_key) {
|
||||
this.sec_key = sec_key;
|
||||
}
|
||||
|
||||
public String getBuildID() {
|
||||
return buildID;
|
||||
|
@ -55,12 +75,13 @@ public class BuildResult {
|
|||
this.resubmit = resubmit;
|
||||
}
|
||||
|
||||
public BuildResult(String buildID, String status, String outPut, List<Case> msg, String resubmit) {
|
||||
public BuildResult(String buildID, String status, String outPut, List<Case> msg, String resubmit, String sec_key) {
|
||||
this.buildID = buildID;
|
||||
this.status = status;
|
||||
this.outPut = outPut;
|
||||
this.msg = msg;
|
||||
this.resubmit = resubmit;
|
||||
this.sec_key = sec_key;
|
||||
}
|
||||
|
||||
public String getCompileSuccess() {
|
||||
|
@ -70,4 +91,37 @@ public class BuildResult {
|
|||
public void setCompileSuccess(String compileSuccess) {
|
||||
this.compileSuccess = compileSuccess;
|
||||
}
|
||||
|
||||
public String getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public void setStep(String step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
public String getTextMsg() {
|
||||
return textMsg;
|
||||
}
|
||||
|
||||
public void setTextMsg(String textMsg) {
|
||||
this.textMsg = textMsg;
|
||||
}
|
||||
|
||||
public String getCreatePodStatus() {
|
||||
return createPodStatus;
|
||||
}
|
||||
|
||||
public void setCreatePodStatus(String createPodStatus) {
|
||||
this.createPodStatus = createPodStatus;
|
||||
}
|
||||
|
||||
public String getDownloadStatus() {
|
||||
return downloadStatus;
|
||||
}
|
||||
|
||||
public void setDownloadStatus(String downloadStatus) {
|
||||
this.downloadStatus = downloadStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package com.educoder.bridge.game.model;
|
||||
|
||||
/**
|
||||
* 评测结果
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*
|
||||
*/
|
||||
public class EvaluatingResult {
|
||||
|
||||
/**
|
||||
* 整体成功
|
||||
*/
|
||||
Boolean wholeSuccess;
|
||||
/**
|
||||
* 分步失败
|
||||
*/
|
||||
Boolean stepFail;
|
||||
|
||||
public Boolean getWholeSuccess() {
|
||||
return wholeSuccess;
|
||||
}
|
||||
|
||||
public void setWholeSuccess(Boolean wholeSuccess) {
|
||||
this.wholeSuccess = wholeSuccess;
|
||||
}
|
||||
|
||||
public Boolean getStepFail() {
|
||||
return stepFail;
|
||||
}
|
||||
|
||||
public void setStepFail(Boolean stepFail) {
|
||||
this.stepFail = stepFail;
|
||||
}
|
||||
|
||||
public void merge(EvaluatingResult eResult) {
|
||||
if (null != eResult.wholeSuccess) {
|
||||
if (null == this.wholeSuccess) {
|
||||
this.wholeSuccess = eResult.wholeSuccess;
|
||||
} else {
|
||||
this.wholeSuccess = this.wholeSuccess && eResult.wholeSuccess;
|
||||
}
|
||||
}
|
||||
if (null != eResult.stepFail) {
|
||||
if (null == this.stepFail) {
|
||||
this.stepFail = eResult.stepFail;
|
||||
} else {
|
||||
this.stepFail = this.stepFail || eResult.stepFail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTaskSuccess() {
|
||||
return Boolean.TRUE.equals(wholeSuccess) || Boolean.FALSE.equals(stepFail);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.educoder.bridge.game.model;
|
||||
|
||||
public class PodCreateStrategy {
|
||||
|
||||
private Integer timeLimit;
|
||||
|
||||
public Integer getTimeLimit() {
|
||||
return timeLimit;
|
||||
}
|
||||
|
||||
public PodCreateStrategy setTimeLimit(Integer timeLimit) {
|
||||
this.timeLimit = timeLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.educoder.bridge.game.model;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
public class PodRef {
|
||||
private Pod pod;
|
||||
|
||||
public Pod getPod() {
|
||||
return pod;
|
||||
}
|
||||
|
||||
public void setPod(Pod pod) {
|
||||
this.pod = pod;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.educoder.bridge.game.model;
|
||||
|
||||
/**
|
||||
* 简单评测结果
|
||||
*
|
||||
* @author jzx
|
||||
*/
|
||||
|
||||
public class SimpleBuildResult {
|
||||
private String buildID;
|
||||
private String textMsg;
|
||||
|
||||
public String getBuildID() {
|
||||
return buildID;
|
||||
}
|
||||
|
||||
public void setBuildID(String buildID) {
|
||||
this.buildID = buildID;
|
||||
}
|
||||
|
||||
public String getTextMsg() {
|
||||
return textMsg;
|
||||
}
|
||||
|
||||
public void setTextMsg(String textMsg) {
|
||||
this.textMsg = textMsg;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.educoder.bridge.game.model;
|
||||
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
|
||||
import io.fabric8.kubernetes.client.dsl.ExecWatch;
|
||||
|
||||
public class WatchObject {
|
||||
PipedInputStream in;
|
||||
PipedInputStream pis;
|
||||
PipedOutputStream pos;
|
||||
|
||||
ExecWatch watch;
|
||||
|
||||
public PipedInputStream getIn() {
|
||||
return in;
|
||||
}
|
||||
|
||||
public void setIn(PipedInputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public PipedInputStream getPis() {
|
||||
return pis;
|
||||
}
|
||||
|
||||
public void setPis(PipedInputStream pis) {
|
||||
this.pis = pis;
|
||||
}
|
||||
|
||||
public PipedOutputStream getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public void setPos(PipedOutputStream pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public ExecWatch getWatch() {
|
||||
return watch;
|
||||
}
|
||||
|
||||
public void setWatch(ExecWatch watch) {
|
||||
this.watch = watch;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,40 +1,38 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.HttpHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.NioHttpClientUtils;
|
||||
/**
|
||||
* Created by guange on 17/02/2017.
|
||||
*/
|
||||
@Service("EducoderService")
|
||||
public class EducoderService {
|
||||
private final static Logger logger = LoggerFactory.getLogger(EducoderService.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(EducoderService.class);
|
||||
@Autowired
|
||||
AppConfig appConfig;
|
||||
|
||||
@Autowired
|
||||
AppConfig appConfig;
|
||||
public void commitResultToEducoder(Map buildResult) {
|
||||
JSONObject result = new JSONObject(buildResult);
|
||||
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
|
||||
NioHttpClientUtils.sendPost(appConfig.getEducoderURL(), result);
|
||||
}
|
||||
|
||||
public void commitResultToEducoder (Map buildResult){
|
||||
JSONObject result = new JSONObject(buildResult);
|
||||
public void commitResultToEducoder(Map buildResult, int readTimeOut) {
|
||||
JSONObject result = new JSONObject(buildResult);
|
||||
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
|
||||
NioHttpClientUtils.sendPost(appConfig.getEducoderURL(), result, readTimeOut);
|
||||
}
|
||||
|
||||
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
|
||||
|
||||
HttpHelper.sendPost(appConfig.getEducoderURL(), result);
|
||||
}
|
||||
|
||||
public void commitResultToEducoder (Map buildResult, int readTimeOut){
|
||||
JSONObject result = new JSONObject(buildResult);
|
||||
|
||||
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
|
||||
|
||||
HttpHelper.sendPost(appConfig.getEducoderURL(), result, readTimeOut);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public void commitSimpileResultToEducoder(Map buildResult) {
|
||||
JSONObject result = new JSONObject(buildResult);
|
||||
logger.info("educoderURL: {}, result: {}", appConfig.getSimpileEducoderURL(), result);
|
||||
NioHttpClientUtils.sendPost(appConfig.getSimpileEducoderURL(), result);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 暂时不使用
|
||||
*
|
||||
* @author mm
|
||||
*
|
||||
*/
|
||||
@Service("K8sExecService")
|
||||
public class K8sExecService {
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,29 @@
|
|||
|
||||
package com.educoder.bridge.game.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.ShellUtil;
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.omg.CORBA.TIMEOUT;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.ProcessStatusUtil;
|
||||
import com.educoder.bridge.common.utils.ShellUtil;
|
||||
import com.educoder.bridge.common.utils.TpUtils;
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.game.model.BuildResult;
|
||||
import com.educoder.bridge.k8s.service.BridgePodService;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
/**
|
||||
* 与kubernetes交互的service
|
||||
|
@ -25,178 +34,187 @@ import java.util.concurrent.TimeoutException;
|
|||
@Service
|
||||
public class KubernetesService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KubernetesService.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(KubernetesService.class);
|
||||
@Autowired
|
||||
PodManagerService podManagerService;
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
@Autowired
|
||||
private BridgePodService bridgePodService;
|
||||
|
||||
/**
|
||||
* 在pod中执行评测脚本
|
||||
*/
|
||||
public void executeShellInPod(JSONObject buildParams, Pod pod, int needPortMapping, int timeLimit, int isPublished,
|
||||
int instanceChallenge, String testCases) {
|
||||
String podName = pod.getMetadata().getName();
|
||||
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, isPublished: {}, instanceChallenge: {}", podName,
|
||||
needPortMapping, timeLimit, isPublished, instanceChallenge);
|
||||
// 在pod中限时执行评测脚本
|
||||
// 设置输入数组
|
||||
StringBuilder ins = new StringBuilder();
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
for (int i = 0; i < cases.size(); i++) {
|
||||
String input = cases.getJSONObject(i).getString("input");
|
||||
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
|
||||
}
|
||||
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
|
||||
String tpiID = buildParams.getString("tpiID");
|
||||
String buildID = buildParams.getString("buildID");
|
||||
String tpiWorkspace = TpUtils.buildTpiWorkspace(appConfig.getWorkspace(), tpiID);
|
||||
String shFile = tpiWorkspace + "/evaluate.sh";
|
||||
String command = "kubectl exec " + podName + " timeout " + timeLimit + " bash " + shFile + " " + instanceChallenge + " " + ins;
|
||||
logger.info("evaluate command: {}", command);
|
||||
// 为pod的score加1,若pod之前不存在,则score为1
|
||||
JedisUtil.zup("taskNum", podName);
|
||||
Instant executeStartInstant = Instant.now();
|
||||
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command);
|
||||
int exitStatus = buildResult.getInteger("exitStatus");
|
||||
String out = buildResult.getString("out");
|
||||
JSONObject timeCost = this.recordExecuteTime(executeStartInstant, tpiID, buildID);
|
||||
BuildResult result = processResult(buildParams, podName, needPortMapping, timeLimit, isPublished, instanceChallenge, testCases,
|
||||
command, exitStatus, out);// timeout, 繁忙
|
||||
boolean taskResult = "0".equals(result.getStatus());
|
||||
if (taskResult) { // 如果正常完成,清理资源。
|
||||
clearResource(podName);
|
||||
}
|
||||
bridgePodService.updateExecuteTime(buildParams, timeCost, pod, result);
|
||||
JedisUtil.del("timeCost:" + tpiID + ":" + buildID);
|
||||
}
|
||||
|
||||
private JSONObject recordExecuteTime(Instant executeStartInstant, String tpiID, String buildID) {
|
||||
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
|
||||
JSONObject timeCost = GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute",
|
||||
String.format("%.3f", executeCost));
|
||||
return timeCost;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
PodManagerService podManagerService;
|
||||
public BuildResult processResult(JSONObject buildParams, String podName, int needPortMapping, int timeLimit,
|
||||
int isPublished, int instanceChallenge, String testCases, String command, int exitStatus, String out) {
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
if (ProcessStatusUtil.isTimeout(exitStatus)) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
String oriOut = out;
|
||||
// 为了避免其他输出干扰结果判断,仅提取平台封装输出
|
||||
out = GameHelper.getRealResult(out);
|
||||
// 如果不是调试模式
|
||||
if (isPublished == 1) {
|
||||
// 正式环境下,如果结果为空或者不是有效的json格式,报系统繁忙
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
debugErrorOut(command, oriOut, out);
|
||||
out = GameHelper.getUnknowErrorResult(cases.size());
|
||||
}
|
||||
} else {
|
||||
// 测试环境下,如果提出自定义输出后,结果为空或者不是有效的json格式,可判定为脚本错误
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
out = GameHelper.getShellErrorResult(cases.size(), oriOut);
|
||||
} else { // 否则为正常输出
|
||||
if (!out.equals(oriOut)) { // 对于正常输出,如果没有任何冗余,不予提示,否则提示为调试模式
|
||||
JSONObject buildOutAndOriOut = JSONObject.parseObject(out);
|
||||
buildOutAndOriOut.put("oriOut", oriOut);
|
||||
out = buildOutAndOriOut.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 此时已经在pod中执行完评测脚本,pod失去了一个『正在执行』任务.
|
||||
// 大多数情况下,此时该pod对应的score为0,即无任务,将该pod从zset中移除,表示这不再是一个任务运行期pod
|
||||
JedisUtil.zdown("taskNum", podName);
|
||||
return gameService.encapsulateBuildResult(out, buildParams, testCases);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在pod中执行评测脚本
|
||||
*/
|
||||
public String executeShellInPod(String podName, int needPortMapping, int timeLimit, int isPublished, int instanceChallenge,
|
||||
String testCases) {
|
||||
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, isPublished: {}, instanceChallenge: {}",
|
||||
podName, needPortMapping, timeLimit, isPublished, instanceChallenge);
|
||||
private void clearResource(String podName) {
|
||||
if (!svcExist(podName) && !svcExist(podName + "-22") // 22的特殊处理
|
||||
&& !JedisUtil.zhas("taskNum", podName)) {
|
||||
deletePod(podName);
|
||||
}
|
||||
gameService.executeWaitingTask();
|
||||
}
|
||||
|
||||
// 设置输入数组
|
||||
StringBuffer ins = new StringBuffer();
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
for (int i = 0; i < cases.size(); i++) {
|
||||
String input = cases.getJSONObject(i).getString("input");
|
||||
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
|
||||
}
|
||||
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
|
||||
/**
|
||||
* 在pod中执行评测脚本
|
||||
*/
|
||||
public String executePersistenceShellInPod(String podName, String tpiID, int needPortMapping, int timeLimit,
|
||||
int instanceChallenge, String testCases) throws GameException {
|
||||
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, instanceChallenge: {}", podName, needPortMapping,
|
||||
timeLimit, instanceChallenge);
|
||||
// 设置输入数组
|
||||
StringBuffer ins = new StringBuffer();
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
for (int i = 0; i < cases.size(); i++) {
|
||||
String input = cases.getJSONObject(i).getString("input");
|
||||
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
|
||||
}
|
||||
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
|
||||
int setTimeLimit = timeLimit / 2;
|
||||
// 拼接出k8s执行命令
|
||||
String command = "timeout " + setTimeLimit + " kubectl exec " + podName + " bash " + appConfig.getWorkspace()
|
||||
+ "/myshixun_" + tpiID + "/evaluate.sh " + instanceChallenge + " " + ins;
|
||||
logger.debug("evaluate command: {}", command);
|
||||
// 为pod的score加1,若pod之前不存在,则score为1
|
||||
JedisUtil.zup("taskNum", podName);
|
||||
// 在pod中限时执行评测脚本
|
||||
String out;
|
||||
try {
|
||||
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command, 1);
|
||||
out = buildResult.getString("out");
|
||||
// todo: 有时候不抛异常,只是任务被kill掉,很奇怪?
|
||||
if (buildResult.getInteger("exitStatus") == 137) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
if (StringUtils.isBlank(out)) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
String oriOut = out;
|
||||
// 为了避免其他输出干扰结果判断,仅提取平台封装输出
|
||||
out = GameHelper.getRealResult(out);
|
||||
// 如果结果为空或者不是有效的json格式,可判定为脚本错误
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
debugErrorOut(command, oriOut, out);
|
||||
out = GameHelper.getShellErrorResult(cases.size(), out);
|
||||
}
|
||||
// 此时已经在pod中执行完评测脚本,pod失去了一个『正在执行』任务.
|
||||
// 大多数情况下,此时该pod对应的score为0,即无任务,将该pod从zset中移除,表示这不再是一个任务运行期pod
|
||||
JedisUtil.zdown("taskNum", podName);
|
||||
return out;
|
||||
}
|
||||
|
||||
// 拼接出k8s执行命令
|
||||
String command = "timeout " + timeLimit + " kubectl exec " + podName + " bash "
|
||||
+ "/data/workspace/myshixun_" + podName.split("-")[1] + "/evaluate.sh " + instanceChallenge + " " + ins;
|
||||
/**
|
||||
* 输出执行信息
|
||||
*
|
||||
* @param command
|
||||
* @param oriOut
|
||||
* @param out
|
||||
*/
|
||||
private void debugErrorOut(String command, String oriOut, String out) {
|
||||
logger.info("执行命令:{}, 原始输出:{}, 最终输出: {}", command, oriOut, out);
|
||||
}
|
||||
|
||||
logger.debug("evaluate command: {}", command);
|
||||
/**
|
||||
* 需要端口映射服务的pod,判断其svc是否存在
|
||||
*
|
||||
* @param podName
|
||||
* @return
|
||||
*/
|
||||
public boolean svcExist(String podName) {
|
||||
return k8sService.svcExist(podName);
|
||||
}
|
||||
|
||||
// 为pod的score加1,若pod之前不存在,则score为1
|
||||
JedisUtil.zup("taskNum", podName);
|
||||
|
||||
// 在pod中限时执行评测脚本
|
||||
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command);
|
||||
String out = buildResult.getString("out");
|
||||
|
||||
// 详见timeout的help说明
|
||||
if (buildResult.getInteger("exitStatus") == 124 || buildResult.getInteger("exitStatus") == (128 + 9)) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
|
||||
String oriOut = out;
|
||||
// 为了避免其他输出干扰结果判断,仅提取平台封装输出
|
||||
out = GameHelper.getRealResult(out);
|
||||
|
||||
// 如果不是调试模式
|
||||
if (isPublished == 1) {
|
||||
// 正式环境下,如果结果为空或者不是有效的json格式,报系统繁忙
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
debugErrorOut(command, oriOut, out);
|
||||
out = GameHelper.getUnknowErrorResult(cases.size());
|
||||
}
|
||||
} else {
|
||||
// 测试环境下,如果提出自定义输出后,结果为空或者不是有效的json格式,可判定为脚本错误
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
out = GameHelper.getShellErrorResult(cases.size(), oriOut);
|
||||
} else { // 否则为正常输出
|
||||
if (!out.equals(oriOut)) { // 对于正常输出,如果没有任何冗余,不予提示,否则提示为调试模式
|
||||
JSONObject buildOutAndOriOut = JSONObject.parseObject(out);
|
||||
buildOutAndOriOut.put("oriOut", oriOut);
|
||||
out = buildOutAndOriOut.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 此时已经在pod中执行完评测脚本,pod失去了一个『正在执行』任务.
|
||||
// 大多数情况下,此时该pod对应的score为0,即无任务,将该pod从zset中移除,表示这不再是一个任务运行期pod
|
||||
JedisUtil.zdown("taskNum", podName);
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在pod中执行评测脚本
|
||||
*/
|
||||
public String executePersistenceShellInPod(String podName,String tpiID, int needPortMapping, int timeLimit, int instanceChallenge,
|
||||
String testCases) throws GameException {
|
||||
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, instanceChallenge: {}",
|
||||
podName, needPortMapping, timeLimit, instanceChallenge);
|
||||
|
||||
// 设置输入数组
|
||||
StringBuffer ins = new StringBuffer();
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
for (int i = 0; i < cases.size(); i++) {
|
||||
String input = cases.getJSONObject(i).getString("input");
|
||||
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
|
||||
}
|
||||
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
|
||||
int setTimeLimit = timeLimit/2;
|
||||
// 拼接出k8s执行命令
|
||||
String command = "timeout " + setTimeLimit + " kubectl exec " + podName + " bash "
|
||||
+ "/data/workspace/myshixun_" + tpiID + "/evaluate.sh " + instanceChallenge + " " + ins;
|
||||
|
||||
logger.debug("evaluate command: {}", command);
|
||||
|
||||
// 为pod的score加1,若pod之前不存在,则score为1
|
||||
JedisUtil.zup("taskNum", podName);
|
||||
|
||||
// 在pod中限时执行评测脚本
|
||||
String out;
|
||||
try {
|
||||
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command, 1);
|
||||
out = buildResult.getString("out");
|
||||
|
||||
// todo: 有时候不抛异常,只是任务被kill掉,很奇怪?
|
||||
if (buildResult.getInteger("exitStatus") == 137) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
if(StringUtils.isBlank(out)){
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
|
||||
}
|
||||
|
||||
String oriOut = out;
|
||||
// 为了避免其他输出干扰结果判断,仅提取平台封装输出
|
||||
out = GameHelper.getRealResult(out);
|
||||
// 如果结果为空或者不是有效的json格式,可判定为脚本错误
|
||||
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
|
||||
debugErrorOut(command, oriOut, out);
|
||||
out = GameHelper.getShellErrorResult(cases.size(), out);
|
||||
}
|
||||
|
||||
// 此时已经在pod中执行完评测脚本,pod失去了一个『正在执行』任务.
|
||||
// 大多数情况下,此时该pod对应的score为0,即无任务,将该pod从zset中移除,表示这不再是一个任务运行期pod
|
||||
JedisUtil.zdown("taskNum", podName);
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出执行信息
|
||||
* @param command
|
||||
* @param oriOut
|
||||
* @param out
|
||||
*/
|
||||
private void debugErrorOut(String command, String oriOut, String out) {
|
||||
logger.info("执行命令:{}, 原始输出:{}, 最终输出: {}",
|
||||
command, oriOut, out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 需要端口映射服务的pod,判断其svc是否存在
|
||||
*
|
||||
* @param podName
|
||||
* @return
|
||||
*/
|
||||
public boolean svcExist(String podName) {
|
||||
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
|
||||
if (out.getInteger("exitStatus") == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除pod
|
||||
* @param podName
|
||||
*/
|
||||
public void deletePod(String podName) {
|
||||
// 若Pod的删除定时任务之前已经生成,则取消
|
||||
podManagerService.cancelDel(podName);
|
||||
|
||||
logger.info("直接删除pod:{}", podName);
|
||||
String command = "kubectl delete pod " + podName + " --now";
|
||||
ShellUtil.executeAndGetExitStatus(command);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 删除pod
|
||||
*
|
||||
* @param podName
|
||||
*/
|
||||
public void deletePod(String podName) {
|
||||
// 若Pod的删除定时任务之前已经生成,则取消
|
||||
podManagerService.cancelDel(podName);
|
||||
k8sService.deletePod(podName);
|
||||
}
|
||||
}
|
|
@ -1,110 +1,104 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.ShellUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
/**
|
||||
* pod生命周期管理
|
||||
*/
|
||||
@Service
|
||||
public class PodManagerService {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final ConcurrentHashMap<String, Long> deleteTimeMap = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
private final ConcurrentHashMap<String, Long> deleteTimeMap = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 在指定时间删除pod 重复调用,可以重置设定
|
||||
*
|
||||
* @param podName
|
||||
* @param delayTime
|
||||
* 单位秒
|
||||
*/
|
||||
public void deletePodAfterTime(String podName, long delayTime) {
|
||||
deleteTimeMap.put(podName, System.currentTimeMillis() + delayTime * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定时间删除pod
|
||||
* 重复调用,可以重置设定
|
||||
*
|
||||
* @param podName
|
||||
* @param delayTime 单位秒
|
||||
*/
|
||||
public void deletePodAfterTime(String podName, long delayTime) {
|
||||
deleteTimeMap.put(podName, System.currentTimeMillis() + delayTime * 1000);
|
||||
}
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
new Thread(() -> {
|
||||
this.doWork();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void doWork() {
|
||||
AtomicBoolean hasDel = new AtomicBoolean(false);
|
||||
while (true) {
|
||||
hasDel.set(false);
|
||||
deleteTimeMap.forEach((podName, delTime) -> {
|
||||
if (delTime < System.currentTimeMillis()) {
|
||||
hasDel.set(true);
|
||||
try {
|
||||
delPod(podName);
|
||||
} catch (Exception e) {
|
||||
logger.error("delPod:" + podName, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
if (!hasDel.get()) {
|
||||
Thread.sleep(1000);
|
||||
} // 没任务,休眠2秒
|
||||
} catch (Exception e) {
|
||||
// ignore quietly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init(){
|
||||
new Thread(() -> {
|
||||
this.doWork();
|
||||
}).start();
|
||||
}
|
||||
// TODO 不需要 synchronized
|
||||
private synchronized void delService(String podName) {
|
||||
Boolean r = k8sService.deleteService(podName);
|
||||
logger.info("定时任务:删除实训 {} service结果:{}", podName, r);
|
||||
if (Boolean.TRUE.equals(r)) {
|
||||
JedisUtil.hdel("port", podName);
|
||||
JedisUtil.hdel("port1", podName);
|
||||
logger.info("定时任务: 删除pod {}对应的port", podName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void doWork() {
|
||||
AtomicBoolean hasDel = new AtomicBoolean(false);
|
||||
// TODO 不需要 synchronized
|
||||
private synchronized void delPod(String podName) throws Exception {
|
||||
// 将本定时任务从deleteTimeMap中去除
|
||||
deleteTimeMap.remove(podName);
|
||||
// 根据podName来删除pod
|
||||
Boolean r = k8sService.deletePod(podName);
|
||||
logger.info("定时任务: 删除pod {}结果: {}", podName, r);
|
||||
if (Boolean.TRUE.equals(r)) {
|
||||
delService(podName);
|
||||
delService(podName + "-22"); // 特殊处理-22的服务
|
||||
}
|
||||
// 一个pod被删除,则执行一个正在等待的任务
|
||||
GameService gameService = (GameService) BeanFactory.getObejct("GameService");
|
||||
gameService.executeWaitingTask();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
hasDel.set(false);
|
||||
|
||||
deleteTimeMap.forEach((podName, delTime) -> {
|
||||
if (delTime < System.currentTimeMillis()) {
|
||||
hasDel.set(true);
|
||||
|
||||
try {
|
||||
delPod(podName);
|
||||
} catch (Exception e) {
|
||||
logger.error("delPod", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
if(!hasDel.get()) {Thread.sleep(1000);} //没任务,休眠2秒
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void delService(String podName, JSONObject result){
|
||||
// 若存在端口映射service,则一并删除
|
||||
JSONObject svc = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
|
||||
if (result.getInteger("exitStatus") == 0 && svc.getInteger("exitStatus") == 0) {
|
||||
logger.info("定时任务: 删除pod对应的service: {}", podName);
|
||||
// 根据podName删除service
|
||||
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl delete service " + podName + " --now");
|
||||
// 移除tpi-port键值对
|
||||
JedisUtil.hdel("port", podName);
|
||||
JedisUtil.hdel("port1", podName);
|
||||
|
||||
logger.info("定时任务:删除service结果:{}", out.getString("out"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private synchronized void delPod(String podName) throws Exception {
|
||||
// 根据podName来删除pod
|
||||
JSONObject result = ShellUtil.executeAndGetExitStatus("kubectl delete pod " + podName + " --now");
|
||||
logger.info("定时任务: 删除pod-{}结果: {}", podName, result.getString("out"));
|
||||
|
||||
delService(podName, result);
|
||||
delService(podName+"-22", result); //特殊处理-22的服务
|
||||
|
||||
// 将本定时任务从deleteTimeMap中去除
|
||||
deleteTimeMap.remove(podName);
|
||||
|
||||
// 一个pod被删除,则执行一个正在等待的任务
|
||||
GameService gameService = (GameService) BeanFactory.getObejct("GameService");
|
||||
gameService.executeWaitingTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消删除
|
||||
*/
|
||||
public synchronized void cancelDel(String podName) {
|
||||
if (deleteTimeMap.containsKey(podName)) {
|
||||
deleteTimeMap.remove(podName);
|
||||
logger.info("取消定时删除,podName: {}", podName);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 取消删除
|
||||
*/
|
||||
// TODO 不需要 synchronized
|
||||
public synchronized void cancelDel(String podName) {
|
||||
if (deleteTimeMap.containsKey(podName)) {
|
||||
deleteTimeMap.remove(podName);
|
||||
logger.info("取消定时删除,podName: {}", podName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ResourceFileService {
|
||||
|
||||
private final ConcurrentHashMap<String, String> cacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
public String getResourceFileContent(String name) {
|
||||
String content = cacheMap.get(name);
|
||||
if (content == null) {
|
||||
content = this.readResourceFileContent(name);
|
||||
cacheMap.put(name, content);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private String readResourceFileContent(String name) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = this.getClass().getClassLoader().getResourceAsStream(name);
|
||||
String c = IOUtils.toString(in, Charsets.toCharset("UTF-8"));
|
||||
return c;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("读取资源文件" + name + "失败", e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.game.model.WatchObject;
|
||||
|
||||
import io.fabric8.kubernetes.client.dsl.ExecWatch;
|
||||
|
||||
/**
|
||||
* shell 执行时间管理
|
||||
*/
|
||||
@Service
|
||||
public class ShellExecManageService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final ConcurrentHashMap<Long, ExecTime> execTimeMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final AtomicLong key = new AtomicLong(1);
|
||||
|
||||
private static class ExecTime {
|
||||
private WatchObject wo;
|
||||
private Long overtime;
|
||||
private String podName;
|
||||
|
||||
public ExecTime(WatchObject wo, Long overtime, String podName) {
|
||||
super();
|
||||
this.wo = wo;
|
||||
this.overtime = overtime;
|
||||
this.podName = podName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入执行时间
|
||||
*
|
||||
* @param execWatch
|
||||
* @param delayTime
|
||||
* 单位秒
|
||||
*/
|
||||
public Long putExecTime(WatchObject wo, long delayTime, String podName) {
|
||||
long overtime = System.currentTimeMillis() + delayTime * 1000;
|
||||
ExecTime execTime = new ExecTime(wo, overtime, podName);
|
||||
Long k = key.incrementAndGet();
|
||||
execTimeMap.put(k, execTime);
|
||||
return k;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
new Thread(() -> {
|
||||
this.doWork();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void doWork() {
|
||||
AtomicBoolean hasDel = new AtomicBoolean(false);
|
||||
|
||||
while (true) {
|
||||
hasDel.set(false);
|
||||
|
||||
execTimeMap.forEach((execKey, execTime) -> {
|
||||
if (execTime.overtime < System.currentTimeMillis()) {
|
||||
hasDel.set(true);
|
||||
|
||||
try {
|
||||
overtime(execKey, execTime);
|
||||
} catch (Exception e) {
|
||||
logger.error("pod [" + execTime.podName + "] 评测超时,关闭连接发生异常", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasDel.get()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
// ignore quietly
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 超时处理
|
||||
*
|
||||
* @param execKey
|
||||
* @param execTime
|
||||
* @throws Exception
|
||||
*/
|
||||
private void overtime(Long execKey, ExecTime execTime) throws Exception {
|
||||
|
||||
// KubernetesService.close(execTime.podName,
|
||||
// execTime.wo.getWatch(),
|
||||
// execTime.wo.getIn(),
|
||||
// execTime.wo.getPis(),
|
||||
// execTime.wo.getPos());
|
||||
|
||||
execTimeMap.remove(execKey);
|
||||
logger.info("pod [{}] 评测超时,关闭连接", execTime.podName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 已经完成,删除执行时间
|
||||
*/
|
||||
public void removeExecTime(Long execKey) {
|
||||
execTimeMap.remove(execKey);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,24 +1,89 @@
|
|||
package com.educoder.bridge.game.service;
|
||||
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import com.educoder.bridge.common.utils.TimeHelper;
|
||||
import com.educoder.bridge.webssh.model.Webssh;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* Created by zzx on 17/12/29.
|
||||
*/
|
||||
@Service("VncService")
|
||||
public class VncService {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(VncService.class);
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
public void getvnc(String tpiID, String containers) {
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
@Autowired
|
||||
private PodManagerService podManagerService;
|
||||
/**
|
||||
* 创建VNC连接需要的pod和svc
|
||||
* @param tpiID
|
||||
* @param containers
|
||||
*/
|
||||
public void getVnc(String tpiID, String containers) {
|
||||
logger.debug("tpiID: {}, podType: {}", tpiID, "vnc");
|
||||
String podName = "vnc-" + tpiID;
|
||||
// 查看pod是否已经存在
|
||||
Pod pod = k8sService.getPod(podName);
|
||||
boolean existPod = false;
|
||||
if(pod != null) {
|
||||
String phase = pod.getStatus().getPhase();
|
||||
if ("Running".equals(phase)) {
|
||||
existPod = true;
|
||||
} else {
|
||||
k8sService.deletePod(podName);
|
||||
logger.info("获取vnc连接信息,delete 处于{}状态的 pod {}", phase, podName);
|
||||
}
|
||||
}
|
||||
// 创建pod(type直接为vnc)
|
||||
k8sService.createPod(podName, tpiID, "vnc", containers);
|
||||
if (!existPod) {
|
||||
k8sService.createPod(podName, tpiID, "vnc", containers, null);
|
||||
}
|
||||
// 创建svc
|
||||
int vncPort = Integer.parseInt(JedisUtil.hget("port", podName));
|
||||
k8sService.createService(podName, tpiID, 8080, vncPort);
|
||||
boolean existService = k8sService.svcExist(podName);
|
||||
if (!existService) {
|
||||
int vncPort = Integer.parseInt(JedisUtil.hget("port-vnc", podName));
|
||||
k8sService.createService(podName, tpiID, appConfig.getVncPort(), vncPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 直接删除
|
||||
*
|
||||
* @param tpiID
|
||||
* @throws Exception
|
||||
*/
|
||||
public void deleteNow(String tpiID) throws Exception {
|
||||
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
|
||||
String podName = getPodNameFromTpiId(tpiID);
|
||||
if (StringUtils.isEmpty(podName)) {
|
||||
return;
|
||||
}
|
||||
// 删除pod及svc
|
||||
podManagerService.deletePodAfterTime(podName, 0);
|
||||
// 移除占用的端口
|
||||
JedisUtil.hdel("port-vnc", podName);
|
||||
}
|
||||
/**
|
||||
* 通过tpiID获取podName
|
||||
*
|
||||
* @param tpiID
|
||||
* @return
|
||||
*/
|
||||
private String getPodNameFromTpiId(String tpiID) {
|
||||
Map<String, String> inLabels = new HashMap<>();
|
||||
inLabels.put("tpiID", tpiID);
|
||||
inLabels.put("type", "vnc");
|
||||
Map<String, String> notInLabels = new HashMap<>();
|
||||
Pod pod = k8sService.getK8sPod(inLabels, notInLabels);
|
||||
return pod == null ? null : pod.getMetadata().getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.educoder.bridge.game.thread;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* 善后异常,评测线程出错,善后处理发生的异常。
|
||||
*
|
||||
* @author mumu
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AftermathException extends RuntimeException {
|
||||
JSONObject buildParams = null;
|
||||
|
||||
public AftermathException(String message, Throwable cause, JSONObject buildParams) {
|
||||
super(message, cause);
|
||||
this.buildParams = buildParams;
|
||||
}
|
||||
|
||||
public JSONObject getBuildParams() {
|
||||
return buildParams;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.educoder.bridge.game.thread;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
|
||||
public class BridgeThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public BridgeThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
|
||||
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
|
||||
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject buildParams = null;
|
||||
try {
|
||||
BuildThread task = (BuildThread) r;
|
||||
buildParams = task.getBuildParams();
|
||||
|
||||
String tpiID = buildParams.getString("tpiID");
|
||||
logger.error("评测线程" + tpiID + "出错", t);
|
||||
|
||||
String testCases = buildParams.getString("testCases");
|
||||
// 回传错误信息到前台
|
||||
GameService gameService = BeanFactory.getObejct(GameService.class);
|
||||
gameService.encapsulateBuildResult(
|
||||
GameHelper.getUnknowErrorResult(JSONObject.parseObject(testCases).size()), buildParams, testCases);
|
||||
} catch (Throwable e) {
|
||||
throw new AftermathException("评测线程出错,善后处理发生异常", e, buildParams);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package com.educoder.bridge.game.thread;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BridgeThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
|
||||
|
||||
private int queueCapacity = Integer.MAX_VALUE;
|
||||
|
||||
private TaskDecorator taskDecorator;
|
||||
|
||||
private boolean allowCoreThreadTimeOut = false;
|
||||
|
||||
/**
|
||||
* 所有线程都会委托给这个execute方法,在这个方法中我们把父线程的MDC内容赋值给子线程
|
||||
* https://logback.qos.ch/manual/mdc.html#managedThreads
|
||||
*
|
||||
* @param runnable
|
||||
*/
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
// 获取父线程MDC中的内容,必须在run方法之前,否则等异步线程执行的时候有可能MDC里面的值已经被清空了,这个时候就会返回null
|
||||
Map<String, String> context = MDC.getCopyOfContextMap();
|
||||
super.execute(() -> run(runnable, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 子线程委托的执行方法
|
||||
*
|
||||
* @param runnable {@link Runnable}
|
||||
* @param context 父线程MDC内容
|
||||
*/
|
||||
private void run(Runnable runnable, Map<String, String> context) {
|
||||
// 将父线程的MDC内容传给子线程
|
||||
MDC.setContextMap(context);
|
||||
try {
|
||||
// 执行异步操作
|
||||
runnable.run();
|
||||
} finally {
|
||||
// 清空MDC内容
|
||||
MDC.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
Thread t = super.newThread(runnable);
|
||||
UncaughtBridgeExceptionHandler eh = BeanFactory.getObejct(UncaughtBridgeExceptionHandler.class);
|
||||
t.setUncaughtExceptionHandler(eh);
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutorService initializeExecutor(ThreadFactory threadFactory,
|
||||
RejectedExecutionHandler rejectedExecutionHandler) {
|
||||
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
|
||||
|
||||
ThreadPoolExecutor executor;
|
||||
if (this.taskDecorator != null) {
|
||||
// 使用 BridgeThreadPoolExecutor 执行 afterExecute, 处理异常情况
|
||||
executor = new BridgeThreadPoolExecutor(super.getCorePoolSize(), super.getMaxPoolSize(),
|
||||
super.getKeepAliveSeconds(), TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
super.execute(taskDecorator.decorate(command));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// 使用 BridgeThreadPoolExecutor 执行 afterExecute, 处理异常情况
|
||||
executor = new BridgeThreadPoolExecutor(super.getCorePoolSize(), super.getMaxPoolSize(),
|
||||
super.getKeepAliveSeconds(), TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
|
||||
|
||||
}
|
||||
|
||||
if (this.allowCoreThreadTimeOut) {
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
}
|
||||
|
||||
Field field = ReflectionUtils.findField(ThreadPoolTaskExecutor.class, "threadPoolExecutor",
|
||||
ThreadPoolExecutor.class);
|
||||
field.setAccessible(true);
|
||||
ReflectionUtils.setField(field, this, executor);
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setQueueCapacity(int queueCapacity) {
|
||||
super.setQueueCapacity(queueCapacity);
|
||||
this.queueCapacity = queueCapacity;
|
||||
|
||||
}
|
||||
|
||||
public void setTaskDecorator(TaskDecorator taskDecorator) {
|
||||
super.setTaskDecorator(taskDecorator);
|
||||
this.taskDecorator = taskDecorator;
|
||||
}
|
||||
|
||||
public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
|
||||
super.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);
|
||||
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +1,5 @@
|
|||
package com.educoder.bridge.game.thread;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.game.service.KubernetesService;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
@ -27,6 +10,29 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.constant.BuildResultCsts;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.game.model.PodCreateStrategy;
|
||||
import com.educoder.bridge.game.model.PodRef;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.game.service.KubernetesService;
|
||||
import com.educoder.bridge.k8s.service.BridgePodService;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
/**
|
||||
* 评测线程
|
||||
*
|
||||
|
@ -37,6 +43,7 @@ import java.util.concurrent.Future;
|
|||
@Service("BuildThread")
|
||||
@Scope("prototype")
|
||||
public class BuildThread extends Thread {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
@Autowired
|
||||
|
@ -45,11 +52,12 @@ public class BuildThread extends Thread {
|
|||
private AppConfig appConfig;
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
@Autowired
|
||||
private BridgePodService bridgePodService;
|
||||
|
||||
private JSONObject buildParams;
|
||||
|
||||
public BuildThread() {
|
||||
this.setUncaughtExceptionHandler(new UncaughtBridgeExceptionHandler(buildParams));
|
||||
}
|
||||
|
||||
public BuildThread(JSONObject buildParams) {
|
||||
|
@ -61,6 +69,10 @@ public class BuildThread extends Thread {
|
|||
this.buildParams = buildParams;
|
||||
}
|
||||
|
||||
public JSONObject getBuildParams() {
|
||||
return buildParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String tpiID = buildParams.getString("tpiID");
|
||||
|
@ -69,80 +81,122 @@ public class BuildThread extends Thread {
|
|||
Map<String, String> podInLabels = new HashMap<>(1);
|
||||
Map<String, String> podNotInLabels = new HashMap<>(1);
|
||||
podInLabels.put("tpiID", tpiID);
|
||||
podNotInLabels.put("type", "webssh");
|
||||
podInLabels.put("type", "evaluate,evassh");
|
||||
String type = buildParams.getInteger("podType") != 2 ? "evaluate" : "evassh";
|
||||
|
||||
String testCases = buildParams.getString("testCases");
|
||||
String out = GameHelper.getTextMsgResult("服务启动中...");
|
||||
gameService.encapsulateStepByStepResult(out, buildParams, testCases);
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
|
||||
// 传递MDC的内容
|
||||
final Map<String, String> mdc = MDC.getCopyOfContextMap();
|
||||
// git pull
|
||||
Future<Object> pull = executor.submit(Executors.callable(() -> {
|
||||
Future<Boolean> pull = executor.submit(() -> {
|
||||
try {
|
||||
MDC.setContextMap(mdc);
|
||||
Instant pullStartInstant = Instant.now();
|
||||
gameService.gitPull(tpiWorkspace, buildParams.getString("tpiGitURL"), buildParams.getInteger("contentModified"));
|
||||
gameService.gitPull(tpiWorkspace, buildParams.getString("tpiGitURL"),
|
||||
buildParams.getInteger("contentModified"));
|
||||
double pullCost = (double) Duration.between(pullStartInstant, Instant.now()).toMillis() / 1000;
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull", String.format("%.3f", pullCost));
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull",
|
||||
String.format("%.3f", pullCost));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error("下载实训" + tpiID + "代码失败", e);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// 创建pod
|
||||
final PodRef podRef = new PodRef();
|
||||
Instant podStartInstant = Instant.now();
|
||||
Future<Object> createPod = executor.submit(Executors.callable(() -> {
|
||||
String podName = k8sService.getPod(podInLabels, podNotInLabels);
|
||||
if (StringUtils.isEmpty(podName)) {
|
||||
Pod pod = k8sService.createPod(type + "-" + tpiID, tpiID, type, buildParams.getString("containers"));
|
||||
podName = pod.getMetadata().getName();
|
||||
}
|
||||
MDC.setContextMap(mdc);
|
||||
|
||||
// 设立(重设)对应pod的定时删除任务(这个时间必须大于${timeLimit},确保脚本执行期间pod不会中途死) 单位:秒
|
||||
int timeLimit = buildParams.getInteger("timeLimit");
|
||||
gameService.reTiming(podName, timeLimit + 60);
|
||||
gameService.reTiming(type + "-" + tpiID, timeLimit + 60);
|
||||
|
||||
Pod pod = k8sService.getK8sRunningPod(podInLabels, podNotInLabels);
|
||||
String podName = pod == null ? null : pod.getMetadata().getName();
|
||||
if (StringUtils.isEmpty(podName)) {
|
||||
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setTimeLimit(timeLimit);
|
||||
pod = k8sService.createPod(type + "-" + tpiID, tpiID, type, buildParams.getString("containers"),
|
||||
podCreateStrategy);
|
||||
|
||||
}
|
||||
if (pod != null) {
|
||||
podRef.setPod(pod);
|
||||
podName = pod.getMetadata().getName();
|
||||
// 设立(重设)对应pod的定时删除任务(这个时间必须大于${timeLimit},确保脚本执行期间pod不会中途死) 单位:秒
|
||||
gameService.reTiming(podName, timeLimit + 60);
|
||||
}
|
||||
}));
|
||||
boolean pullResult = false;
|
||||
try {
|
||||
pull.get();
|
||||
createPod.get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
pullResult = pull.get();
|
||||
} catch (InterruptedException e) {// 不应该发生
|
||||
logger.error("等待下载实训" + tpiID + "代码被中断", e);
|
||||
} catch (ExecutionException e) {// 不应该发生
|
||||
logger.error("等待下载实训" + tpiID + "代码出错", e);
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
try {
|
||||
createPod.get();
|
||||
} catch (InterruptedException e) {// 不应该发生
|
||||
logger.error("创建实训pod " + tpiID + "代码被中断", e);
|
||||
} catch (ExecutionException e) {
|
||||
logger.error("创建实训pod " + tpiID + "失败", e);
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray cases = JSONArray.parseArray(testCases);
|
||||
if (!pullResult) {
|
||||
String msg = GameHelper.getResult("系统繁忙,请稍后重试", cases.size(),
|
||||
BuildResultCsts.DOWNLOAD_STATUS_FAIL, BuildResultCsts.CREATE_POD_STATUS_FAIL);
|
||||
gameService.encapsulateBuildResult(msg, buildParams, testCases);
|
||||
return;
|
||||
} else {
|
||||
if (podRef.getPod() == null) {
|
||||
String msg = GameHelper.getResult("系统繁忙,请稍后重试", cases.size(),
|
||||
BuildResultCsts.DOWNLOAD_STATUS_SUCCESS, BuildResultCsts.CREATE_POD_STATUS_FAIL);
|
||||
gameService.encapsulateBuildResult(msg, buildParams, testCases);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 通过标签获取pod名
|
||||
String podName = k8sService.getPod(podInLabels, podNotInLabels);
|
||||
String podName = podRef.getPod().getMetadata().getName();
|
||||
// 按需创建端口映射svc
|
||||
if (buildParams.getInteger("needPortMapping") != 0 && !kubernetesService.svcExist(podName)) {
|
||||
k8sService.createService(podName, tpiID, buildParams.getInteger("needPortMapping"),
|
||||
Integer.parseInt(JedisUtil.hget("port", podName)));
|
||||
}
|
||||
|
||||
out = GameHelper.getTextMsgResult("服务启动完成");
|
||||
gameService.encapsulateStepByStepResult(out, buildParams, testCases);
|
||||
|
||||
// 记录创建pod耗时
|
||||
double createPodAndSvcCost = (double) Duration.between(podStartInstant, Instant.now()).toMillis() / 1000;
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod", String.format("%.3f", createPodAndSvcCost));
|
||||
JSONObject timeCost = GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod",
|
||||
String.format("%.3f", createPodAndSvcCost));
|
||||
|
||||
//bridgePodService.updateBridgePod(buildParams, timeCost, podRef.getPod());
|
||||
|
||||
// 在pod中执行评测脚本
|
||||
Instant executeStartInstant = Instant.now();
|
||||
Integer executeTimeLimit = buildParams.getInteger("executeTime") == null ? buildParams.getInteger("timeLimit") : buildParams.getInteger("executeTime");
|
||||
String out = kubernetesService.executeShellInPod(podName, buildParams.getInteger("needPortMapping"),
|
||||
Integer executeTimeLimit = buildParams.getInteger("executeTime") == null ? buildParams.getInteger("timeLimit")
|
||||
: buildParams.getInteger("executeTime");
|
||||
kubernetesService.executeShellInPod(buildParams, podRef.getPod(), buildParams.getInteger("needPortMapping"),
|
||||
executeTimeLimit, buildParams.getInteger("isPublished"), buildParams.getInteger("instanceChallenge"),
|
||||
buildParams.getString("testCases"));
|
||||
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute", String.format("%.3f", executeCost));
|
||||
|
||||
// 封装结果并回传给前台
|
||||
String status = gameService.encapsulateBuildResult(out, buildParams, buildParams.getString("testCases"));
|
||||
|
||||
// 如果成功过关,删除评测pod并执行等待任务
|
||||
if ("0".equals(status)) {
|
||||
// service不存在且pod不处于任务运行期才删除pod
|
||||
if (!kubernetesService.svcExist(podName)
|
||||
&& !kubernetesService.svcExist(podName+"-22") //22的特殊处理
|
||||
&& !JedisUtil.zhas("taskNum", podName)) {
|
||||
kubernetesService.deletePod(podName);
|
||||
}
|
||||
gameService.executeWaitingTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BuildThread{" + buildParams.toJSONString() + '}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.BeanFactory;
|
||||
import com.educoder.bridge.common.utils.GameHelper;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
|
||||
import com.educoder.bridge.game.service.GameService;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
|
@ -59,7 +59,8 @@ public class BuildThreadPersistence extends Thread {
|
|||
private final static Logger logger = LoggerFactory.getLogger(BuildThreadPersistence.class);
|
||||
|
||||
public BuildThreadPersistence() {
|
||||
this.setUncaughtExceptionHandler(new UncaughtBridgeExceptionHandler(buildParams));
|
||||
UncaughtBridgeExceptionHandler eh = BeanFactory.getObejct(UncaughtBridgeExceptionHandler.class);
|
||||
this.setUncaughtExceptionHandler(eh);
|
||||
}
|
||||
|
||||
public BuildThreadPersistence(JSONObject buildParams) {
|
||||
|
@ -85,7 +86,7 @@ public class BuildThreadPersistence extends Thread {
|
|||
Map<String, String> podNotInLabels = new HashMap<>(1);
|
||||
podNotInLabels.put("type", "webssh");
|
||||
String type = buildParams.getInteger("podType") != 2 ? "evaluate" : "evassh";
|
||||
podInLabels.put("name", type + "-" + persistenceName );
|
||||
podInLabels.put("name", type + "-" + persistenceName);
|
||||
ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
// git pull
|
||||
Future<Object> pull = executor.submit(Executors.callable(() -> {
|
||||
|
@ -95,9 +96,10 @@ public class BuildThreadPersistence extends Thread {
|
|||
buildParams.getInteger("contentModified"));
|
||||
double pullCost = (double) Duration.between(pullStartInstant, Instant.now()).toMillis() / 1000;
|
||||
logger.debug("pull耗时{}, tpiID{}", pullCost, tpiID);
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull", String.format("%.3f", pullCost));
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull",
|
||||
String.format("%.3f", pullCost));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -109,7 +111,7 @@ public class BuildThreadPersistence extends Thread {
|
|||
{
|
||||
String pod = k8sService.getPod(podInLabels, podNotInLabels);
|
||||
if (pod.equals("")) {
|
||||
Pod createPod = k8sService.createPersistencePod(type + "-" + persistenceName , tpiID, type,
|
||||
Pod createPod = k8sService.createPersistencePod(type + "-" + persistenceName, tpiID, type,
|
||||
buildParams.getString("containers"));
|
||||
// 返回容器pod名称
|
||||
return createPod.getMetadata().getName();
|
||||
|
@ -132,12 +134,13 @@ public class BuildThreadPersistence extends Thread {
|
|||
|
||||
// 记录创建pod耗时
|
||||
double createPodAndSvcCost = (double) Duration.between(podStartInstant, Instant.now()).toMillis() / 1000;
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod", String.format("%.3f", createPodAndSvcCost));
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod",
|
||||
String.format("%.3f", createPodAndSvcCost));
|
||||
|
||||
// 设立(重设)对应pod的定时删除任务(这个时间必须大于${timeLimit},确保脚本执行期间pod不会中途死) 单位:秒
|
||||
int timeLimit = buildParams.getInteger("timeLimit");
|
||||
gameService.reTiming(podName, timeLimit + 1800);
|
||||
|
||||
|
||||
logger.info("当前容器同步返回失败,tipId:{} , 总消耗时间{}", buildParams.getString("tpiID"),
|
||||
System.currentTimeMillis() - currentTimeMillis);
|
||||
// 在pod中执行评测脚本
|
||||
|
@ -147,7 +150,8 @@ public class BuildThreadPersistence extends Thread {
|
|||
buildParams.getInteger("instanceChallenge"), buildParams.getString("testCases"));
|
||||
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
|
||||
logger.debug("执行耗时{}, tpiID{}", executeCost, tpiID);
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute", String.format("%.3f", executeCost));
|
||||
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute",
|
||||
String.format("%.3f", executeCost));
|
||||
//
|
||||
// 封装结果并回传给前台
|
||||
Map<String, String> persistenceEncapsulateBuildResult = gameService.persistenceEncapsulateBuildResult(out,
|
||||
|
@ -163,7 +167,6 @@ public class BuildThreadPersistence extends Thread {
|
|||
|
||||
} catch (Exception e) {
|
||||
logger.error("评测线程抛出异常:", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package com.educoder.bridge.k8s.constant;
|
||||
|
||||
public interface BridgePodCsts {
|
||||
|
||||
String STATUS_BEGIN = "0";
|
||||
String STATUS_END = "1";
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.educoder.bridge.k8s.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.k8s.model.NodeQueryParam;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Node;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* Node相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "Node", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/nodes")
|
||||
public class NodeController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
/**
|
||||
* 获取Node列表
|
||||
*/
|
||||
@RequestMapping(path = "/list", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "获取Node列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<List<Node>> getNodes(@RequestBody(required = false) NodeQueryParam param) throws Exception {
|
||||
logger.info("获取Node列表");
|
||||
|
||||
ApiResult<List<Node>> result = new ApiResult<>();
|
||||
|
||||
|
||||
List<Node> nodeList = k8sService.getNodes(param);
|
||||
|
||||
result.setData(nodeList);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取Node列表
|
||||
*/
|
||||
@RequestMapping(path = "/{name}", method = RequestMethod.GET)
|
||||
@ApiOperation(value = "获取Node详情", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<Node> getNode(@PathVariable("name") String name) throws Exception {
|
||||
logger.info("获取Node {}详情", name);
|
||||
|
||||
ApiResult<Node> result = new ApiResult<>();
|
||||
|
||||
NodeQueryParam param = new NodeQueryParam();
|
||||
param.setName(name);
|
||||
List<Node> nodeList = k8sService.getNodes(param);
|
||||
if(nodeList != null && nodeList.size() > 0) {
|
||||
result.setData(nodeList.get(0));
|
||||
} else {
|
||||
result.setCode(ApiResultCodeCsts.FAIL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.educoder.bridge.k8s.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
import com.educoder.bridge.common.model.BridgePage;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.k8s.model.BridgePod;
|
||||
import com.educoder.bridge.k8s.model.PodQueryParam;
|
||||
import com.educoder.bridge.k8s.service.BridgePodService;
|
||||
import com.github.pagehelper.Page;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* Pod相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "Pod", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/pods")
|
||||
public class PodController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
@Autowired
|
||||
private BridgePodService bridgePodService;
|
||||
|
||||
/**
|
||||
* 获取Node列表
|
||||
*/
|
||||
@RequestMapping(path = "/list", method = RequestMethod.POST)
|
||||
@ApiOperation(value = "获取Pod列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<BridgePage<BridgePod>> getPods(@RequestBody(required = false) PodQueryParam param)
|
||||
throws Exception {
|
||||
logger.info("获取Pod列表");
|
||||
|
||||
ApiResult<BridgePage<BridgePod>> result = new ApiResult<>();
|
||||
List<BridgePod> list = bridgePodService.getBridgePods(param);
|
||||
BridgePage<BridgePod> page = new BridgePage<>((Page<BridgePod>) list);
|
||||
result.setData(page);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Pod详情
|
||||
*/
|
||||
@RequestMapping(path = "/{name}", method = RequestMethod.GET)
|
||||
@ApiOperation(value = "获取Pod详情", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<Pod> getPod(@PathVariable("name") String name) throws Exception {
|
||||
logger.info("获取Pod {} 详情", name);
|
||||
|
||||
ApiResult<Pod> result = new ApiResult<>();
|
||||
|
||||
Pod pod = k8sService.getPod(name);
|
||||
if (pod != null) {
|
||||
result.setData(pod);
|
||||
} else {
|
||||
result.setCode(ApiResultCodeCsts.FAIL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.educoder.bridge.k8s.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.educoder.bridge.k8s.model.BridgePod;
|
||||
import com.educoder.bridge.k8s.model.PodQueryParam;
|
||||
|
||||
public interface BridgePodMapper {
|
||||
int deleteByPrimaryKey(Long id);
|
||||
|
||||
int insert(BridgePod record);
|
||||
|
||||
int insertSelective(BridgePod record);
|
||||
|
||||
BridgePod selectByPrimaryKey(Long id);
|
||||
|
||||
int updateByPrimaryKeySelective(BridgePod record);
|
||||
|
||||
int updateByPrimaryKey(BridgePod record);
|
||||
|
||||
List<BridgePod> selectBridgePod(PodQueryParam param);
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
package com.educoder.bridge.k8s.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "bridge pod 信息", description = "bridge pod 信息")
|
||||
public class BridgePod {
|
||||
@ApiModelProperty(value = "id")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "pod name")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "实训id")
|
||||
private String tpiID;
|
||||
|
||||
@ApiModelProperty(value = "k8s pod创建时间")
|
||||
private LocalDateTime k8sCreateTime;
|
||||
@ApiModelProperty(value = "删除时间")
|
||||
private LocalDateTime deleteTime;
|
||||
|
||||
@ApiModelProperty(value = "测评标识")
|
||||
private String secKey;
|
||||
@ApiModelProperty(value = "评测请求到达时间")
|
||||
private LocalDateTime requestTime;
|
||||
@ApiModelProperty(value = "下载代码耗时")
|
||||
private Double pull;
|
||||
@ApiModelProperty(value = "创建pod耗时")
|
||||
private Double createPod;
|
||||
@ApiModelProperty(value = "执行评测脚本耗时")
|
||||
private Double execute;
|
||||
@ApiModelProperty(value = "评测总耗时")
|
||||
private Double evaluateAllTime;
|
||||
|
||||
@ApiModelProperty(value = "pod所在node名称")
|
||||
private String nodeName;
|
||||
@ApiModelProperty(value = "pod所在node ip")
|
||||
private String nodeIp;
|
||||
|
||||
@ApiModelProperty(value = "下载代码结果:0,失败; 1,成功.")
|
||||
private String downloadStatus;
|
||||
@ApiModelProperty(value = "创建pod结果:0,失败; 1,成功.")
|
||||
private String createPodStatus;
|
||||
@ApiModelProperty(value = "编译结果:0,失败; 1,成功.")
|
||||
private String compileStatus;
|
||||
@ApiModelProperty(value = "运行结果:-1,失败; 0,成功.")
|
||||
private String runStatus;
|
||||
@ApiModelProperty(value = "评测状态:0,开始; 1,评测结束.")
|
||||
private String status;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTpiID() {
|
||||
return tpiID;
|
||||
}
|
||||
|
||||
public void setTpiID(String tpiID) {
|
||||
this.tpiID = tpiID;
|
||||
}
|
||||
|
||||
public LocalDateTime getK8sCreateTime() {
|
||||
return k8sCreateTime;
|
||||
}
|
||||
|
||||
public void setK8sCreateTime(LocalDateTime k8sCreateTime) {
|
||||
this.k8sCreateTime = k8sCreateTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getDeleteTime() {
|
||||
return deleteTime;
|
||||
}
|
||||
|
||||
public void setDeleteTime(LocalDateTime deleteTime) {
|
||||
this.deleteTime = deleteTime;
|
||||
}
|
||||
|
||||
public String getSecKey() {
|
||||
return secKey;
|
||||
}
|
||||
|
||||
public void setSecKey(String secKey) {
|
||||
this.secKey = secKey;
|
||||
}
|
||||
|
||||
public LocalDateTime getRequestTime() {
|
||||
return requestTime;
|
||||
}
|
||||
|
||||
public void setRequestTime(LocalDateTime requestTime) {
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public Double getPull() {
|
||||
return pull;
|
||||
}
|
||||
|
||||
public void setPull(Double pull) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
public Double getCreatePod() {
|
||||
return createPod;
|
||||
}
|
||||
|
||||
public void setCreatePod(Double createPod) {
|
||||
this.createPod = createPod;
|
||||
}
|
||||
|
||||
public Double getExecute() {
|
||||
return execute;
|
||||
}
|
||||
|
||||
public void setExecute(Double execute) {
|
||||
this.execute = execute;
|
||||
}
|
||||
|
||||
public Double getEvaluateAllTime() {
|
||||
return evaluateAllTime;
|
||||
}
|
||||
|
||||
public void setEvaluateAllTime(Double evaluateAllTime) {
|
||||
this.evaluateAllTime = evaluateAllTime;
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
public void setNodeName(String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
public String getNodeIp() {
|
||||
return nodeIp;
|
||||
}
|
||||
|
||||
public void setNodeIp(String nodeIp) {
|
||||
this.nodeIp = nodeIp;
|
||||
}
|
||||
|
||||
public String getDownloadStatus() {
|
||||
return downloadStatus;
|
||||
}
|
||||
|
||||
public void setDownloadStatus(String downloadStatus) {
|
||||
this.downloadStatus = downloadStatus;
|
||||
}
|
||||
|
||||
public String getCreatePodStatus() {
|
||||
return createPodStatus;
|
||||
}
|
||||
|
||||
public void setCreatePodStatus(String createPodStatus) {
|
||||
this.createPodStatus = createPodStatus;
|
||||
}
|
||||
|
||||
public String getCompileStatus() {
|
||||
return compileStatus;
|
||||
}
|
||||
|
||||
public void setCompileStatus(String compileStatus) {
|
||||
this.compileStatus = compileStatus;
|
||||
}
|
||||
|
||||
public String getRunStatus() {
|
||||
return runStatus;
|
||||
}
|
||||
|
||||
public void setRunStatus(String runStatus) {
|
||||
this.runStatus = runStatus;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.educoder.bridge.k8s.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NodeQueryParam {
|
||||
|
||||
private String name;
|
||||
private Map<String, String> labels;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Map<String, String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabels(Map<String, String> labels) {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
package com.educoder.bridge.k8s.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "pod查询参数", description = "pod查询参数")
|
||||
public class PodQueryParam {
|
||||
@ApiModelProperty(value = "id")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "pod name")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "实训id")
|
||||
private String tpiID;
|
||||
|
||||
@ApiModelProperty(value = "请求时间")
|
||||
private LocalDateTime requestTime;
|
||||
@ApiModelProperty(value = "最小请求时间")
|
||||
private LocalDateTime minRequestTime;
|
||||
@ApiModelProperty(value = "最大请求时间")
|
||||
private LocalDateTime maxRequestTime;
|
||||
@ApiModelProperty(value = "测评标识")
|
||||
private String secKey;
|
||||
|
||||
@ApiModelProperty(value = "pod所在node名称")
|
||||
private String nodeName;
|
||||
@ApiModelProperty(value = "pod所在node ip")
|
||||
private String nodeIp;
|
||||
|
||||
@ApiModelProperty(value = "下载代码结果:0,失败; 1,成功.")
|
||||
private String downloadStatus;
|
||||
@ApiModelProperty(value = "创建pod结果:0,失败; 1,成功.")
|
||||
private String createPodStatus;
|
||||
@ApiModelProperty(value = "编译结果:0,失败; 1,成功.")
|
||||
private String compileStatus;
|
||||
@ApiModelProperty(value = "运行结果:-1,失败; 0,成功.")
|
||||
private String runStatus;
|
||||
@ApiModelProperty(value = "评测状态:0,开始; 1,评测结束.")
|
||||
private String status;
|
||||
|
||||
@ApiModelProperty(value = "排序字段。默认按id降序")
|
||||
private String sortField;
|
||||
@ApiModelProperty(value = "排序字段方向:asc或者desc。默认desc")
|
||||
private String sortDirection;
|
||||
|
||||
@ApiModelProperty(value = "第几页,从1开始")
|
||||
private Integer pageNum = 1;
|
||||
@ApiModelProperty(value = "每页数量")
|
||||
private Integer pageSize = 10;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getTpiID() {
|
||||
return tpiID;
|
||||
}
|
||||
|
||||
public void setTpiID(String tpiID) {
|
||||
this.tpiID = tpiID;
|
||||
}
|
||||
|
||||
public LocalDateTime getRequestTime() {
|
||||
return requestTime;
|
||||
}
|
||||
|
||||
public void setRequestTime(LocalDateTime requestTime) {
|
||||
this.requestTime = requestTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getMinRequestTime() {
|
||||
return minRequestTime;
|
||||
}
|
||||
|
||||
public void setMinRequestTime(LocalDateTime minRequestTime) {
|
||||
this.minRequestTime = minRequestTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getMaxRequestTime() {
|
||||
return maxRequestTime;
|
||||
}
|
||||
|
||||
public void setMaxRequestTime(LocalDateTime maxRequestTime) {
|
||||
this.maxRequestTime = maxRequestTime;
|
||||
}
|
||||
|
||||
public String getSecKey() {
|
||||
return secKey;
|
||||
}
|
||||
|
||||
public void setSecKey(String secKey) {
|
||||
this.secKey = secKey;
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
public void setNodeName(String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
public String getNodeIp() {
|
||||
return nodeIp;
|
||||
}
|
||||
|
||||
public void setNodeIp(String nodeIp) {
|
||||
this.nodeIp = nodeIp;
|
||||
}
|
||||
|
||||
public String getDownloadStatus() {
|
||||
return downloadStatus;
|
||||
}
|
||||
|
||||
public void setDownloadStatus(String downloadStatus) {
|
||||
this.downloadStatus = downloadStatus;
|
||||
}
|
||||
|
||||
public String getCreatePodStatus() {
|
||||
return createPodStatus;
|
||||
}
|
||||
|
||||
public void setCreatePodStatus(String createPodStatus) {
|
||||
this.createPodStatus = createPodStatus;
|
||||
}
|
||||
|
||||
public String getCompileStatus() {
|
||||
return compileStatus;
|
||||
}
|
||||
|
||||
public void setCompileStatus(String compileStatus) {
|
||||
this.compileStatus = compileStatus;
|
||||
}
|
||||
|
||||
public String getRunStatus() {
|
||||
return runStatus;
|
||||
}
|
||||
|
||||
public void setRunStatus(String runStatus) {
|
||||
this.runStatus = runStatus;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getSortField() {
|
||||
return sortField;
|
||||
}
|
||||
|
||||
public void setSortField(String sortField) {
|
||||
this.sortField = sortField;
|
||||
}
|
||||
|
||||
public String getSortDirection() {
|
||||
return sortDirection;
|
||||
}
|
||||
|
||||
public void setSortDirection(String sortDirection) {
|
||||
this.sortDirection = sortDirection;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package com.educoder.bridge.k8s.service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.TimeHelper;
|
||||
import com.educoder.bridge.game.model.BuildResult;
|
||||
import com.educoder.bridge.k8s.constant.BridgePodCsts;
|
||||
import com.educoder.bridge.k8s.dao.BridgePodMapper;
|
||||
import com.educoder.bridge.k8s.model.BridgePod;
|
||||
import com.educoder.bridge.k8s.model.PodQueryParam;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
@Service
|
||||
public class BridgePodService {
|
||||
|
||||
@Autowired
|
||||
private BridgePodMapper bridgePodMapper;
|
||||
|
||||
public List<BridgePod> getBridgePods(PodQueryParam param) {
|
||||
|
||||
PageHelper.startPage(param.getPageNum(), param.getPageSize());
|
||||
return bridgePodMapper.selectBridgePod(param);
|
||||
}
|
||||
|
||||
public void createBridgePod(BridgePod bridgePod) {
|
||||
bridgePodMapper.insert(bridgePod);
|
||||
}
|
||||
|
||||
public BridgePod createBridgePod(String name, String tpiID, LocalDateTime requestTime, String secKey) {
|
||||
BridgePod bridgePod = new BridgePod();
|
||||
bridgePod.setName(name);
|
||||
bridgePod.setTpiID(tpiID);
|
||||
bridgePod.setSecKey(secKey);
|
||||
bridgePod.setRequestTime(requestTime);
|
||||
bridgePod.setStatus(BridgePodCsts.STATUS_BEGIN);
|
||||
|
||||
bridgePodMapper.insert(bridgePod);
|
||||
return bridgePod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新下载代码时间,创建pod时间,pod信息
|
||||
*
|
||||
* @param buildParams
|
||||
* @param timeCost
|
||||
* @param pod
|
||||
*/
|
||||
public void updateBridgePod(JSONObject buildParams, JSONObject timeCost, Pod pod) {
|
||||
BridgePod bridgePod = new BridgePod();
|
||||
bridgePod.setId(buildParams.getLong("bridgePodId"));
|
||||
|
||||
String pull = timeCost.getString("pull");
|
||||
Double takeTime = pull == null ? null : Double.parseDouble(pull);
|
||||
bridgePod.setPull(takeTime);
|
||||
|
||||
String createPod = timeCost.getString("createPod");
|
||||
takeTime = createPod == null ? null : Double.parseDouble(createPod);
|
||||
bridgePod.setCreatePod(takeTime);
|
||||
|
||||
String createTime = pod.getMetadata().getCreationTimestamp();
|
||||
if (createTime.endsWith("Z")) {
|
||||
createTime = createTime.substring(0, createTime.length() - 1);
|
||||
}
|
||||
LocalDateTime time = LocalDateTime.parse(createTime);
|
||||
bridgePod.setK8sCreateTime(time);
|
||||
|
||||
bridgePod.setNodeName(pod.getSpec().getNodeName());
|
||||
bridgePod.setNodeIp(pod.getStatus().getHostIP());
|
||||
|
||||
bridgePodMapper.updateByPrimaryKeySelective(bridgePod);
|
||||
}
|
||||
|
||||
public void updateExecuteTime(JSONObject buildParams, JSONObject timeCost, Pod pod, BuildResult result) {
|
||||
BridgePod bridgePod = new BridgePod();
|
||||
bridgePod.setId(buildParams.getLong("bridgePodId"));
|
||||
|
||||
// 下载代码和创建pod
|
||||
String pull = timeCost.getString("pull");
|
||||
Double takeTime = pull == null ? null : Double.parseDouble(pull);
|
||||
bridgePod.setPull(takeTime);
|
||||
|
||||
String createPod = timeCost.getString("createPod");
|
||||
takeTime = createPod == null ? null : Double.parseDouble(createPod);
|
||||
bridgePod.setCreatePod(takeTime);
|
||||
|
||||
String createTime = pod.getMetadata().getCreationTimestamp();
|
||||
if (createTime.endsWith("Z")) {
|
||||
createTime = createTime.substring(0, createTime.length() - 1);
|
||||
}
|
||||
LocalDateTime time = LocalDateTime.parse(createTime);
|
||||
bridgePod.setK8sCreateTime(time);
|
||||
|
||||
bridgePod.setNodeName(pod.getSpec().getNodeName());
|
||||
bridgePod.setNodeIp(pod.getStatus().getHostIP());
|
||||
|
||||
// 评测数据
|
||||
String execute = timeCost.getString("execute");
|
||||
takeTime = execute == null ? null : Double.parseDouble(execute);
|
||||
bridgePod.setExecute(takeTime);
|
||||
|
||||
takeTime = (double) (System.currentTimeMillis()
|
||||
- TimeHelper.convertTimeToMillis(timeCost.getString("evaluateStartTime"))) / 1000;
|
||||
bridgePod.setEvaluateAllTime(takeTime);
|
||||
|
||||
bridgePod.setDownloadStatus(result.getDownloadStatus());
|
||||
bridgePod.setCreatePodStatus(result.getCreatePodStatus());
|
||||
bridgePod.setCompileStatus(result.getCompileSuccess());
|
||||
bridgePod.setRunStatus(result.getStatus());
|
||||
bridgePod.setStatus(BridgePodCsts.STATUS_END);
|
||||
|
||||
bridgePodMapper.updateByPrimaryKeySelective(bridgePod);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package com.educoder.bridge.log.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
import com.educoder.bridge.log.model.LogLevel;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/logs")
|
||||
public class LogController {
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 修改项目日志输出级别
|
||||
*
|
||||
* @param allLevel
|
||||
* 全局日志级别
|
||||
* @param singleLevel
|
||||
* 某个类日志级别
|
||||
* @param singlePath
|
||||
* 需要单独设置日志输出级别的类的全限定名(例:log.SecondController)
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
@RequestMapping(value = "levels/set", method = RequestMethod.PUT)
|
||||
public String changeLevel(@RequestParam(required = false) String allLevel,
|
||||
@RequestParam(required = false) String singleLevel, @RequestParam(required = false) String singlePath) {
|
||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
if (!StringUtils.isEmpty(allLevel)) {
|
||||
// 设置全局日志级别
|
||||
ch.qos.logback.classic.Logger logger = loggerContext.getLogger("root");
|
||||
logger.setLevel(Level.toLevel(allLevel));
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(singleLevel)) {
|
||||
// 设置某个类日志级别-可以实现定向日志级别调整
|
||||
ch.qos.logback.classic.Logger vLogger = loggerContext.getLogger(singlePath);
|
||||
if (vLogger != null) {
|
||||
vLogger.setLevel(Level.toLevel(singleLevel));
|
||||
}
|
||||
}
|
||||
|
||||
testLogLevel();
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("code", 0);
|
||||
response.put("msg", "修改log level级别成功");
|
||||
return "success";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "levels/{name}", method = RequestMethod.PUT)
|
||||
@ApiOperation(value = "设置日志级别", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<LogLevel> setLevel(@PathVariable("name") String name, @RequestParam("level") String level) {
|
||||
ApiResult<LogLevel> result = new ApiResult<>();
|
||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
|
||||
ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
|
||||
logger.setLevel(Level.toLevel(level));
|
||||
|
||||
testLogLevel();
|
||||
|
||||
result.setMsg("设置日志级别成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(path = "levels/{name}", method = RequestMethod.GET)
|
||||
@ApiOperation(value = "获取 日志级别", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<LogLevel> getRootLevel(@PathVariable("name") String name) {
|
||||
ApiResult<LogLevel> result = new ApiResult<>();
|
||||
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
|
||||
Level level = logger.getLevel();
|
||||
LogLevel logLevel = new LogLevel();
|
||||
logLevel.setLevel(level.toString());
|
||||
result.setData(logLevel);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 此方法用于测试
|
||||
*/
|
||||
private void testLogLevel() {
|
||||
logger.trace("test log level");
|
||||
logger.debug("test log level");
|
||||
logger.info("test log level");
|
||||
logger.warn("test log level");
|
||||
logger.error("test log level");
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.educoder.bridge.log.model;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "日志级别", description = "日志级别")
|
||||
public class LogLevel {
|
||||
|
||||
@ApiModelProperty(value = "root或者具体类名")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "日志级别")
|
||||
private String level;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.educoder.bridge.user.controller;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
import com.educoder.bridge.user.model.LoginInfo;
|
||||
import com.educoder.bridge.user.model.User;
|
||||
import com.educoder.bridge.user.service.UserService;
|
||||
import com.educoder.bridge.user.util.JwtUtils;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* 登录相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "用户登录", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class LoginController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
@RequestMapping(path = "/login")
|
||||
@ApiOperation(value = "登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<String> login(@RequestBody LoginInfo loginInfo) throws Exception {
|
||||
logger.info("用户{}登录", loginInfo.getLoginName());
|
||||
|
||||
ApiResult<String> result = new ApiResult<>();
|
||||
|
||||
User user = userService.login(loginInfo);
|
||||
|
||||
long expireTime = System.currentTimeMillis() + 1000L * 60 * 30;
|
||||
Date expireDatePoint = new Date(expireTime);
|
||||
String token = JwtUtils.genToken(user, expireDatePoint);
|
||||
result.setData(token);
|
||||
result.setMsg("登录成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出
|
||||
*/
|
||||
@RequestMapping(path = "/logout")
|
||||
@ApiOperation(value = "退出", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<?> logout(HttpServletRequest request) throws Exception {
|
||||
HttpSession session = request.getSession(true);
|
||||
User user = (User) session.getAttribute("user");
|
||||
String name = user == null ? "" : user.getName();
|
||||
logger.info("用户{}退出", name);
|
||||
|
||||
session.removeAttribute("user");
|
||||
|
||||
ApiResult<?> result = new ApiResult<>();
|
||||
result.setMsg("退出成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.educoder.bridge.user.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.educoder.bridge.common.model.ApiResult;
|
||||
import com.educoder.bridge.user.model.PasswordUpdateInfo;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* 用户相关的接口
|
||||
*
|
||||
* @author jiangzhongxiang
|
||||
*/
|
||||
@Api(value = "用户", hidden = true)
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
@RequestMapping(path = "/passwords/update")
|
||||
@ApiOperation(value = "修改密码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public ApiResult<?> updatePassword(@RequestBody PasswordUpdateInfo pui) throws Exception {
|
||||
logger.info("用户{}修改密码", "xxx");
|
||||
|
||||
ApiResult<?> result = new ApiResult<>();
|
||||
|
||||
result.setMsg("修改成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.educoder.bridge.user.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.educoder.bridge.user.model.User;
|
||||
|
||||
public interface UserMapper {
|
||||
int deleteByPrimaryKey(Long id);
|
||||
|
||||
int insert(User record);
|
||||
|
||||
int insertSelective(User record);
|
||||
|
||||
User selectByPrimaryKey(Long id);
|
||||
|
||||
int updateByPrimaryKeySelective(User record);
|
||||
|
||||
int updateByPrimaryKey(User record);
|
||||
|
||||
List<User> selectUser(Map<String,Object> param);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.educoder.bridge.user.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.user.util.JwtUtils;
|
||||
|
||||
public class AuthorizationInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
|
||||
|
||||
String token = req.getHeader("ACCESS_TOKEN");
|
||||
if (StringUtils.isBlank(token)) {
|
||||
// res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
throw new GameException(-2, "未授权"); // 改成直接返回,不要抛异常
|
||||
}
|
||||
try {
|
||||
JwtUtils.verifyToken(token);
|
||||
} catch (Exception e) {
|
||||
// res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
throw new GameException(-2, "未授权"); // 改成直接返回,不要抛异常
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
|
||||
ModelAndView modelAndView) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
|
||||
Object o, Exception e) throws Exception {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.educoder.bridge.user.model;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "登录信息", description = "登录信息")
|
||||
public class LoginInfo {
|
||||
|
||||
@ApiModelProperty(value = "登录名")
|
||||
private String loginName;
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
public String getLoginName() {
|
||||
return loginName;
|
||||
}
|
||||
|
||||
public void setLoginName(String loginName) {
|
||||
this.loginName = loginName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.educoder.bridge.user.model;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(value = "密码修改信息", description = "密码修改信息")
|
||||
public class PasswordUpdateInfo {
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "新密码")
|
||||
private String newPassword;
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return newPassword;
|
||||
}
|
||||
|
||||
public void setNewPassword(String newPassword) {
|
||||
this.newPassword = newPassword;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.educoder.bridge.user.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class User {
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String password;
|
||||
|
||||
private String email;
|
||||
|
||||
private String mobile;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
private String status;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.educoder.bridge.user.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.shiro.codec.Base64;
|
||||
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
|
||||
import org.apache.shiro.crypto.hash.DefaultHashService;
|
||||
import org.apache.shiro.crypto.hash.Hash;
|
||||
import org.apache.shiro.crypto.hash.HashRequest;
|
||||
import org.apache.shiro.util.ByteSource;
|
||||
import org.apache.shiro.util.SimpleByteSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.educoder.bridge.game.exception.GameException;
|
||||
import com.educoder.bridge.user.dao.UserMapper;
|
||||
import com.educoder.bridge.user.model.LoginInfo;
|
||||
import com.educoder.bridge.user.model.User;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
public User login(LoginInfo loginInfo) throws GameException {
|
||||
// 查询用户
|
||||
String name = loginInfo.getLoginName();
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("name", name);
|
||||
List<User> list = userMapper.selectUser(param);
|
||||
User user = list.size() > 0 ? list.get(0) : null;
|
||||
if (user == null) {
|
||||
logger.error("不存在的用户{}请求登录 ", name);
|
||||
throw new GameException(-2, "用户名或者密码错误:" + name);
|
||||
}
|
||||
|
||||
// 用户密码
|
||||
String password = user.getPassword();
|
||||
int index = password.indexOf("$");
|
||||
String salt = password.substring(0, index);
|
||||
String realPassword = user.getPassword().substring(index + 1);
|
||||
|
||||
DefaultHashService hashService = new DefaultHashService();
|
||||
hashService.setHashAlgorithmName("MD5");
|
||||
hashService.setPrivateSalt(new SimpleByteSource("bridge_admin"));
|
||||
hashService.setRandomNumberGenerator(new SecureRandomNumberGenerator());// 用于生成公盐。默认就这个
|
||||
hashService.setHashIterations(1000); // 生成Hash值的迭代次数
|
||||
HashRequest request = new HashRequest.Builder().setSource(ByteSource.Util.bytes(loginInfo.getPassword()))
|
||||
.setSalt(ByteSource.Util.bytes(Base64.decode(salt))).build();
|
||||
Hash hash = hashService.computeHash(request);
|
||||
|
||||
boolean r = hash.toHex().equals(realPassword);
|
||||
if (!r) {
|
||||
logger.error("用户{}密码错误 ", name);
|
||||
throw new GameException(-2, "用户名或者密码错误:" + name);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.educoder.bridge.user.util;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTCreator;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.Claim;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.educoder.bridge.user.model.User;
|
||||
|
||||
public class JwtUtils {
|
||||
|
||||
private static final String SECRET = "61bfbcf03829f424726e357fd0bb4095";
|
||||
|
||||
private static String ISSUER = "educoder_bridge";
|
||||
|
||||
/**
|
||||
* 生成token
|
||||
*
|
||||
* @param claims
|
||||
* @param expireDatePoint
|
||||
* 过期时间点
|
||||
* @return
|
||||
*/
|
||||
public static String genToken(User user, Date expireDatePoint) {
|
||||
|
||||
try {
|
||||
// 使用HMAC256进行加密
|
||||
Algorithm algorithm = Algorithm.HMAC256(SECRET);
|
||||
|
||||
// 创建jwt
|
||||
JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER). // 发行人
|
||||
withExpiresAt(expireDatePoint); // 过期时间点
|
||||
|
||||
// 传入参数
|
||||
builder.withClaim("name", user.getName());
|
||||
|
||||
// 签名加密
|
||||
return builder.sign(algorithm);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("创建token失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密jwt
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static Map<String, String> verifyToken(String token) throws RuntimeException {
|
||||
Algorithm algorithm = null;
|
||||
try {
|
||||
// 使用HMAC256进行加密
|
||||
algorithm = Algorithm.HMAC256(SECRET);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// 解密
|
||||
JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
|
||||
DecodedJWT jwt = verifier.verify(token);
|
||||
Map<String, Claim> map = jwt.getClaims();
|
||||
Map<String, String> resultMap = new HashMap<>();
|
||||
map.forEach((k, v) -> resultMap.put(k, v.asString()));
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,9 @@
|
|||
package com.educoder.bridge.webssh.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.controller.BaseController;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.webssh.model.Webssh;
|
||||
import com.educoder.bridge.webssh.service.WebsshService;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -19,20 +11,30 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.settings.AppConfig;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.webssh.model.Webssh;
|
||||
import com.educoder.bridge.webssh.service.WebsshService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
|
||||
/**
|
||||
* @author guange
|
||||
* @date 2017/08/02
|
||||
*/
|
||||
@Api(value = "提供webssh连接", hidden = true)
|
||||
@RestController
|
||||
public class WebsshController extends BaseController {
|
||||
@Autowired
|
||||
private WebsshService websshService;
|
||||
public class WebsshController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebsshController.class);
|
||||
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
|
||||
private WebsshService websshService;
|
||||
|
||||
@Autowired
|
||||
private AppConfig appConfig;
|
||||
|
||||
@ApiOperation(value = "获取连接容器所需的ip和端口信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@RequestMapping(path = "/webssh/getConnectInfo")
|
||||
|
@ -49,17 +51,15 @@ public class WebsshController extends BaseController {
|
|||
JSONObject response = new JSONObject();
|
||||
response.put("address", sshInfo.getAddress());
|
||||
response.put("port", Integer.parseInt(sshInfo.getPort()) + "");
|
||||
response.put("ws_address", appConfig.getServerUrl()); //websocket连接地址
|
||||
response.put("ws_address", appConfig.getServerUrl()); // websocket连接地址
|
||||
response.put("code", 0);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "删除tpiID对应的webssh类型的pod", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@RequestMapping(path = "/webssh/delete")
|
||||
public JSONObject delete(
|
||||
@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
|
||||
public JSONObject delete(@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
|
||||
@ApiParam(name = "digestKey", required = true, value = "签名") @RequestParam String digestKey,
|
||||
@ApiParam(name = "identifier", required = true, value = "game的标示") @RequestParam String identifier)
|
||||
throws Exception {
|
||||
|
@ -67,40 +67,33 @@ public class WebsshController extends BaseController {
|
|||
JSONObject response = new JSONObject();
|
||||
|
||||
// 用identifier与私钥拼接与digestKey比较,相等响应,不想等拒绝
|
||||
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
|
||||
if (digestKey.equals(serverDigestKey)) {
|
||||
try {
|
||||
websshService.deleteNow(tpiID);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "成功发起删除命令");
|
||||
} catch (Exception e) {
|
||||
logger.error("主动删除pod失败,{}", e.getMessage());
|
||||
response.put("code", -1);
|
||||
response.put("msg", "删除pod失败");
|
||||
}
|
||||
} else {
|
||||
response.put("code", -1);
|
||||
response.put("msg", "认证不通过,服务端拒绝连接");
|
||||
}
|
||||
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
|
||||
if (digestKey.equals(serverDigestKey)) {
|
||||
try {
|
||||
websshService.deleteNow(tpiID);
|
||||
response.put("code", 0);
|
||||
response.put("msg", "成功发起删除命令");
|
||||
} catch (Exception e) {
|
||||
logger.error("主动删除pod失败", e);
|
||||
response.put("code", -1);
|
||||
response.put("msg", "删除pod失败");
|
||||
}
|
||||
} else {
|
||||
response.put("code", -1);
|
||||
response.put("msg", "认证不通过,服务端拒绝连接");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/", "ssh" }, method = RequestMethod.GET)
|
||||
public ModelAndView index(@RequestParam("Host") String host, @RequestParam("Port") int port,
|
||||
@RequestParam("Gameid") int gameId, @RequestParam("Username") String username,
|
||||
@RequestParam("Password") String password, @RequestParam("Tab") String tab, @RequestParam("Rows") int rows,
|
||||
@RequestParam("Columns") int columns, @RequestParam("Width") int width, @RequestParam("Height") int height
|
||||
|
||||
@RequestMapping(value={"/", "ssh"}, method= RequestMethod.GET)
|
||||
public ModelAndView index(@RequestParam("Host")String host,
|
||||
@RequestParam("Port")int port,
|
||||
@RequestParam("Gameid")int gameId,
|
||||
@RequestParam("Username")String username,
|
||||
@RequestParam("Password")String password,
|
||||
@RequestParam("Tab")String tab,
|
||||
@RequestParam("Rows")int rows,
|
||||
@RequestParam("Columns")int columns,
|
||||
@RequestParam("Width")int width,
|
||||
@RequestParam("Height")int height
|
||||
|
||||
) {
|
||||
//index就是视图的名称(index.ftl)
|
||||
) {
|
||||
// index就是视图的名称(index.ftl)
|
||||
logger.debug("/ssh: 接收到前端连接请求,host: {}, port: {}, {}", host, port, appConfig.getServerUrl());
|
||||
ModelAndView mv = new ModelAndView();
|
||||
mv.setViewName("index");
|
||||
|
|
|
@ -1,21 +1,5 @@
|
|||
package com.educoder.bridge.webssh.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.webssh.model.ConnectInfo;
|
||||
import com.educoder.bridge.webssh.model.WebscoketObj;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -26,278 +10,294 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.Base64Util;
|
||||
import com.educoder.bridge.webssh.model.ConnectInfo;
|
||||
import com.educoder.bridge.webssh.model.WebscoketObj;
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.UserInfo;
|
||||
|
||||
@Service
|
||||
public class JchService {
|
||||
@Autowired
|
||||
private WebsshService websshService;
|
||||
@Autowired
|
||||
private WebsshService websshService;
|
||||
|
||||
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {
|
||||
com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int arg0) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isEnabled(int arg0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(int arg0, String arg1) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void log(int arg0, String arg1) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
|
||||
@Value("${trustiePodUrl}")
|
||||
String trustiePodUrl;
|
||||
/**
|
||||
* 在webssh连接时,初始化一个ssh连接
|
||||
*
|
||||
* @param wsSession
|
||||
*/
|
||||
public void add(WebSocketSession wsSession) {
|
||||
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
WebscoketObj webscoketObj = new WebscoketObj();
|
||||
webscoketObj.setSession(wsSession);
|
||||
|
||||
/**
|
||||
* 在webssh连接时,初始化一个ssh连接
|
||||
*
|
||||
* @param wsSession
|
||||
*/
|
||||
public void add(WebSocketSession wsSession) {
|
||||
sessionQueue.add(webscoketObj);
|
||||
}
|
||||
|
||||
WebscoketObj webscoketObj = new WebscoketObj();
|
||||
webscoketObj.setSession(wsSession);
|
||||
/**
|
||||
* 处理客户端发过来的数据
|
||||
*
|
||||
* @param buffer
|
||||
*/
|
||||
public void recv(String buffer, WebSocketSession session) {
|
||||
logger.debug("webssh收到数据:" + buffer);
|
||||
WebscoketObj webscoketObj = null;
|
||||
try {
|
||||
// logger.debug("recv函数,进程:{},sessionID:{},信息:{}",
|
||||
// Thread.currentThread().getId(), session.getId(), buffer);
|
||||
JSONObject object = JSONObject.parseObject(buffer);
|
||||
String tp = object.getString("tp");
|
||||
if ("init".equals(tp)) {
|
||||
// 初始化连接
|
||||
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","gameid":"1080","rows":"30"}}
|
||||
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null) {
|
||||
WebscoketObj finalWebscoketObj = webscoketObj;
|
||||
executorService.execute(() -> {
|
||||
logger.debug("connectToSSH 内线程;id:{},session:{},websocketObj:{}",
|
||||
Thread.currentThread().getId(), session.getId(),
|
||||
finalWebscoketObj.getSession().getId());
|
||||
connectTossh(finalWebscoketObj, connectInfo, session);
|
||||
|
||||
sessionQueue.add(webscoketObj);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if ("client".equals(tp)) {
|
||||
String data = object.getString("data");
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null) {
|
||||
transTossh(webscoketObj.getOutputStream(), data);
|
||||
}
|
||||
} else if ("h".equals(tp)) {
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null && webscoketObj.getChannel() != null) {
|
||||
webscoketObj.getChannel().getSession().sendKeepAliveMsg();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("转发命令到ssh出错: {}", e);
|
||||
// closeBySsh(webscoketObj);
|
||||
if (webscoketObj != null) {
|
||||
closeByWebsocket(webscoketObj.getSession());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理客户端发过来的数据
|
||||
* @param buffer
|
||||
*/
|
||||
public void recv(String buffer, WebSocketSession session) {
|
||||
logger.debug("webssh收到数据:" + buffer);
|
||||
WebscoketObj webscoketObj = null;
|
||||
try {
|
||||
// logger.debug("recv函数,进程:{},sessionID:{},信息:{}", Thread.currentThread().getId(), session.getId(), buffer);
|
||||
JSONObject object = JSONObject.parseObject(buffer);
|
||||
String tp = object.getString("tp");
|
||||
if ("init".equals(tp)) {
|
||||
//初始化连接
|
||||
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","gameid":"1080","rows":"30"}}
|
||||
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null) {
|
||||
WebscoketObj finalWebscoketObj = webscoketObj;
|
||||
executorService.execute(() -> {
|
||||
logger.debug("connectToSSH 内线程;id:{},session:{},websocketObj:{}",
|
||||
Thread.currentThread().getId(), session.getId(), finalWebscoketObj.getSession().getId());
|
||||
connectTossh(finalWebscoketObj, connectInfo, session);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
} else if ("client".equals(tp)) {
|
||||
String data = object.getString("data");
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null) {
|
||||
transTossh(webscoketObj.getOutputStream(), data);
|
||||
}
|
||||
} else if ("h".equals(tp)){
|
||||
webscoketObj = findBySession(session);
|
||||
if (webscoketObj != null && webscoketObj.getChannel()!=null) {
|
||||
webscoketObj.getChannel().getSession().sendKeepAliveMsg();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("转发命令到ssh出错: {}", e);
|
||||
//closeBySsh(webscoketObj);
|
||||
closeByWebsocket(webscoketObj.getSession());
|
||||
}
|
||||
private void transTossh(OutputStream outputStream, String data) throws IOException {
|
||||
if (outputStream != null) {
|
||||
outputStream.write(data.getBytes());
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void connectTossh(WebscoketObj webscoketObj, ConnectInfo connectInfo, WebSocketSession webSocketSession) {
|
||||
Session session = null;
|
||||
try {
|
||||
JSch jsch = new JSch();
|
||||
JSch.setLogger(jschLogger);
|
||||
|
||||
private void transTossh(OutputStream outputStream, String data) throws IOException {
|
||||
if (outputStream != null) {
|
||||
outputStream.write(data.getBytes());
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
// 启动线程
|
||||
java.util.Properties config = new java.util.Properties();
|
||||
config.put("StrictHostKeyChecking", "no");
|
||||
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), connectInfo.getPort());
|
||||
|
||||
private void connectTossh(WebscoketObj webscoketObj, ConnectInfo connectInfo, WebSocketSession webSocketSession) {
|
||||
Session session = null;
|
||||
try {
|
||||
JSch jsch = new JSch();
|
||||
JSch.setLogger(jschLogger);
|
||||
session.setConfig(config);
|
||||
session.setPassword(connectInfo.getSecret());
|
||||
session.setUserInfo(new UserInfo() {
|
||||
@Override
|
||||
public String getPassphrase() {
|
||||
return null;
|
||||
}
|
||||
|
||||
//启动线程
|
||||
java.util.Properties config = new java.util.Properties();
|
||||
config.put("StrictHostKeyChecking", "no");
|
||||
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), connectInfo.getPort());
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
session.setConfig(config);
|
||||
session.setPassword(connectInfo.getSecret());
|
||||
session.setUserInfo(new UserInfo() {
|
||||
@Override
|
||||
public String getPassphrase() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean promptPassword(String s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean promptPassphrase(String s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promptPassword(String s) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean promptYesNo(String s) {
|
||||
return true;
|
||||
} // Accept all server keys
|
||||
|
||||
@Override
|
||||
public boolean promptPassphrase(String s) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void showMessage(String s) {
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public boolean promptYesNo(String s) {
|
||||
return true;
|
||||
} // Accept all server keys
|
||||
session.setServerAliveInterval(30 * 1000); // 30秒心跳一次,用于保活
|
||||
|
||||
@Override
|
||||
public void showMessage(String s) {
|
||||
}
|
||||
});
|
||||
session.connect();
|
||||
ChannelShell channel = (ChannelShell) session.openChannel("shell");
|
||||
channel.setPtyType("xterm");
|
||||
|
||||
if (connectInfo.getRows() > 0 && connectInfo.getColumns() > 0) {
|
||||
channel.setPtySize(connectInfo.getColumns(), connectInfo.getRows(), connectInfo.getWidth(),
|
||||
connectInfo.getHeight());
|
||||
}
|
||||
|
||||
session.setServerAliveInterval(30*1000); //30秒心跳一次,用于保活
|
||||
channel.connect();
|
||||
|
||||
session.connect();
|
||||
ChannelShell channel = (ChannelShell) session.openChannel("shell");
|
||||
channel.setPtyType("xterm");
|
||||
webscoketObj.setChannel(channel);
|
||||
InputStream inputStream = channel.getInputStream();
|
||||
webscoketObj.setOutputStream(channel.getOutputStream());
|
||||
|
||||
if (connectInfo.getRows()>0&&connectInfo.getColumns()>0) {
|
||||
channel.setPtySize(
|
||||
connectInfo.getColumns(),
|
||||
connectInfo.getRows(),
|
||||
connectInfo.getWidth(),
|
||||
connectInfo.getHeight());
|
||||
}
|
||||
webscoketObj.setConnectInfo(connectInfo);
|
||||
|
||||
channel.connect();
|
||||
websshService.active("" + connectInfo.getGameid());
|
||||
|
||||
webscoketObj.setChannel(channel);
|
||||
InputStream inputStream = channel.getInputStream();
|
||||
webscoketObj.setOutputStream(channel.getOutputStream());
|
||||
// 循环读取
|
||||
byte[] buf = new byte[1024];
|
||||
while (true) {
|
||||
int length = inputStream.read(buf);
|
||||
if (length < 0) {
|
||||
throw new Exception("读取终止,连接: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort());
|
||||
}
|
||||
sendMsg(webSocketSession, Arrays.copyOfRange(buf, 0, length));
|
||||
}
|
||||
|
||||
webscoketObj.setConnectInfo(connectInfo);
|
||||
} catch (Exception e) {
|
||||
logger.error("连接关闭: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
|
||||
} finally {
|
||||
logger.info("连接关闭, {}", connectInfo.getHost());
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
|
||||
websshService.active(""+connectInfo.getGameid());
|
||||
closeByWebsocket(webscoketObj.getSession());
|
||||
}
|
||||
}
|
||||
|
||||
//循环读取
|
||||
byte[] buf = new byte[1024];
|
||||
while (true) {
|
||||
int length = inputStream.read(buf);
|
||||
if (length < 0) {
|
||||
throw new Exception("读取终止,连接: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort());
|
||||
}
|
||||
sendMsg(webSocketSession, Arrays.copyOfRange(buf, 0, length));
|
||||
}
|
||||
/**
|
||||
* 发送数据回websocket
|
||||
*
|
||||
* @param session
|
||||
* @param buffer
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendMsg(WebSocketSession session, byte[] buffer) throws IOException {
|
||||
session.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭ssh和websocket
|
||||
*
|
||||
* @param webscoketObj
|
||||
*/
|
||||
private void _close(WebscoketObj webscoketObj) {
|
||||
if (webscoketObj != null && webscoketObj.getChannel() != null) {
|
||||
webscoketObj.getChannel().disconnect();
|
||||
try {
|
||||
webscoketObj.getSession().close();
|
||||
webscoketObj.getOutputStream().close();
|
||||
} catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("连接关闭: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
|
||||
} finally {
|
||||
logger.info("连接关闭, {}", connectInfo.getHost());
|
||||
if (session!=null) {
|
||||
session.disconnect();
|
||||
}
|
||||
// 从队列中去除
|
||||
// sessionQueue.remove(webscoketObj);
|
||||
}
|
||||
}
|
||||
|
||||
closeByWebsocket(webscoketObj.getSession());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 因ssh关闭,需要主动关闭websocket
|
||||
*
|
||||
* @param webscoketObj
|
||||
*/
|
||||
private void closeBySsh(WebscoketObj webscoketObj) {
|
||||
_close(webscoketObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 因为webscoket关闭,需要关闭内部ssh
|
||||
*
|
||||
* @param session
|
||||
*/
|
||||
public void closeByWebsocket(WebSocketSession session) {
|
||||
WebscoketObj webscoketObj = findBySession(session);
|
||||
this._close(webscoketObj);
|
||||
|
||||
/**
|
||||
* 发送数据回websocket
|
||||
*
|
||||
* @param session
|
||||
* @param buffer
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendMsg(WebSocketSession session, byte[] buffer) throws IOException {
|
||||
session.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
|
||||
}
|
||||
if (webscoketObj != null && webscoketObj.getConnectInfo() != null) {
|
||||
int gameId = webscoketObj.getConnectInfo().getGameid();
|
||||
|
||||
/**
|
||||
* 关闭ssh和websocket
|
||||
*
|
||||
* @param webscoketObj
|
||||
*/
|
||||
private void _close(WebscoketObj webscoketObj) {
|
||||
if (webscoketObj != null && webscoketObj.getChannel()!=null) {
|
||||
webscoketObj.getChannel().disconnect();
|
||||
try {
|
||||
webscoketObj.getSession().close();
|
||||
webscoketObj.getOutputStream().close();
|
||||
} catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
}
|
||||
// 如果只剩下这个才删除
|
||||
if (findExistConnectByGameId(gameId)) {
|
||||
try {
|
||||
logger.debug("ssh的pod删除任务加入任务队列:{}", gameId);
|
||||
websshService.delete("" + gameId);
|
||||
} catch (Exception e) {
|
||||
logger.error("删除pod-{}失败:{}", webscoketObj.getConnectInfo().getGameid(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
sessionQueue.remove(webscoketObj);
|
||||
}
|
||||
|
||||
//从队列中去除
|
||||
// sessionQueue.remove(webscoketObj);
|
||||
}
|
||||
}
|
||||
// TODO 这里要注意,如果gameId对应多台主机怎么处理?
|
||||
/**
|
||||
* 通过gameId来匹配
|
||||
*
|
||||
* @param gameId
|
||||
*/
|
||||
public boolean findExistConnectByGameId(int gameId) {
|
||||
|
||||
/**
|
||||
* 因ssh关闭,需要主动关闭websocket
|
||||
*
|
||||
* @param webscoketObj
|
||||
*/
|
||||
private void closeBySsh(WebscoketObj webscoketObj) {
|
||||
_close(webscoketObj);
|
||||
}
|
||||
logger.debug("当前gameID对应的websocket数目:{}",
|
||||
sessionQueue.stream().filter(webscoketObj -> webscoketObj.getConnectInfo() != null
|
||||
&& webscoketObj.getConnectInfo().getGameid() == gameId).count());
|
||||
return sessionQueue.stream()
|
||||
.filter(webscoketObj -> webscoketObj.getConnectInfo() != null
|
||||
&& webscoketObj.getConnectInfo().getGameid() == gameId)
|
||||
// .count() > 0;
|
||||
.count() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 因为webscoket关闭,需要关闭内部ssh
|
||||
*
|
||||
* @param session
|
||||
*/
|
||||
public void closeByWebsocket(WebSocketSession session) {
|
||||
WebscoketObj webscoketObj = findBySession(session);
|
||||
this._close(webscoketObj);
|
||||
|
||||
if (webscoketObj!=null && webscoketObj.getConnectInfo() != null) {
|
||||
int gameId = webscoketObj.getConnectInfo().getGameid();
|
||||
|
||||
// 如果只剩下这个才删除
|
||||
if(findExistConnectByGameId(gameId)){
|
||||
try {
|
||||
logger.debug("ssh的pod删除任务加入任务队列:{}",gameId);
|
||||
websshService.delete("" + gameId);
|
||||
} catch (Exception e) {
|
||||
logger.error("删除pod-{}失败:{}", webscoketObj.getConnectInfo().getGameid(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
sessionQueue.remove(webscoketObj);
|
||||
}
|
||||
|
||||
//TODO 这里要注意,如果gameId对应多台主机怎么处理?
|
||||
/**
|
||||
* 通过gameId来匹配
|
||||
* @param gameId
|
||||
*/
|
||||
public boolean findExistConnectByGameId(int gameId){
|
||||
|
||||
logger.debug("当前gameID对应的websocket数目:{}",sessionQueue.stream().filter(webscoketObj ->webscoketObj.getConnectInfo()!=null &&webscoketObj.getConnectInfo().getGameid()==gameId).count());
|
||||
return sessionQueue.stream().filter(webscoketObj ->
|
||||
webscoketObj.getConnectInfo()!=null && webscoketObj.getConnectInfo().getGameid()==gameId)
|
||||
// .count() > 0;
|
||||
.count() == 1;
|
||||
}
|
||||
|
||||
|
||||
public WebscoketObj findBySession(WebSocketSession session) {
|
||||
Optional<WebscoketObj> optional = sessionQueue.stream().filter(webscoketObj -> webscoketObj.getSession() == session).findFirst();
|
||||
if (optional.isPresent()) {
|
||||
return optional.get();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public WebscoketObj findBySession(WebSocketSession session) {
|
||||
Optional<WebscoketObj> optional = sessionQueue.stream()
|
||||
.filter(webscoketObj -> webscoketObj.getSession() == session).findFirst();
|
||||
if (optional.isPresent()) {
|
||||
return optional.get();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
package com.educoder.bridge.webssh.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import com.educoder.bridge.common.utils.ShellUtil;
|
||||
import com.educoder.bridge.common.utils.TimeHelper;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.game.service.PodManagerService;
|
||||
import com.educoder.bridge.webssh.model.Webssh;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -15,7 +10,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import com.educoder.bridge.common.utils.JedisUtil;
|
||||
import com.educoder.bridge.common.utils.PortUtil;
|
||||
import com.educoder.bridge.common.utils.TimeHelper;
|
||||
import com.educoder.bridge.game.service.K8sService;
|
||||
import com.educoder.bridge.game.service.PodManagerService;
|
||||
import com.educoder.bridge.webssh.model.Webssh;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
|
||||
/**
|
||||
* @author guange
|
||||
|
@ -23,139 +25,143 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||
*/
|
||||
@Service("WebsshService")
|
||||
public class WebsshService {
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebsshService.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(WebsshService.class);
|
||||
|
||||
@Value("${webssh.configBakPath}")
|
||||
private String configBakPath;
|
||||
@Value("${webssh.configBakPath}")
|
||||
private String configBakPath;
|
||||
|
||||
@Value("${k8s.serverUrl}")
|
||||
private String k8sServer;
|
||||
@Value("${k8s.serverUrl}")
|
||||
private String k8sServer;
|
||||
|
||||
@Value("${webssh.delayDeleteTime:900}") //15分钟
|
||||
private int delayDeleteTime;
|
||||
@Value("${webssh.delayDeleteTime:900}") // 15分钟
|
||||
private int delayDeleteTime;
|
||||
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
@Autowired
|
||||
private K8sService k8sService;
|
||||
|
||||
@Autowired
|
||||
PodManagerService podManagerService;
|
||||
@Autowired
|
||||
PodManagerService podManagerService;
|
||||
|
||||
private static ScheduledExecutorService timer;
|
||||
public Webssh create(String tpiID, Integer podType, String containers) throws Exception {
|
||||
logger.debug("tpiID: {}, podType: {}", tpiID, podType);
|
||||
Webssh webssh = new Webssh();
|
||||
|
||||
public Webssh create(String tpiID, Integer podType, String containers) throws Exception {
|
||||
logger.debug("tpiID: {}, podType: {}", tpiID, podType);
|
||||
Webssh webssh = new Webssh();
|
||||
String baseName = podType != 2 ? "webssh" : "evassh";
|
||||
String podName = baseName + "-" + tpiID;
|
||||
|
||||
String baseName = podType != 2 ? "webssh" : "evassh";
|
||||
String podName = baseName + "-" + tpiID;
|
||||
String websshServiceName = podName + "-22";
|
||||
|
||||
String websshServiceName = podName + "-22";
|
||||
// 取对应的port号
|
||||
String svcPort = JedisUtil.hget("port1", podName);
|
||||
// 获取svcPort或新生成svcPort(webssh的映射端口号)
|
||||
if (svcPort == null) {
|
||||
svcPort = PortUtil.getPort() + "";
|
||||
JedisUtil.hset("port1", podName, svcPort);
|
||||
}
|
||||
|
||||
// 取对应的port号
|
||||
String svcPort = JedisUtil.hget("port1", podName);
|
||||
// 获取svcPort或新生成svcPort(webssh的映射端口号)
|
||||
if (svcPort == null) {
|
||||
svcPort = PortUtil.getPort() + "";
|
||||
JedisUtil.hset("port1", podName, svcPort);
|
||||
}
|
||||
// 如果pod和服务都存在
|
||||
boolean existService = serviceExist(websshServiceName);
|
||||
boolean existPod = false;
|
||||
Pod pod = k8sService.getPod(podName);
|
||||
if(pod != null) {
|
||||
String phase = pod.getStatus().getPhase();
|
||||
if ("Running".equals(phase)) {
|
||||
existPod = true;
|
||||
} else {
|
||||
k8sService.deletePod(podName);
|
||||
logger.info("获取ssh连接信息,delete 处于{}状态的 pod {}", phase, podName);
|
||||
}
|
||||
}
|
||||
if (existService && existPod) {
|
||||
// 如果已经被加入删除任务,移除删除任务
|
||||
podManagerService.cancelDel(podName);
|
||||
|
||||
// 如果pod和服务都存在
|
||||
if (serviceExist(websshServiceName) && podExist(podName)) {
|
||||
// 如果已经被加入删除任务,移除删除任务
|
||||
podManagerService.cancelDel(podName);
|
||||
// 直接返回结果
|
||||
webssh.setAddress(k8sServer);
|
||||
webssh.setPort(svcPort);
|
||||
return webssh;
|
||||
}
|
||||
|
||||
// 直接返回结果
|
||||
webssh.setAddress(k8sServer);
|
||||
webssh.setPort(svcPort);
|
||||
return webssh;
|
||||
}
|
||||
if (!existPod) {
|
||||
k8sService.createPod(podName, tpiID, baseName, containers, null);
|
||||
}
|
||||
|
||||
if (!podExist(podName)) {
|
||||
k8sService.createPod(podName, tpiID, baseName, containers);
|
||||
}
|
||||
if (!existService) {
|
||||
k8sService.createService(websshServiceName, podName, tpiID, 22, Integer.parseInt(svcPort));
|
||||
}
|
||||
logger.info("Pod成功创建,Webssh连入,tpiID: {}, podName: {}, time: {}", tpiID, websshServiceName,
|
||||
TimeHelper.getCurrentTime());
|
||||
|
||||
webssh.setAddress(k8sServer);
|
||||
webssh.setPort(svcPort + "");
|
||||
logger.debug("response: ip: {}, port: {}", webssh.getAddress(), webssh.getPort());
|
||||
return webssh;
|
||||
}
|
||||
|
||||
if (!serviceExist(websshServiceName)) {
|
||||
k8sService.createService(websshServiceName, podName, tpiID, 22, Integer.parseInt(svcPort));
|
||||
}
|
||||
logger.info("Pod成功创建,Webssh连入,tpiID: {}, podName: {}, time: {}",
|
||||
tpiID, websshServiceName, TimeHelper.getCurrentTime());
|
||||
public boolean serviceExist(String podName) {
|
||||
return k8sService.svcExist(podName);
|
||||
}
|
||||
|
||||
webssh.setAddress(k8sServer);
|
||||
webssh.setPort(svcPort + "");
|
||||
logger.debug("response: ip: {}, port: {}", webssh.getAddress(), webssh.getPort());
|
||||
return webssh;
|
||||
}
|
||||
public boolean podExist(String podName) {
|
||||
return k8sService.podExist(podName);
|
||||
}
|
||||
|
||||
public boolean serviceExist(String podName) {
|
||||
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
|
||||
if (out.getInteger("exitStatus") == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void delete(String tpiID) {
|
||||
delete(tpiID, delayDeleteTime);
|
||||
}
|
||||
|
||||
public boolean podExist(String podName) {
|
||||
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get pod " + podName);
|
||||
if (out.getInteger("exitStatus") == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void delete(String tpiID, int delayTime) {
|
||||
// 获取pod名
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
|
||||
public void delete(String tpiID) {
|
||||
delete(tpiID, delayDeleteTime);
|
||||
}
|
||||
if (StringUtils.isEmpty(websshPodName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void delete(String tpiID,int delayTime) {
|
||||
// 获取pod名
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
// 当删除队列中已经有删除当前port对应的任务的时候就直接返回
|
||||
podManagerService.deletePodAfterTime(websshPodName, delayTime);
|
||||
|
||||
if (StringUtils.isEmpty(websshPodName)) {
|
||||
return;
|
||||
}
|
||||
logger.info("Webssh连接断开,生成定时删除任务,Pod加入删除队列: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName,
|
||||
TimeHelper.getCurrentTime());
|
||||
}
|
||||
|
||||
//当删除队列中已经有删除当前port对应的任务的时候就直接返回
|
||||
podManagerService.deletePodAfterTime(websshPodName, delayTime);
|
||||
public void deleteNow(String tpiID) throws Exception {
|
||||
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
|
||||
logger.info("Webssh连接断开,生成定时删除任务,Pod加入删除队列: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName, TimeHelper.getCurrentTime());
|
||||
}
|
||||
if (StringUtils.isEmpty(websshPodName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void deleteNow(String tpiID) throws Exception {
|
||||
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
delete(tpiID, 0);
|
||||
|
||||
if (StringUtils.isEmpty(websshPodName)) {
|
||||
return;
|
||||
}
|
||||
int timeout = 10;
|
||||
while ((podExist(websshPodName) || serviceExist(websshPodName)) && timeout > 0) {
|
||||
Thread.sleep(1000);
|
||||
timeout--;
|
||||
}
|
||||
}
|
||||
|
||||
delete(tpiID, 0);
|
||||
/**
|
||||
* 通过tpiID获取podName
|
||||
*
|
||||
* @param tpiID
|
||||
* @return
|
||||
*/
|
||||
private String getPodNameFromTpiId(String tpiID) {
|
||||
Map<String, String> inLabels = new HashMap<>();
|
||||
inLabels.put("tpiID", tpiID);
|
||||
inLabels.put("type", "webssh,evassh");
|
||||
Map<String, String> notInLabels = new HashMap<>();
|
||||
Pod pod = k8sService.getK8sPod(inLabels, notInLabels);
|
||||
return pod == null ? null : pod.getMetadata().getName();
|
||||
}
|
||||
|
||||
int timeout = 10;
|
||||
while (podExist(websshPodName) || serviceExist(websshPodName) && timeout > 0) {
|
||||
Thread.sleep(1000);
|
||||
timeout--;
|
||||
}
|
||||
}
|
||||
public void active(String tpiID) {
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
|
||||
/**
|
||||
* 通过tpiID获取podName
|
||||
* @param tpiID
|
||||
* @return
|
||||
*/
|
||||
private String getPodNameFromTpiId(String tpiID){
|
||||
String out = ShellUtil.execute("kubectl get pods -l tpiID=" + tpiID + ",type!=evaluate | grep -v NAME");
|
||||
String websshPodName = out.substring(0, out.indexOf(" "));
|
||||
return websshPodName;
|
||||
}
|
||||
|
||||
public void active(String tpiID) {
|
||||
String websshPodName = getPodNameFromTpiId(tpiID);
|
||||
|
||||
logger.info("Webssh active方法被调用,连接被激活,将pod从定时删除队列中移除: tpiID: {}, podName: {}, time: {}",
|
||||
tpiID, websshPodName, TimeHelper.getCurrentTime());
|
||||
podManagerService.cancelDel(websshPodName);
|
||||
}
|
||||
logger.info("Webssh active方法被调用,连接被激活,将pod从定时删除队列中移除: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName,
|
||||
TimeHelper.getCurrentTime());
|
||||
podManagerService.cancelDel(websshPodName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.http.impl.nio.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.nio.NHttpClientEventHandler;
|
||||
import org.apache.http.nio.conn.NHttpClientConnectionManager;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.util.Asserts;
|
||||
|
||||
abstract class BridgeCloseableHttpAsyncClientBase extends CloseableHttpPipeliningClient {
|
||||
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
static enum Status {INACTIVE, ACTIVE, STOPPED}
|
||||
|
||||
private final NHttpClientConnectionManager connmgr;
|
||||
private final Thread reactorThread;
|
||||
|
||||
private final AtomicReference<Status> status;
|
||||
|
||||
public BridgeCloseableHttpAsyncClientBase(
|
||||
final NHttpClientConnectionManager connmgr,
|
||||
final ThreadFactory threadFactory,
|
||||
final NHttpClientEventHandler handler, long bodyLength) {
|
||||
super();
|
||||
this.connmgr = connmgr;
|
||||
if (threadFactory != null && handler != null) {
|
||||
this.reactorThread = threadFactory.newThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// 使用 bridge
|
||||
final IOEventDispatch ioEventDispatch = new BridgeInternalIODispatch(handler, bodyLength,
|
||||
BridgeCloseableHttpAsyncClientBase.this);
|
||||
connmgr.execute(ioEventDispatch);
|
||||
} catch (final Exception ex) {
|
||||
log.error("I/O reactor terminated abnormally", ex);
|
||||
} finally {
|
||||
status.set(Status.STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
this.reactorThread = null;
|
||||
}
|
||||
this.status = new AtomicReference<Status>(Status.INACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (this.status.compareAndSet(Status.INACTIVE, Status.ACTIVE)) {
|
||||
if (this.reactorThread != null) {
|
||||
this.reactorThread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ensureRunning() {
|
||||
final Status currentStatus = this.status.get();
|
||||
Asserts.check(currentStatus == Status.ACTIVE, "Request cannot be executed; " +
|
||||
"I/O reactor status: %s", currentStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPED)) {
|
||||
if (this.reactorThread != null) {
|
||||
try {
|
||||
this.connmgr.shutdown();
|
||||
} catch (final IOException ex) {
|
||||
this.log.error("I/O error shutting down connection manager", ex);
|
||||
}
|
||||
try {
|
||||
this.reactorThread.join();
|
||||
} catch (final InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.status.get() == Status.ACTIVE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,873 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.http.impl.nio.client;
|
||||
|
||||
import java.net.ProxySelector;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.ConnectionReuseStrategy;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.auth.AuthSchemeProvider;
|
||||
import org.apache.http.client.AuthenticationStrategy;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.RedirectStrategy;
|
||||
import org.apache.http.client.UserTokenHandler;
|
||||
import org.apache.http.client.config.AuthSchemes;
|
||||
import org.apache.http.client.config.CookieSpecs;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.protocol.RequestAddCookies;
|
||||
import org.apache.http.client.protocol.RequestAuthCache;
|
||||
import org.apache.http.client.protocol.RequestClientConnControl;
|
||||
import org.apache.http.client.protocol.RequestDefaultHeaders;
|
||||
import org.apache.http.client.protocol.RequestExpectContinue;
|
||||
import org.apache.http.client.protocol.ResponseProcessCookies;
|
||||
import org.apache.http.config.ConnectionConfig;
|
||||
import org.apache.http.config.Lookup;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.conn.SchemePortResolver;
|
||||
import org.apache.http.conn.routing.HttpRoutePlanner;
|
||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
||||
import org.apache.http.conn.util.PublicSuffixMatcher;
|
||||
import org.apache.http.conn.util.PublicSuffixMatcherLoader;
|
||||
import org.apache.http.cookie.CookieSpecProvider;
|
||||
import org.apache.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.http.impl.NoConnectionReuseStrategy;
|
||||
import org.apache.http.impl.auth.BasicSchemeFactory;
|
||||
import org.apache.http.impl.auth.DigestSchemeFactory;
|
||||
import org.apache.http.impl.auth.KerberosSchemeFactory;
|
||||
import org.apache.http.impl.auth.NTLMSchemeFactory;
|
||||
import org.apache.http.impl.auth.SPNegoSchemeFactory;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
import org.apache.http.impl.client.NoopUserTokenHandler;
|
||||
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
|
||||
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
|
||||
import org.apache.http.impl.client.TargetAuthenticationStrategy;
|
||||
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
|
||||
import org.apache.http.impl.conn.DefaultRoutePlanner;
|
||||
import org.apache.http.impl.conn.DefaultSchemePortResolver;
|
||||
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
|
||||
import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
|
||||
import org.apache.http.impl.cookie.IgnoreSpecProvider;
|
||||
import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
|
||||
import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
|
||||
import org.apache.http.impl.nio.conn.BridgeManagedNHttpClientConnectionFactory;
|
||||
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
|
||||
import org.apache.http.impl.nio.reactor.IOReactorConfig;
|
||||
import org.apache.http.nio.NHttpClientEventHandler;
|
||||
import org.apache.http.nio.conn.NHttpClientConnectionManager;
|
||||
import org.apache.http.nio.conn.NoopIOSessionStrategy;
|
||||
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
|
||||
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
|
||||
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
|
||||
import org.apache.http.nio.reactor.ConnectingIOReactor;
|
||||
import org.apache.http.protocol.HttpProcessor;
|
||||
import org.apache.http.protocol.HttpProcessorBuilder;
|
||||
import org.apache.http.protocol.RequestContent;
|
||||
import org.apache.http.protocol.RequestTargetHost;
|
||||
import org.apache.http.protocol.RequestUserAgent;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
import org.apache.http.util.TextUtils;
|
||||
import org.apache.http.util.VersionInfo;
|
||||
|
||||
/**
|
||||
* Builder for {@link CloseableHttpAsyncClient} instances.
|
||||
* <p>
|
||||
* When a particular component is not explicitly this class will use its default
|
||||
* implementation. System properties will be taken into account when configuring
|
||||
* the default implementations when {@link #useSystemProperties()} method is
|
||||
* called prior to calling {@link #build()}.
|
||||
* <ul>
|
||||
* <li>ssl.TrustManagerFactory.algorithm</li>
|
||||
* <li>javax.net.ssl.trustStoreType</li>
|
||||
* <li>javax.net.ssl.trustStore</li>
|
||||
* <li>javax.net.ssl.trustStoreProvider</li>
|
||||
* <li>javax.net.ssl.trustStorePassword</li>
|
||||
* <li>ssl.KeyManagerFactory.algorithm</li>
|
||||
* <li>javax.net.ssl.keyStoreType</li>
|
||||
* <li>javax.net.ssl.keyStore</li>
|
||||
* <li>javax.net.ssl.keyStoreProvider</li>
|
||||
* <li>javax.net.ssl.keyStorePassword</li>
|
||||
* <li>https.protocols</li>
|
||||
* <li>https.cipherSuites</li>
|
||||
* <li>http.proxyHost</li>
|
||||
* <li>http.proxyPort</li>
|
||||
* <li>http.keepAlive</li>
|
||||
* <li>http.maxConnections</li>
|
||||
* <li>http.agent</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Please note that some settings used by this class can be mutually exclusive
|
||||
* and may not apply when building {@link CloseableHttpAsyncClient} instances.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class BridgeHttpAsyncClientBuilder {
|
||||
|
||||
private NHttpClientConnectionManager connManager;
|
||||
private boolean connManagerShared;
|
||||
private SchemePortResolver schemePortResolver;
|
||||
private SchemeIOSessionStrategy sslStrategy;
|
||||
private HostnameVerifier hostnameVerifier;
|
||||
private SSLContext sslcontext;
|
||||
private ConnectionReuseStrategy reuseStrategy;
|
||||
private ConnectionKeepAliveStrategy keepAliveStrategy;
|
||||
private AuthenticationStrategy targetAuthStrategy;
|
||||
private AuthenticationStrategy proxyAuthStrategy;
|
||||
private UserTokenHandler userTokenHandler;
|
||||
private HttpProcessor httpprocessor;
|
||||
|
||||
private LinkedList<HttpRequestInterceptor> requestFirst;
|
||||
private LinkedList<HttpRequestInterceptor> requestLast;
|
||||
private LinkedList<HttpResponseInterceptor> responseFirst;
|
||||
private LinkedList<HttpResponseInterceptor> responseLast;
|
||||
|
||||
private HttpRoutePlanner routePlanner;
|
||||
private RedirectStrategy redirectStrategy;
|
||||
private Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||
private Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||
private CookieStore cookieStore;
|
||||
private CredentialsProvider credentialsProvider;
|
||||
private String userAgent;
|
||||
private HttpHost proxy;
|
||||
private Collection<? extends Header> defaultHeaders;
|
||||
private IOReactorConfig defaultIOReactorConfig;
|
||||
private ConnectionConfig defaultConnectionConfig;
|
||||
private RequestConfig defaultRequestConfig;
|
||||
|
||||
private ThreadFactory threadFactory;
|
||||
private NHttpClientEventHandler eventHandler;
|
||||
|
||||
private PublicSuffixMatcher publicSuffixMatcher;
|
||||
|
||||
private boolean systemProperties;
|
||||
private boolean cookieManagementDisabled;
|
||||
private boolean authCachingDisabled;
|
||||
private boolean connectionStateDisabled;
|
||||
|
||||
private int maxConnTotal = 0;
|
||||
private int maxConnPerRoute = 0;
|
||||
/**
|
||||
* 请求体长度
|
||||
*/
|
||||
private long bodyLength;
|
||||
|
||||
public static BridgeHttpAsyncClientBuilder create() {
|
||||
return new BridgeHttpAsyncClientBuilder();
|
||||
}
|
||||
|
||||
protected BridgeHttpAsyncClientBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns file containing public suffix matcher. Instances of this class can be
|
||||
* created with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
|
||||
*
|
||||
* @see org.apache.http.conn.util.PublicSuffixMatcher
|
||||
* @see org.apache.http.conn.util.PublicSuffixMatcherLoader
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
|
||||
this.publicSuffixMatcher = publicSuffixMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link NHttpClientConnectionManager} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setConnectionManager(final NHttpClientConnectionManager connManager) {
|
||||
this.connManager = connManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the connection manager is to be shared by multiple client instances.
|
||||
* <p>
|
||||
* If the connection manager is shared its life-cycle is expected to be managed
|
||||
* by the caller and it will not be shut down if the client is closed.
|
||||
*
|
||||
* @param shared
|
||||
* defines whether or not the connection manager can be shared by
|
||||
* multiple clients.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setConnectionManagerShared(final boolean shared) {
|
||||
this.connManagerShared = shared;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link SchemePortResolver} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) {
|
||||
this.schemePortResolver = schemePortResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns maximum total connection value.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setMaxConnTotal(final int maxConnTotal) {
|
||||
this.maxConnTotal = maxConnTotal;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns maximum connection per route value.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
|
||||
this.maxConnPerRoute = maxConnPerRoute;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link ConnectionReuseStrategy} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setConnectionReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
|
||||
this.reuseStrategy = reuseStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link ConnectionKeepAliveStrategy} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setKeepAliveStrategy(
|
||||
final ConnectionKeepAliveStrategy keepAliveStrategy) {
|
||||
this.keepAliveStrategy = keepAliveStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link UserTokenHandler} instance.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #disableConnectionState()} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
|
||||
this.userTokenHandler = userTokenHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link AuthenticationStrategy} instance for proxy authentication.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setTargetAuthenticationStrategy(
|
||||
final AuthenticationStrategy targetAuthStrategy) {
|
||||
this.targetAuthStrategy = targetAuthStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link AuthenticationStrategy} instance for target host
|
||||
* authentication.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setProxyAuthenticationStrategy(
|
||||
final AuthenticationStrategy proxyAuthStrategy) {
|
||||
this.proxyAuthStrategy = proxyAuthStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link HttpProcessor} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
|
||||
this.httpprocessor = httpprocessor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this protocol interceptor to the head of the protocol processing list.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
|
||||
if (itcp == null) {
|
||||
return this;
|
||||
}
|
||||
if (responseFirst == null) {
|
||||
responseFirst = new LinkedList<HttpResponseInterceptor>();
|
||||
}
|
||||
responseFirst.addFirst(itcp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this protocol interceptor to the tail of the protocol processing list.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
|
||||
if (itcp == null) {
|
||||
return this;
|
||||
}
|
||||
if (responseLast == null) {
|
||||
responseLast = new LinkedList<HttpResponseInterceptor>();
|
||||
}
|
||||
responseLast.addLast(itcp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this protocol interceptor to the head of the protocol processing list.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
|
||||
if (itcp == null) {
|
||||
return this;
|
||||
}
|
||||
if (requestFirst == null) {
|
||||
requestFirst = new LinkedList<HttpRequestInterceptor>();
|
||||
}
|
||||
requestFirst.addFirst(itcp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this protocol interceptor to the tail of the protocol processing list.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
|
||||
if (itcp == null) {
|
||||
return this;
|
||||
}
|
||||
if (requestLast == null) {
|
||||
requestLast = new LinkedList<HttpRequestInterceptor>();
|
||||
}
|
||||
requestLast.addLast(itcp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link HttpRoutePlanner} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
|
||||
this.routePlanner = routePlanner;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link RedirectStrategy} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
|
||||
this.redirectStrategy = redirectStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link CookieStore} instance which will be used for request
|
||||
* execution if not explicitly set in the client execution context.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
|
||||
this.cookieStore = cookieStore;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link CredentialsProvider} instance which will be used for
|
||||
* request execution if not explicitly set in the client execution context.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultCredentialsProvider(
|
||||
final CredentialsProvider credentialsProvider) {
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
|
||||
* be used for request execution if not explicitly set in the client execution
|
||||
* context.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultAuthSchemeRegistry(
|
||||
final Lookup<AuthSchemeProvider> authSchemeRegistry) {
|
||||
this.authSchemeRegistry = authSchemeRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
|
||||
* be used for request execution if not explicitly set in the client execution
|
||||
* context.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultCookieSpecRegistry(
|
||||
final Lookup<CookieSpecProvider> cookieSpecRegistry) {
|
||||
this.cookieSpecRegistry = cookieSpecRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@code User-Agent} value.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setUserAgent(final String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default proxy value.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setRoutePlanner( org.apache.http.conn.routing.HttpRoutePlanner)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setProxy(final HttpHost proxy) {
|
||||
this.proxy = proxy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link SchemeIOSessionStrategy} instance.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setSSLStrategy(final SchemeIOSessionStrategy strategy) {
|
||||
this.sslStrategy = strategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link SSLContext} instance.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* and the
|
||||
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
|
||||
* methods.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setSSLContext(final SSLContext sslcontext) {
|
||||
this.sslcontext = sslcontext;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link X509HostnameVerifier} instance.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* and the
|
||||
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
|
||||
* methods.
|
||||
*
|
||||
* @deprecated (4.1) use
|
||||
* {@link #setSSLHostnameVerifier(javax.net.ssl.HostnameVerifier)}
|
||||
*/
|
||||
@Deprecated
|
||||
public final BridgeHttpAsyncClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link javax.net.ssl.HostnameVerifier} instance.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* and the
|
||||
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
|
||||
* methods.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default request header values.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
|
||||
this.defaultHeaders = defaultHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link IOReactorConfig}.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultIOReactorConfig(final IOReactorConfig config) {
|
||||
this.defaultIOReactorConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link ConnectionConfig}.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
|
||||
* method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
|
||||
this.defaultConnectionConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link RequestConfig} instance which will be used for request
|
||||
* execution if not explicitly set in the client execution context.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
|
||||
this.defaultRequestConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link ThreadFactory} instance.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
|
||||
this.threadFactory = threadFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link NHttpClientEventHandler} instance.
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder setEventHandler(final NHttpClientEventHandler eventHandler) {
|
||||
this.eventHandler = eventHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables connection state tracking.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder disableConnectionState() {
|
||||
connectionStateDisabled = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables state (cookie) management.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder disableCookieManagement() {
|
||||
cookieManagementDisabled = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables authentication scheme caching.
|
||||
* <p>
|
||||
* Please note this value can be overridden by the
|
||||
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder disableAuthCaching() {
|
||||
authCachingDisabled = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use system properties when creating and configuring default implementations.
|
||||
*/
|
||||
public final BridgeHttpAsyncClientBuilder useSystemProperties() {
|
||||
systemProperties = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final BridgeHttpAsyncClientBuilder setBodyLength(long bodyLength) {
|
||||
this.bodyLength = bodyLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String[] split(final String s) {
|
||||
if (TextUtils.isBlank(s)) {
|
||||
return null;
|
||||
}
|
||||
return s.split(" *, *");
|
||||
}
|
||||
|
||||
public CloseableHttpAsyncClient build() {
|
||||
|
||||
PublicSuffixMatcher publicSuffixMatcher = this.publicSuffixMatcher;
|
||||
if (publicSuffixMatcher == null) {
|
||||
publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
|
||||
}
|
||||
|
||||
NHttpClientConnectionManager connManager = this.connManager;
|
||||
if (connManager == null) {
|
||||
SchemeIOSessionStrategy sslStrategy = this.sslStrategy;
|
||||
if (sslStrategy == null) {
|
||||
SSLContext sslcontext = this.sslcontext;
|
||||
if (sslcontext == null) {
|
||||
if (systemProperties) {
|
||||
sslcontext = SSLContexts.createSystemDefault();
|
||||
} else {
|
||||
sslcontext = SSLContexts.createDefault();
|
||||
}
|
||||
}
|
||||
final String[] supportedProtocols = systemProperties ? split(System.getProperty("https.protocols"))
|
||||
: null;
|
||||
final String[] supportedCipherSuites = systemProperties
|
||||
? split(System.getProperty("https.cipherSuites"))
|
||||
: null;
|
||||
HostnameVerifier hostnameVerifier = this.hostnameVerifier;
|
||||
if (hostnameVerifier == null) {
|
||||
hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
|
||||
}
|
||||
sslStrategy = new SSLIOSessionStrategy(sslcontext, supportedProtocols, supportedCipherSuites,
|
||||
hostnameVerifier);
|
||||
}
|
||||
final ConnectingIOReactor ioreactor = IOReactorUtils.create(
|
||||
defaultIOReactorConfig != null ? defaultIOReactorConfig : IOReactorConfig.DEFAULT, threadFactory);
|
||||
// 加入 BridgeManagedNHttpClientConnectionFactory
|
||||
final PoolingNHttpClientConnectionManager poolingmgr = new PoolingNHttpClientConnectionManager(ioreactor,
|
||||
BridgeManagedNHttpClientConnectionFactory.INSTANCE,
|
||||
RegistryBuilder.<SchemeIOSessionStrategy>create().register("http", NoopIOSessionStrategy.INSTANCE)
|
||||
.register("https", sslStrategy).build());
|
||||
if (defaultConnectionConfig != null) {
|
||||
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
|
||||
}
|
||||
if (systemProperties) {
|
||||
String s = System.getProperty("http.keepAlive", "true");
|
||||
if ("true".equalsIgnoreCase(s)) {
|
||||
s = System.getProperty("http.maxConnections", "5");
|
||||
final int max = Integer.parseInt(s);
|
||||
poolingmgr.setDefaultMaxPerRoute(max);
|
||||
poolingmgr.setMaxTotal(2 * max);
|
||||
}
|
||||
} else {
|
||||
if (maxConnTotal > 0) {
|
||||
poolingmgr.setMaxTotal(maxConnTotal);
|
||||
}
|
||||
if (maxConnPerRoute > 0) {
|
||||
poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
|
||||
}
|
||||
}
|
||||
connManager = poolingmgr;
|
||||
}
|
||||
ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
|
||||
if (reuseStrategy == null) {
|
||||
if (systemProperties) {
|
||||
final String s = System.getProperty("http.keepAlive", "true");
|
||||
if ("true".equalsIgnoreCase(s)) {
|
||||
reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
|
||||
} else {
|
||||
reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
|
||||
}
|
||||
} else {
|
||||
reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
|
||||
}
|
||||
}
|
||||
ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
|
||||
if (keepAliveStrategy == null) {
|
||||
keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
|
||||
}
|
||||
AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
|
||||
if (targetAuthStrategy == null) {
|
||||
targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
|
||||
}
|
||||
AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
|
||||
if (proxyAuthStrategy == null) {
|
||||
proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
|
||||
}
|
||||
UserTokenHandler userTokenHandler = this.userTokenHandler;
|
||||
if (userTokenHandler == null) {
|
||||
if (!connectionStateDisabled) {
|
||||
userTokenHandler = DefaultAsyncUserTokenHandler.INSTANCE;
|
||||
} else {
|
||||
userTokenHandler = NoopUserTokenHandler.INSTANCE;
|
||||
}
|
||||
}
|
||||
SchemePortResolver schemePortResolver = this.schemePortResolver;
|
||||
if (schemePortResolver == null) {
|
||||
schemePortResolver = DefaultSchemePortResolver.INSTANCE;
|
||||
}
|
||||
|
||||
HttpProcessor httpprocessor = this.httpprocessor;
|
||||
if (httpprocessor == null) {
|
||||
|
||||
String userAgent = this.userAgent;
|
||||
if (userAgent == null) {
|
||||
if (systemProperties) {
|
||||
userAgent = System.getProperty("http.agent");
|
||||
}
|
||||
if (userAgent == null) {
|
||||
userAgent = VersionInfo.getUserAgent("Apache-HttpAsyncClient", "org.apache.http.nio.client",
|
||||
getClass());
|
||||
}
|
||||
}
|
||||
|
||||
final HttpProcessorBuilder b = HttpProcessorBuilder.create();
|
||||
if (requestFirst != null) {
|
||||
for (final HttpRequestInterceptor i : requestFirst) {
|
||||
b.addFirst(i);
|
||||
}
|
||||
}
|
||||
if (responseFirst != null) {
|
||||
for (final HttpResponseInterceptor i : responseFirst) {
|
||||
b.addFirst(i);
|
||||
}
|
||||
}
|
||||
b.addAll(new RequestDefaultHeaders(defaultHeaders), new RequestContent(), new RequestTargetHost(),
|
||||
new RequestClientConnControl(), new RequestUserAgent(userAgent), new RequestExpectContinue());
|
||||
if (!cookieManagementDisabled) {
|
||||
b.add(new RequestAddCookies());
|
||||
}
|
||||
if (!authCachingDisabled) {
|
||||
b.add(new RequestAuthCache());
|
||||
}
|
||||
if (!cookieManagementDisabled) {
|
||||
b.add(new ResponseProcessCookies());
|
||||
}
|
||||
if (requestLast != null) {
|
||||
for (final HttpRequestInterceptor i : requestLast) {
|
||||
b.addLast(i);
|
||||
}
|
||||
}
|
||||
if (responseLast != null) {
|
||||
for (final HttpResponseInterceptor i : responseLast) {
|
||||
b.addLast(i);
|
||||
}
|
||||
}
|
||||
httpprocessor = b.build();
|
||||
}
|
||||
// Add redirect executor, if not disabled
|
||||
HttpRoutePlanner routePlanner = this.routePlanner;
|
||||
if (routePlanner == null) {
|
||||
if (proxy != null) {
|
||||
routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
|
||||
} else if (systemProperties) {
|
||||
routePlanner = new SystemDefaultRoutePlanner(schemePortResolver, ProxySelector.getDefault());
|
||||
} else {
|
||||
routePlanner = new DefaultRoutePlanner(schemePortResolver);
|
||||
}
|
||||
}
|
||||
Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
|
||||
if (authSchemeRegistry == null) {
|
||||
authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
|
||||
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
|
||||
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
|
||||
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
|
||||
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
|
||||
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()).build();
|
||||
}
|
||||
Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
|
||||
if (cookieSpecRegistry == null) {
|
||||
final CookieSpecProvider defaultProvider = new DefaultCookieSpecProvider(publicSuffixMatcher);
|
||||
final CookieSpecProvider laxStandardProvider = new RFC6265CookieSpecProvider(
|
||||
RFC6265CookieSpecProvider.CompatibilityLevel.RELAXED, publicSuffixMatcher);
|
||||
final CookieSpecProvider strictStandardProvider = new RFC6265CookieSpecProvider(
|
||||
RFC6265CookieSpecProvider.CompatibilityLevel.STRICT, publicSuffixMatcher);
|
||||
cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
|
||||
.register(CookieSpecs.DEFAULT, defaultProvider).register("best-match", defaultProvider)
|
||||
.register("compatibility", defaultProvider).register(CookieSpecs.STANDARD, laxStandardProvider)
|
||||
.register(CookieSpecs.STANDARD_STRICT, strictStandardProvider)
|
||||
.register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
|
||||
.register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider()).build();
|
||||
}
|
||||
|
||||
CookieStore defaultCookieStore = this.cookieStore;
|
||||
if (defaultCookieStore == null) {
|
||||
defaultCookieStore = new BasicCookieStore();
|
||||
}
|
||||
|
||||
CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
|
||||
if (defaultCredentialsProvider == null) {
|
||||
if (systemProperties) {
|
||||
defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
|
||||
} else {
|
||||
defaultCredentialsProvider = new BasicCredentialsProvider();
|
||||
}
|
||||
}
|
||||
RedirectStrategy redirectStrategy = this.redirectStrategy;
|
||||
if (redirectStrategy == null) {
|
||||
redirectStrategy = DefaultRedirectStrategy.INSTANCE;
|
||||
}
|
||||
|
||||
RequestConfig defaultRequestConfig = this.defaultRequestConfig;
|
||||
if (defaultRequestConfig == null) {
|
||||
defaultRequestConfig = RequestConfig.DEFAULT;
|
||||
}
|
||||
|
||||
final MainClientExec exec = new MainClientExec(httpprocessor, routePlanner, redirectStrategy,
|
||||
targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
|
||||
|
||||
ThreadFactory threadFactory = null;
|
||||
NHttpClientEventHandler eventHandler = null;
|
||||
if (!this.connManagerShared) {
|
||||
threadFactory = this.threadFactory;
|
||||
if (threadFactory == null) {
|
||||
threadFactory = Executors.defaultThreadFactory();
|
||||
}
|
||||
eventHandler = this.eventHandler;
|
||||
if (eventHandler == null) {
|
||||
eventHandler = new HttpAsyncRequestExecutor();
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 bridge
|
||||
return new BridgeInternalHttpAsyncClient(connManager, reuseStrategy, keepAliveStrategy, threadFactory,
|
||||
eventHandler, exec, cookieSpecRegistry, authSchemeRegistry, defaultCookieStore,
|
||||
defaultCredentialsProvider, defaultRequestConfig, bodyLength);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.http.impl.nio.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.ConnectionReuseStrategy;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthSchemeProvider;
|
||||
import org.apache.http.auth.AuthState;
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.concurrent.BasicFuture;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.config.Lookup;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.cookie.CookieSpecProvider;
|
||||
import org.apache.http.nio.NHttpClientEventHandler;
|
||||
import org.apache.http.nio.conn.NHttpClientConnectionManager;
|
||||
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
|
||||
import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
|
||||
import org.apache.http.protocol.BasicHttpContext;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
class BridgeInternalHttpAsyncClient extends BridgeCloseableHttpAsyncClientBase {
|
||||
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private final NHttpClientConnectionManager connmgr;
|
||||
private final ConnectionReuseStrategy connReuseStrategy;
|
||||
private final ConnectionKeepAliveStrategy keepaliveStrategy;
|
||||
private final InternalClientExec exec;
|
||||
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||
private final CookieStore cookieStore;
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
private final RequestConfig defaultConfig;
|
||||
|
||||
public BridgeInternalHttpAsyncClient(
|
||||
final NHttpClientConnectionManager connmgr,
|
||||
final ConnectionReuseStrategy connReuseStrategy,
|
||||
final ConnectionKeepAliveStrategy keepaliveStrategy,
|
||||
final ThreadFactory threadFactory,
|
||||
final NHttpClientEventHandler handler,
|
||||
final InternalClientExec exec,
|
||||
final Lookup<CookieSpecProvider> cookieSpecRegistry,
|
||||
final Lookup<AuthSchemeProvider> authSchemeRegistry,
|
||||
final CookieStore cookieStore,
|
||||
final CredentialsProvider credentialsProvider,
|
||||
final RequestConfig defaultConfig, final long bodyLength) {
|
||||
super(connmgr, threadFactory, handler, bodyLength);
|
||||
this.connmgr = connmgr;
|
||||
this.connReuseStrategy = connReuseStrategy;
|
||||
this.keepaliveStrategy = keepaliveStrategy;
|
||||
this.exec = exec;
|
||||
this.cookieSpecRegistry = cookieSpecRegistry;
|
||||
this.authSchemeRegistry = authSchemeRegistry;
|
||||
this.cookieStore = cookieStore;
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
this.defaultConfig = defaultConfig;
|
||||
}
|
||||
|
||||
private void setupContext(final HttpClientContext context) {
|
||||
if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
|
||||
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
|
||||
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
|
||||
context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
|
||||
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
|
||||
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
|
||||
context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
|
||||
}
|
||||
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
|
||||
context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> execute(
|
||||
final HttpAsyncRequestProducer requestProducer,
|
||||
final HttpAsyncResponseConsumer<T> responseConsumer,
|
||||
final HttpContext context,
|
||||
final FutureCallback<T> callback) {
|
||||
ensureRunning();
|
||||
final BasicFuture<T> future = new BasicFuture<T>(callback);
|
||||
final HttpClientContext localcontext = HttpClientContext.adapt(
|
||||
context != null ? context : new BasicHttpContext());
|
||||
setupContext(localcontext);
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
final DefaultClientExchangeHandlerImpl<T> handler = new DefaultClientExchangeHandlerImpl<T>(
|
||||
this.log,
|
||||
requestProducer,
|
||||
responseConsumer,
|
||||
localcontext,
|
||||
future,
|
||||
this.connmgr,
|
||||
this.connReuseStrategy,
|
||||
this.keepaliveStrategy,
|
||||
this.exec);
|
||||
try {
|
||||
handler.start();
|
||||
} catch (final Exception ex) {
|
||||
handler.failed(ex);
|
||||
}
|
||||
return new FutureWrapper<T>(future, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<List<T>> execute(
|
||||
final HttpHost target,
|
||||
final List<? extends HttpAsyncRequestProducer> requestProducers,
|
||||
final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
|
||||
final HttpContext context,
|
||||
final FutureCallback<List<T>> callback) {
|
||||
throw new UnsupportedOperationException("Pipelining not supported");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package org.apache.http.impl.nio.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.http.impl.nio.DefaultNHttpClientConnection;
|
||||
import org.apache.http.impl.nio.conn.BridgeManagedNHttpClientConnectionImpl;
|
||||
import org.apache.http.nio.NHttpClientEventHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BridgeInternalIODispatch extends InternalIODispatch {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
/**
|
||||
* 请求体长度
|
||||
*/
|
||||
private long bodyLength = -1;
|
||||
private CloseableHttpAsyncClient client;
|
||||
private AtomicBoolean sendOver = new AtomicBoolean();
|
||||
|
||||
public BridgeInternalIODispatch(NHttpClientEventHandler handler, long entityLength,
|
||||
CloseableHttpAsyncClient client) {
|
||||
super(handler);
|
||||
this.bodyLength = entityLength;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onOutputReady(DefaultNHttpClientConnection conn) {
|
||||
if (conn instanceof BridgeManagedNHttpClientConnectionImpl) {
|
||||
BridgeManagedNHttpClientConnectionImpl c = (BridgeManagedNHttpClientConnectionImpl) conn;
|
||||
boolean encoderNotCompleted = c.getContentEncoder() != null && !c.getContentEncoder().isCompleted();
|
||||
if (c.isRequestNotSendComplete() || encoderNotCompleted) {// 需要发送数据
|
||||
|
||||
} else { // 收到server 确认
|
||||
sendOver.compareAndSet(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
super.onOutputReady(conn);
|
||||
if (conn instanceof BridgeManagedNHttpClientConnectionImpl) {
|
||||
BridgeManagedNHttpClientConnectionImpl c = (BridgeManagedNHttpClientConnectionImpl) conn;
|
||||
boolean encoderNotCompleted = c.getContentEncoder() != null && !c.getContentEncoder().isCompleted();
|
||||
if (c.isRequestNotSendComplete() || encoderNotCompleted) {// 需要发送数据
|
||||
// do nothing
|
||||
} else {
|
||||
long length = c.getDataLengthTransferred();
|
||||
if (length >= this.bodyLength) {
|
||||
if (!sendOver.get()) {
|
||||
logger.info("请求已经发送完毕, 总长度是 " + length);
|
||||
} else {
|
||||
logger.info("请求已经发送完毕, 总长度是 " + length + ",收到服务的确认,关闭连接");
|
||||
try {
|
||||
conn.close();
|
||||
client.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("nio 关闭异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package org.apache.http.impl.nio.conn;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.config.ConnectionConfig;
|
||||
import org.apache.http.impl.nio.codecs.DefaultHttpRequestWriterFactory;
|
||||
import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
|
||||
import org.apache.http.nio.NHttpMessageParserFactory;
|
||||
import org.apache.http.nio.NHttpMessageWriterFactory;
|
||||
import org.apache.http.nio.conn.ManagedNHttpClientConnection;
|
||||
import org.apache.http.nio.conn.NHttpConnectionFactory;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.nio.reactor.IOSession;
|
||||
import org.apache.http.nio.util.ByteBufferAllocator;
|
||||
import org.apache.http.nio.util.HeapByteBufferAllocator;
|
||||
|
||||
public class BridgeManagedNHttpClientConnectionFactory implements NHttpConnectionFactory<ManagedNHttpClientConnection> {
|
||||
private final Log headerlog = LogFactory.getLog("org.apache.http.headers");
|
||||
private final Log wirelog = LogFactory.getLog("org.apache.http.wire");
|
||||
private final Log log = LogFactory.getLog(ManagedNHttpClientConnectionImpl.class);
|
||||
|
||||
private static final AtomicLong COUNTER = new AtomicLong();
|
||||
|
||||
// 使用 bridge
|
||||
public static final BridgeManagedNHttpClientConnectionFactory INSTANCE = new BridgeManagedNHttpClientConnectionFactory();
|
||||
|
||||
private final ByteBufferAllocator allocator;
|
||||
private final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory;
|
||||
private final NHttpMessageParserFactory<HttpResponse> responseParserFactory;
|
||||
|
||||
public BridgeManagedNHttpClientConnectionFactory(
|
||||
final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
|
||||
final NHttpMessageParserFactory<HttpResponse> responseParserFactory,
|
||||
final ByteBufferAllocator allocator) {
|
||||
super();
|
||||
this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
|
||||
DefaultHttpRequestWriterFactory.INSTANCE;
|
||||
this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
|
||||
DefaultHttpResponseParserFactory.INSTANCE;
|
||||
this.allocator = allocator != null ? allocator : HeapByteBufferAllocator.INSTANCE;
|
||||
}
|
||||
|
||||
public BridgeManagedNHttpClientConnectionFactory() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedNHttpClientConnection create(final IOSession iosession, final ConnectionConfig config) {
|
||||
final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
|
||||
CharsetDecoder chardecoder = null;
|
||||
CharsetEncoder charencoder = null;
|
||||
final Charset charset = config.getCharset();
|
||||
final CodingErrorAction malformedInputAction = config.getMalformedInputAction() != null
|
||||
? config.getMalformedInputAction()
|
||||
: CodingErrorAction.REPORT;
|
||||
final CodingErrorAction unmappableInputAction = config.getUnmappableInputAction() != null
|
||||
? config.getUnmappableInputAction()
|
||||
: CodingErrorAction.REPORT;
|
||||
if (charset != null) {
|
||||
chardecoder = charset.newDecoder();
|
||||
chardecoder.onMalformedInput(malformedInputAction);
|
||||
chardecoder.onUnmappableCharacter(unmappableInputAction);
|
||||
charencoder = charset.newEncoder();
|
||||
charencoder.onMalformedInput(malformedInputAction);
|
||||
charencoder.onUnmappableCharacter(unmappableInputAction);
|
||||
}
|
||||
|
||||
// 使用 bridge
|
||||
final ManagedNHttpClientConnection conn = new BridgeManagedNHttpClientConnectionImpl(id, this.log,
|
||||
this.headerlog,
|
||||
this.wirelog, iosession, config.getBufferSize(), config.getFragmentSizeHint(), this.allocator,
|
||||
chardecoder, charencoder, config.getMessageConstraints(), null, null, this.requestWriterFactory,
|
||||
this.responseParserFactory);
|
||||
iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
|
||||
return conn;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.apache.http.impl.nio.conn;
|
||||
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.config.MessageConstraints;
|
||||
import org.apache.http.entity.ContentLengthStrategy;
|
||||
import org.apache.http.nio.ContentEncoder;
|
||||
import org.apache.http.nio.NHttpMessageParserFactory;
|
||||
import org.apache.http.nio.NHttpMessageWriterFactory;
|
||||
import org.apache.http.nio.conn.ManagedNHttpClientConnection;
|
||||
import org.apache.http.nio.reactor.IOSession;
|
||||
import org.apache.http.nio.util.ByteBufferAllocator;
|
||||
|
||||
public class BridgeManagedNHttpClientConnectionImpl extends ManagedNHttpClientConnectionImpl
|
||||
implements ManagedNHttpClientConnection {
|
||||
|
||||
public BridgeManagedNHttpClientConnectionImpl(String id, Log log, Log headerlog, Log wirelog, IOSession iosession,
|
||||
int buffersize, int fragmentSizeHint, ByteBufferAllocator allocator, CharsetDecoder chardecoder,
|
||||
CharsetEncoder charencoder, MessageConstraints constraints, ContentLengthStrategy incomingContentStrategy,
|
||||
ContentLengthStrategy outgoingContentStrategy, NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
|
||||
NHttpMessageParserFactory<HttpResponse> responseParserFactory) {
|
||||
super(id, log, headerlog, wirelog, iosession, buffersize, fragmentSizeHint, allocator, chardecoder, charencoder,
|
||||
constraints, incomingContentStrategy, outgoingContentStrategy, requestWriterFactory,
|
||||
responseParserFactory);
|
||||
|
||||
}
|
||||
|
||||
public boolean isRequestNotSendComplete() {
|
||||
return super.hasBufferedOutput;
|
||||
}
|
||||
|
||||
public long getDataLengthTransferred() {
|
||||
return outTransportMetrics.getBytesTransferred();
|
||||
}
|
||||
|
||||
public ContentEncoder getContentEncoder() {
|
||||
return this.contentEncoder;
|
||||
}
|
||||
}
|
|
@ -14,6 +14,9 @@
|
|||
<aop:aspectj-autoproxy/>
|
||||
<context:component-scan base-package="com.educoder.bridge.*.*"/>
|
||||
|
||||
<context:property-placeholder location="classpath:config_${spring.profiles.active}.properties" />
|
||||
<import resource="classpath*:dataSource.xml" />
|
||||
|
||||
<!-- freemaker配置 -->
|
||||
<bean id="freemarkerConfig"
|
||||
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
|
||||
|
@ -38,7 +41,7 @@
|
|||
|
||||
<bean id="websshHandler" class="com.educoder.bridge.webssh.handler.WebsshHandler"/>
|
||||
|
||||
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||
<bean id="threadPoolTaskExecutor" class="com.educoder.bridge.game.thread.BridgeThreadPoolTaskExecutor">
|
||||
<property name="corePoolSize" value="400"/>
|
||||
<property name="maxPoolSize" value="400"/>
|
||||
<property name="queueCapacity" value="5000"/>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status
|
||||
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status.json
|
||||
simpileEducoderURL=https://testbdweb.educoder.net/myshixuns/code_runinng_message.json
|
||||
|
||||
workspace=/data/workspace
|
||||
|
||||
## webssh
|
||||
|
@ -7,7 +9,11 @@ webssh.serverUrl=https://10.9.81.28:6443
|
|||
webssh.userName=root
|
||||
webssh.passwd=123123
|
||||
|
||||
#the k8s server IP that can be accessed from internet
|
||||
|
||||
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
|
||||
websocket.addr=wss://testwebssh.educoder.net/ws
|
||||
|
||||
#the k8s server IP that can be accessed from internet
|
||||
k8s.serverUrl=10.9.81.28
|
||||
#to execute k8s cmds in slave node ,we have to provide the token
|
||||
k8s.token=726b127bcf34784b
|
||||
|
@ -19,32 +25,50 @@ maxRunningPodNum=20000
|
|||
defaultTimeLimit=90
|
||||
|
||||
# redis
|
||||
redisAddress=127.0.0.1
|
||||
redisAddress=192.168.56.101
|
||||
redisPort=6379
|
||||
redisAuth=
|
||||
|
||||
#测试版kubernetes用户名和密码
|
||||
k8sServer=127.0.0.1:8080
|
||||
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
|
||||
k8sServer=10.9.81.28:8080
|
||||
k8sUser=testk8s
|
||||
k8sPasswd=testk8s
|
||||
|
||||
#测试版资源总量
|
||||
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
|
||||
cpuAllocatable=4000
|
||||
memAllocatable=10000
|
||||
|
||||
#测试版dockerURL(主节点)
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
|
||||
dockerMaster=http://10.9.81.28:54243
|
||||
#测试版dockerURL(副节点)
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
|
||||
dockerDeputies=http://10.9.186.111:54243
|
||||
|
||||
#镜像仓库地址
|
||||
registry=10.9.105.90:5000
|
||||
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
|
||||
registry=10.9.164.118:5000
|
||||
|
||||
|
||||
#IP
|
||||
gitIP=10.9.73.116
|
||||
gitBackUpIP=10.9.73.116
|
||||
|
||||
#编译结果最大长度
|
||||
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
|
||||
outputSize=65535
|
||||
|
||||
#认证密钥
|
||||
secretKey=priEn3UwXfJs3PmyXnSG
|
||||
#\u8ba4\u8bc1\u5bc6\u94a5
|
||||
secretKey=priEn3UwXfJs3PmyXnSG
|
||||
|
||||
#GPU \u955c\u50cf
|
||||
gpuImage=ubuntu-nvidia
|
||||
|
||||
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
|
||||
gitUsername=edugit
|
||||
gitPassword=xinedugit#
|
||||
|
||||
# mysql
|
||||
jdbc.driver=com.mysql.jdbc.Driver
|
||||
jdbc.url=jdbc:mysql://192.168.56.101:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
|
||||
jdbc.username=root
|
||||
jdbc.password=123456
|
||||
|
||||
#novnc port
|
||||
vncPort=6901
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#Online
|
||||
educoderURL=https://shixun.educoder.net/api/myshixuns/training_task_status.json
|
||||
workspace=/data/workspace
|
||||
educoderURL=https://www.educoder.net/myshixuns/training_task_status
|
||||
simpileEducoderURL=https://www.educoder.net/myshixuns/code_runinng_message.json
|
||||
workspace=/data2/workspace
|
||||
|
||||
## webssh
|
||||
#webssh.configBakPath=/root/userYaml
|
||||
|
@ -9,7 +10,7 @@ webssh.serverUrl=https://10.9.184.140:6443
|
|||
webssh.userName=root
|
||||
webssh.passwd=123123
|
||||
|
||||
## 命令行连接时的websocket地址
|
||||
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
|
||||
websocket.addr=wss://webssh.educoder.net/ws
|
||||
|
||||
#online
|
||||
|
@ -29,35 +30,35 @@ redisAddress=127.0.0.1
|
|||
redisPort=6379
|
||||
redisAuth=
|
||||
|
||||
#正式版kubernetes用户名和密码
|
||||
#\u6b63\u5f0f\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
|
||||
k8sServer=127.0.0.1:8080
|
||||
k8sUser=testk8s
|
||||
k8sPasswd=testk8s
|
||||
|
||||
#正式版dockerURL(主节点)
|
||||
dockerMaster=http://10.9.184.140:4243
|
||||
#正式版dockerURL(副节点)
|
||||
dockerDeputies=http://10.9.105.90:4243;http://10.9.84.149:4243;http://10.9.46.46:4243;http://10.9.5.67:4243;http://10.9.144.249:4243;http://10.9.164.118:4243
|
||||
#\u6b63\u5f0f\u7248dockerURL(\u4e3b\u8282\u70b9)
|
||||
dockerMaster=http://10.9.5.67:4243
|
||||
#\u6b63\u5f0f\u7248dockerURL(\u526f\u8282\u70b9)
|
||||
dockerDeputies=http://10.9.164.118:4243;http://10.9.144.249:4243;http://10.9.46.46:4243
|
||||
|
||||
#镜像仓库地址
|
||||
registry=10.9.105.90:5000
|
||||
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
|
||||
registry=10.9.164.118:5000
|
||||
|
||||
#正式版k8s可分配资源
|
||||
#\u6b63\u5f0f\u7248k8s\u53ef\u5206\u914d\u8d44\u6e90
|
||||
cpuAllocatable=24000
|
||||
memAllocatable=46160
|
||||
|
||||
#IP
|
||||
#git \u7248\u672c\u5e93IP
|
||||
gitIP=10.9.62.218
|
||||
gitBackUpIP=10.9.62.218
|
||||
|
||||
#编译结果最大长度
|
||||
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
|
||||
outputSize=65535
|
||||
|
||||
#认证密钥
|
||||
#\u8ba4\u8bc1\u5bc6\u94a5
|
||||
secretKey=priEn3UwXfJs3PmyXnSG
|
||||
|
||||
#GPU 镜像
|
||||
#GPU \u955c\u50cf
|
||||
gpuImage=ubuntu-nvidia
|
||||
|
||||
#git用户名及密码
|
||||
gitUsername=edugit
|
||||
gitPassword=xinedugit#
|
||||
#novnc port
|
||||
vncPort=6901
|
|
@ -1,19 +1,20 @@
|
|||
educoderURL=https://testeduplus2.educoder.net/api/myshixuns/training_task_status.json
|
||||
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status.json
|
||||
simpileEducoderURL=https://testbdweb.educoder.net/myshixuns/code_runinng_message.json
|
||||
|
||||
workspace=/data/workspace
|
||||
|
||||
## webssh
|
||||
webssh.configBakPath=/root/userYaml
|
||||
webssh.serverUrl=https://10.9.63.225:6443
|
||||
webssh.serverUrl=https://10.9.81.28:6443
|
||||
webssh.userName=root
|
||||
webssh.passwd=123123
|
||||
|
||||
|
||||
## 命令行连接时的websocket地址
|
||||
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
|
||||
websocket.addr=wss://testwebssh.educoder.net/ws
|
||||
|
||||
#the k8s server IP that can be accessed from internet
|
||||
k8s.serverUrl=10.9.63.225
|
||||
k8s.serverUrl=127.0.0.1
|
||||
#to execute k8s cmds in slave node ,we have to provide the token
|
||||
k8s.token=726b127bcf34784b
|
||||
|
||||
|
@ -28,36 +29,47 @@ redisAddress=127.0.0.1
|
|||
redisPort=6379
|
||||
redisAuth=
|
||||
|
||||
#测试版kubernetes用户名和密码
|
||||
k8sServer=127.0.0.1:8080
|
||||
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
|
||||
k8sServer=10.9.81.28:8080
|
||||
k8sUser=testk8s
|
||||
k8sPasswd=testk8s
|
||||
|
||||
#测试版资源总量
|
||||
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
|
||||
cpuAllocatable=4000
|
||||
memAllocatable=10000
|
||||
|
||||
#测试版dockerURL(主节点)
|
||||
dockerMaster=http://10.9.63.225:54243
|
||||
#测试版dockerURL(副节点)
|
||||
dockerDeputies=http://10.9.29.180:54243
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
|
||||
dockerMaster=http://10.9.81.28:54243
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
|
||||
dockerDeputies=http://10.9.186.111:54243
|
||||
|
||||
#镜像仓库地址
|
||||
registry=10.9.105.90:5000
|
||||
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
|
||||
registry=10.9.164.118:5000
|
||||
|
||||
|
||||
#IP
|
||||
gitIP=10.9.54.50
|
||||
gitIP=10.9.73.116
|
||||
gitBackUpIP=10.9.73.116
|
||||
|
||||
#编译结果最大长度
|
||||
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
|
||||
outputSize=65535
|
||||
|
||||
#认证密钥
|
||||
#\u8ba4\u8bc1\u5bc6\u94a5
|
||||
secretKey=priEn3UwXfJs3PmyXnSG
|
||||
|
||||
#GPU 镜像
|
||||
#GPU \u955c\u50cf
|
||||
gpuImage=ubuntu-nvidia
|
||||
|
||||
#git用户名及密码
|
||||
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
|
||||
gitUsername=edugit
|
||||
gitPassword=xinedugit#
|
||||
gitPassword=xinedugit#
|
||||
|
||||
# mysql
|
||||
jdbc.driver=com.mysql.jdbc.Driver
|
||||
jdbc.url=jdbc:mysql://10.9.70.25:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
|
||||
jdbc.username=root
|
||||
jdbc.password=Trust_#%01
|
||||
|
||||
#novnc port
|
||||
vncPort=6901
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
educoderURL=https://testeduplus2.educoder.net/myshixuns/training_task_status.json
|
||||
simpileEducoderURL=https://testeduplus2.educoder.net/myshixuns/code_runinng_message.json
|
||||
|
||||
workspace=/data/workspace
|
||||
|
||||
## webssh
|
||||
webssh.configBakPath=/root/userYaml
|
||||
webssh.serverUrl=https://10.9.81.28:6443
|
||||
webssh.userName=root
|
||||
webssh.passwd=123123
|
||||
|
||||
|
||||
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
|
||||
websocket.addr=wss://testwebssh2.educoder.net/ws
|
||||
|
||||
#the k8s server IP that can be accessed from internet
|
||||
k8s.serverUrl=127.0.0.1
|
||||
#to execute k8s cmds in slave node ,we have to provide the token
|
||||
k8s.token=726b127bcf34784b
|
||||
|
||||
#limit of running pod number
|
||||
maxRunningPodNum=20000
|
||||
|
||||
# defaultTimeLimit of executing time in a pod.
|
||||
defaultTimeLimit=90
|
||||
|
||||
# redis
|
||||
redisAddress=127.0.0.1
|
||||
redisPort=6379
|
||||
redisAuth=
|
||||
|
||||
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
|
||||
k8sServer=10.9.81.28:8080
|
||||
k8sUser=testk8s
|
||||
k8sPasswd=testk8s
|
||||
|
||||
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
|
||||
cpuAllocatable=4000
|
||||
memAllocatable=10000
|
||||
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
|
||||
dockerMaster=http://10.9.81.28:54243
|
||||
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
|
||||
dockerDeputies=http://10.9.186.111:54243
|
||||
|
||||
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
|
||||
registry=10.9.164.118:5000
|
||||
|
||||
|
||||
#IP
|
||||
gitIP=10.9.73.116
|
||||
gitBackUpIP=10.9.73.116
|
||||
|
||||
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
|
||||
outputSize=65535
|
||||
|
||||
#\u8ba4\u8bc1\u5bc6\u94a5
|
||||
secretKey=priEn3UwXfJs3PmyXnSG
|
||||
|
||||
#GPU \u955c\u50cf
|
||||
gpuImage=ubuntu-nvidia
|
||||
|
||||
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
|
||||
gitUsername=edugit
|
||||
gitPassword=xinedugit#
|
||||
|
||||
# mysql
|
||||
jdbc.driver=com.mysql.jdbc.Driver
|
||||
jdbc.url=jdbc:mysql://10.9.70.25:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
|
||||
jdbc.username=root
|
||||
jdbc.password=Trust_#%01
|
||||
|
||||
#novnc port
|
||||
vncPort=6901
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:websocket="http://www.springframework.org/schema/websocket"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
|
||||
|
||||
<bean id="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
|
||||
<property name="driverClassName" value="${jdbc.driver}" />
|
||||
<property name="url" value="${jdbc.url}" />
|
||||
<property name="username" value="${jdbc.username}" />
|
||||
<property name="password" value="${jdbc.password}" />
|
||||
<property name="initialSize" value="10"></property>
|
||||
<property name="maxActive" value="20"></property>
|
||||
<property name="minIdle" value="10"></property>
|
||||
</bean>
|
||||
|
||||
<bean id="sqlSessionFactory"
|
||||
class="org.mybatis.spring.SqlSessionFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"></property>
|
||||
<property name="typeAliasesPackage"
|
||||
value="com.educoder.bridge.**.model"></property>
|
||||
<property name="mapperLocations"
|
||||
value="classpath*:mapper/*/*Mapper.xml"></property>
|
||||
<property name="plugins">
|
||||
<array>
|
||||
<bean class="com.github.pagehelper.PageInterceptor">
|
||||
<!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 -->
|
||||
<property name="properties">
|
||||
<value>
|
||||
helperDialect=mysql
|
||||
reasonable=true
|
||||
supportMethodsArguments=true
|
||||
params=count=countSql
|
||||
autoRuntimeDialect=true
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
</array>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
|
||||
<property name="sqlSessionFactoryBeanName"
|
||||
value="sqlSessionFactory"></property>
|
||||
<property name="basePackage"
|
||||
value="com.educoder.bridge.**.dao"></property>
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,121 @@
|
|||
#!/bin/bash
|
||||
###日志函数开始
|
||||
maxLogNum=10
|
||||
logNum=1
|
||||
eduLog() {
|
||||
if [ $logNum -gt $maxLogNum ]
|
||||
then
|
||||
return
|
||||
else
|
||||
logNum=$[logNum+1]
|
||||
fi
|
||||
|
||||
echo "educoder:"$1
|
||||
}
|
||||
###日志函数结束
|
||||
|
||||
###获取输出函数开始
|
||||
getLogFile(){
|
||||
if [ -z $evaLogFile ]
|
||||
then
|
||||
evaLogFile=$(cd `dirname $0`; pwd)"/eva.log";
|
||||
fi
|
||||
}
|
||||
|
||||
clearLogFile(){
|
||||
getLogFile
|
||||
rm -rf ${evaLogFile}
|
||||
}
|
||||
|
||||
getPidnum(){
|
||||
evaPidnum=0
|
||||
pids=$(ps -ef | grep "$executeCommand" | grep -v "grep $executeCommand"| awk '{print $2}')
|
||||
for pid in $pids
|
||||
do
|
||||
let evaPidnum=evaPidnum+1
|
||||
done
|
||||
}
|
||||
|
||||
readLine(){
|
||||
linenumThisTime=0
|
||||
readedLine=-1
|
||||
while read LINE
|
||||
do
|
||||
let linenumThisTime=linenumThisTime+1
|
||||
if [ $linenumThisTime -lt $linenum ]
|
||||
then
|
||||
continue
|
||||
else
|
||||
curline="$LINE"
|
||||
readedLine=0
|
||||
break
|
||||
fi
|
||||
done <${evaLogFile}
|
||||
}
|
||||
|
||||
processLine() {
|
||||
if [ ! $readedLine -eq 0 ];then
|
||||
sleep 1s
|
||||
else
|
||||
match=$(echo $curline |grep -e "educoder:.*")
|
||||
if [ ${#match} == 0 ]
|
||||
then
|
||||
alloutput="$alloutput""$curline""\n"
|
||||
else
|
||||
echo $curline
|
||||
fi
|
||||
let linenum=linenum+1
|
||||
fi
|
||||
}
|
||||
|
||||
getResult() {
|
||||
linenum=1
|
||||
alloutput=""
|
||||
getPidnum
|
||||
#eduLog "等待业务程序..。"$evaPidnum
|
||||
while :
|
||||
do
|
||||
if [[ $evaPidnum -eq 0 ]]
|
||||
then
|
||||
if [[ -f ${evaLogFile} && (`cat ${evaLogFile} |wc -l` -gt 0) ]]
|
||||
then
|
||||
break
|
||||
else
|
||||
sleep 1s
|
||||
#eduLog "继续等待业务程序..."
|
||||
getPidnum
|
||||
fi
|
||||
else
|
||||
if [[ -f ${evaLogFile} && (`cat ${evaLogFile} |wc -l` -gt 0) ]]
|
||||
then
|
||||
break
|
||||
else
|
||||
sleep 1s
|
||||
#eduLog "继续等待业务程序..."
|
||||
getPidnum
|
||||
fi
|
||||
fi
|
||||
done
|
||||
#eduLog "业务程序执行中..."$evaPidnum
|
||||
getPidnum
|
||||
while [[ $evaPidnum -eq 1 ]]
|
||||
do
|
||||
#eduLog "业务程序继续执行中..."$evaPidnum
|
||||
readLine
|
||||
processLine
|
||||
sleep 1s
|
||||
getPidnum
|
||||
done
|
||||
#eduLog "业务程序完成,读取剩余日志..."$evaPidnum
|
||||
readLine
|
||||
while [[ $readedLine -eq 0 ]]
|
||||
do
|
||||
processLine
|
||||
readLine
|
||||
done
|
||||
result=$(echo -ne "$alloutput"|base64)
|
||||
}
|
||||
###获取输出函数结束
|
||||
|
||||
clearLogFile
|
||||
source $(cd `dirname $0`; pwd)"/evaluate.sh" $1 $2
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<encoder>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>DEBUG</level>
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<configuration scan="true" scanPeriod="10 minutes">
|
||||
<property name="log_path" value="${catalina.home}/logs/"/>
|
||||
|
||||
<!-- 日志按天生成 -->
|
||||
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log_path}bridge.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_path}bridge.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
</rollingPolicy>
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<configuration scan="true" scanPeriod="1 minutes">
|
||||
<property name="log_path" value="${catalina.home}/logs/"/>
|
||||
|
||||
<!-- 日志按天生成 -->
|
||||
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log_path}bridge.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
|
||||
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_path}bridge.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
</rollingPolicy>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue