OCT
REM: 1. 增加设备节点管理控制器接口 2. 完成获取节点链接状态信息接口 3. 增加获取处置设备能力接口 4. 增加处置设备管理数据库相关接口 5. 增加添加、删除处置设备功能 6. 增加设备链接状态定时更新功能 7. 增加相关单元测试用例
This commit is contained in:
parent
be4bd35ce4
commit
e7843898b7
|
@ -73,7 +73,7 @@ public class ConstValue {
|
||||||
public static final int LOCKED = 1;
|
public static final int LOCKED = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DisposeDeviceCapacity {
|
public enum DeviceCapacity {
|
||||||
CLEANUP (0, "清洗能力"),
|
CLEANUP (0, "清洗能力"),
|
||||||
HIDEPEND (1, "高防能力"),
|
HIDEPEND (1, "高防能力"),
|
||||||
BLACKHOOL (2, "黑洞能力"),
|
BLACKHOOL (2, "黑洞能力"),
|
||||||
|
@ -82,7 +82,7 @@ public class ConstValue {
|
||||||
private int code;
|
private int code;
|
||||||
private String readme;
|
private String readme;
|
||||||
|
|
||||||
DisposeDeviceCapacity(int code, String readme) {
|
DeviceCapacity(int code, String readme) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.readme = readme;
|
this.readme = readme;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,14 @@ public class ConstValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IPAddrType{
|
public enum IPAddrType{
|
||||||
IPV4_TYPE, IPV6_TYPE,
|
IPV4_TYPE, IPV6_TYPE;
|
||||||
|
|
||||||
|
public static IPAddrType getIpAddrType(String ipAddr) {
|
||||||
|
if(ipAddr.contains(":")) {
|
||||||
|
return IPV6_TYPE;
|
||||||
|
} else {
|
||||||
|
return IPV4_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.dispose.common;
|
package com.dispose.common;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 错误码常量定义
|
* 错误码常量定义
|
||||||
*/
|
*/
|
||||||
public enum ErrorCode {
|
public enum ErrorCode {
|
||||||
ERR_OK (0, "成功"),
|
ERR_OK (0, "成功"),
|
||||||
|
@ -27,6 +27,7 @@ public enum ErrorCode {
|
||||||
ERR_DEVICEEXISTS (20, "设备已经存在"),
|
ERR_DEVICEEXISTS (20, "设备已经存在"),
|
||||||
ERR_PARAMEXCEPTION (21, "参数异常"),
|
ERR_PARAMEXCEPTION (21, "参数异常"),
|
||||||
ERR_VERSION (23, "协议版本不兼容,请升级系统"),
|
ERR_VERSION (23, "协议版本不兼容,请升级系统"),
|
||||||
|
ERR_NOSUCHTYPE (24, "没有这个类型的处置设备"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private int errno;
|
private int errno;
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.dispose.controller;
|
package com.dispose.controller;
|
||||||
|
|
||||||
|
import com.dispose.common.ConstValue;
|
||||||
import com.dispose.common.ErrorCode;
|
import com.dispose.common.ErrorCode;
|
||||||
|
import com.dispose.mapper.DisposeDeviceMapper;
|
||||||
import com.dispose.pojo.dto.ProtocolReqDTO;
|
import com.dispose.pojo.dto.ProtocolReqDTO;
|
||||||
import com.dispose.pojo.dto.ProtocolRespDTO;
|
import com.dispose.pojo.dto.ProtocolRespDTO;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
import com.dispose.pojo.vo.common.IDArrayReq;
|
import com.dispose.pojo.vo.common.IDArrayReq;
|
||||||
import com.dispose.pojo.vo.information.LinkStatusRsp;
|
import com.dispose.pojo.vo.information.LinkStatusRsp;
|
||||||
import com.dispose.service.AsyncService;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
|
@ -20,7 +22,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -29,18 +30,18 @@ import java.util.List;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Api(value = "抗DDoS处置平台能力节点信息接口", tags = "抗DDoS处置平台能力节点信息接口")
|
@Api(value = "抗DDoS处置平台能力节点信息接口", tags = "抗DDoS处置平台能力节点信息接口")
|
||||||
@Component
|
@Component
|
||||||
public class DisposeNodeController {
|
public class DisposeNodeInfoController {
|
||||||
@Resource
|
|
||||||
private AsyncService asyncService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DisposeDeviceMapper disposeDeviceMapper;
|
||||||
|
|
||||||
@PostMapping("/linkstatus")
|
@PostMapping("/linkstatus")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ApiOperation("链接状态")
|
@ApiOperation("链接状态")
|
||||||
@Builder
|
@Builder
|
||||||
public ProtocolRespDTO userLogin(@RequestBody ProtocolReqDTO mr)
|
public ProtocolRespDTO getLinkStatus(@RequestBody ProtocolReqDTO mr)
|
||||||
throws JsonProcessingException {
|
throws JsonProcessingException {
|
||||||
ErrorCode err = mr.verifyRequest();
|
ErrorCode err = mr.verifyRequest();
|
||||||
|
|
||||||
|
@ -52,42 +53,38 @@ public class DisposeNodeController {
|
||||||
List<LinkStatusRsp> rspInfo = new ArrayList<>();
|
List<LinkStatusRsp> rspInfo = new ArrayList<>();
|
||||||
|
|
||||||
if(reqInfo.getId().length == 0) {
|
if(reqInfo.getId().length == 0) {
|
||||||
|
List<DisposeDevice> devs = disposeDeviceMapper.selectAll();
|
||||||
|
|
||||||
|
if(devs != null && devs.size() > 0) {
|
||||||
|
devs.forEach(v->{
|
||||||
|
LinkStatusRsp linkStat = LinkStatusRsp.builder().online(v.getLinkStatus()).build();
|
||||||
|
|
||||||
|
linkStat.setStatus(ErrorCode.ERR_OK.getCode());
|
||||||
|
linkStat.setMessage(ErrorCode.ERR_OK.getMsg());
|
||||||
|
|
||||||
|
rspInfo.add(linkStat);
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (String v : reqInfo.getId()) {
|
for (String v : reqInfo.getId()) {
|
||||||
LinkStatusRsp linkStat = LinkStatusRsp.builder()
|
DisposeDevice dev = disposeDeviceMapper.getDeviceById(Long.valueOf(v));
|
||||||
.id(v)
|
LinkStatusRsp linkStat;
|
||||||
.online(1)
|
if(dev != null && dev.getId().equals(Long.valueOf(v))) {
|
||||||
.build();
|
linkStat = LinkStatusRsp.builder().online(dev.getLinkStatus()).build();
|
||||||
|
linkStat.setId(dev.getId().toString());
|
||||||
|
err = ErrorCode.ERR_OK;
|
||||||
|
} else {
|
||||||
|
linkStat = LinkStatusRsp.builder().online(0).build();
|
||||||
|
err = ErrorCode.ERR_NOSUCHDEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkStat.setStatus(err.getCode());
|
||||||
|
linkStat.setMessage(err.getMsg());
|
||||||
|
|
||||||
rspInfo.add(linkStat);
|
rspInfo.add(linkStat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(reqInfo == null || reqInfo.length == 0) {
|
|
||||||
// //return ProtocolRespDTO.result(ErrorCode.ERR_PARAMS);
|
|
||||||
// } else {
|
|
||||||
// for(String v:reqInfo) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MReturnType<ErrorCode, String> ret = userAccountService.loginService(reqInfo.getUserName(), reqInfo.getPassword());
|
|
||||||
//
|
|
||||||
// if(ret.getFirstParam() != ErrorCode.ERR_OK) {
|
|
||||||
// return ProtocolRespDTO.result(ret.getFirstParam());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// LoginRsp rspInfo = LoginRsp.builder()
|
|
||||||
// .userName(reqInfo.getUserName())
|
|
||||||
// .token(ret.getSecondParam())
|
|
||||||
// .logTime(System.currentTimeMillis())
|
|
||||||
// .expireTime(System.currentTimeMillis() + ConstValue.GlobalConfigure.TOKEN_EXPIRED_TIME_MS)
|
|
||||||
// .build();
|
|
||||||
|
|
||||||
return ProtocolRespDTO.result(ErrorCode.ERR_OK, rspInfo);
|
return ProtocolRespDTO.result(ErrorCode.ERR_OK, rspInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.dispose.controller;
|
||||||
|
|
||||||
|
import com.dispose.common.ErrorCode;
|
||||||
|
import com.dispose.pojo.dto.ProtocolReqDTO;
|
||||||
|
import com.dispose.pojo.dto.ProtocolRespDTO;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.MReturnType;
|
||||||
|
import com.dispose.pojo.vo.common.IDReturnStatus;
|
||||||
|
import com.dispose.pojo.vo.device.AddNodeReq;
|
||||||
|
import com.dispose.pojo.vo.device.AddNodeRetData;
|
||||||
|
import com.dispose.pojo.vo.device.AddNodeRsp;
|
||||||
|
import com.dispose.service.DisposeNodeManager;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping(value = "/manager")
|
||||||
|
@Slf4j
|
||||||
|
@Api(value = "抗DDoS处置平台能力节点管理接口", tags = "抗DDoS处置平台能力节点管理接口")
|
||||||
|
@Component
|
||||||
|
public class DisposeNodeManagerController {
|
||||||
|
@Resource
|
||||||
|
private DisposeNodeManager disposeNodeManager;
|
||||||
|
|
||||||
|
@PutMapping("/device")
|
||||||
|
@ResponseBody
|
||||||
|
@ApiOperation("添加处置能力节点")
|
||||||
|
@Builder
|
||||||
|
public ProtocolRespDTO addDisposeNode(@RequestBody ProtocolReqDTO mr)
|
||||||
|
throws JsonProcessingException {
|
||||||
|
|
||||||
|
ErrorCode err = mr.verifyRequest();
|
||||||
|
|
||||||
|
if(err != ErrorCode.ERR_OK) {
|
||||||
|
return ProtocolRespDTO.result(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddNodeReq reqInfo = mr.getRequestObject(AddNodeReq.class);
|
||||||
|
|
||||||
|
AddNodeRsp rspInfo = new AddNodeRsp();
|
||||||
|
|
||||||
|
reqInfo.getItems().forEach(v-> {
|
||||||
|
DisposeDevice dev = DisposeDevice.builder()
|
||||||
|
.id(Long.valueOf(v.getId()))
|
||||||
|
.type(v.getType())
|
||||||
|
.name(v.getName())
|
||||||
|
.ipAddr(v.getIpAddr())
|
||||||
|
.areaCode(v.getAreaCode())
|
||||||
|
.manufacturer(v.getManufacturer())
|
||||||
|
.model(v.getModel())
|
||||||
|
.version(v.getVersion())
|
||||||
|
.build();
|
||||||
|
MReturnType<ErrorCode, String> ret;
|
||||||
|
try {
|
||||||
|
ret = disposeNodeManager.addNewDisposeDevice(dev);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ret = new MReturnType<>(ErrorCode.ERR_NOSUCHDEVICE, v.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
AddNodeRetData retStatus = new AddNodeRetData();
|
||||||
|
retStatus.setIpAddr(v.getIpAddr());
|
||||||
|
retStatus.setDevId(ret.getSecondParam());
|
||||||
|
retStatus.setStatus(ret.getFirstParam().getCode());
|
||||||
|
retStatus.setMessage(ret.getFirstParam().getMsg());
|
||||||
|
rspInfo.getResult().add(retStatus);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ProtocolRespDTO.result(ErrorCode.ERR_OK, rspInfo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ package com.dispose.dispose;
|
||||||
|
|
||||||
import com.dispose.Interceptor.SoapPasswordCallbackHandler;
|
import com.dispose.Interceptor.SoapPasswordCallbackHandler;
|
||||||
import com.dispose.common.ConstValue;
|
import com.dispose.common.ConstValue;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.DisposeDeviceCapacity;
|
||||||
import com.dptech.dispose.AbnormalFlowCleaningServicePortType;
|
import com.dptech.dispose.AbnormalFlowCleaningServicePortType;
|
||||||
import com.dptech.dispose.ArrayOfDetectionObjectDataForService;
|
import com.dptech.dispose.ArrayOfDetectionObjectDataForService;
|
||||||
import com.dptech.dispose.ArrayOfProtectionObjectDataForService;
|
import com.dptech.dispose.ArrayOfProtectionObjectDataForService;
|
||||||
|
@ -12,12 +14,52 @@ import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
|
||||||
import org.apache.wss4j.dom.WSConstants;
|
import org.apache.wss4j.dom.WSConstants;
|
||||||
import org.apache.wss4j.dom.handler.WSHandlerConstants;
|
import org.apache.wss4j.dom.handler.WSHandlerConstants;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class DPTechImpl implements DisposeEntryManager {
|
public class DPTechImpl implements DisposeEntryManager {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DisposeDeviceCapacity> getDeviceCapacity() {
|
||||||
|
List<DisposeDeviceCapacity> capList = new ArrayList<>();
|
||||||
|
|
||||||
|
String devs = cleanTypePort.getAllDetectDevices();
|
||||||
|
|
||||||
|
if(devs != null && devs.length() > 0) {
|
||||||
|
capList.add(DisposeDeviceCapacity.builder()
|
||||||
|
.capacity(ConstValue.DeviceCapacity.DETECIVE.getCode())
|
||||||
|
.tolFlowCapacity(0)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
devs = cleanTypePort.getAllProtectDevices();
|
||||||
|
|
||||||
|
if(devs != null && devs.length() > 0) {
|
||||||
|
List<String> proIPv4 = new ArrayList<>();
|
||||||
|
List<String> proIPv6 = new ArrayList<>();
|
||||||
|
|
||||||
|
ArrayOfProtectionObjectDataForService objs = cleanTypePort.getAllProtectionObjectFromUMC();
|
||||||
|
objs.getProtectionObjectDataForService().forEach(v->{
|
||||||
|
String ipSeg = v.getIpSegment().getValue();
|
||||||
|
if(v.getIpType() == 0 && ipSeg.length() > 0) {
|
||||||
|
proIPv4.addAll(Arrays.asList(ipSeg.replaceAll("\\d{1,}_", "")
|
||||||
|
.split(",")));
|
||||||
|
} else if(v.getIpType() == 1 && ipSeg.length() > 0) {
|
||||||
|
proIPv6.addAll(Arrays.asList(ipSeg.replaceAll("\\d{1,}_", "")
|
||||||
|
.split(",")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
capList.add(DisposeDeviceCapacity.builder()
|
||||||
|
.capacity(ConstValue.DeviceCapacity.CLEANUP.getCode())
|
||||||
|
.tolFlowCapacity(0)
|
||||||
|
.ProtectIpV4(proIPv4.toArray(new String[0]))
|
||||||
|
.ProtectIpV6(proIPv6.toArray(new String[0]))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
return capList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDeviceLinkStatus() {
|
public boolean getDeviceLinkStatus() {
|
||||||
List<ArrayOfProtectionObjectDataForService> objs = getAllProtectionObject();
|
List<ArrayOfProtectionObjectDataForService> objs = getAllProtectionObject();
|
||||||
|
@ -32,14 +74,14 @@ public class DPTechImpl implements DisposeEntryManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> List<T> getAllDetectionObject() {
|
public <T> T getAllDetectionObject() {
|
||||||
return (List<T>) cleanTypePort.getAllDetectionObjectFromUMC().getDetectionObjectDataForService();
|
return (T) cleanTypePort.getAllDetectionObjectFromUMC().getDetectionObjectDataForService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> List<T> getAllProtectionObject() {
|
public <T> T getAllProtectionObject() {
|
||||||
return (List<T>) cleanTypePort.getAllProtectionObjectFromUMC().getProtectionObjectDataForService();
|
return (T) cleanTypePort.getAllProtectionObjectFromUMC().getProtectionObjectDataForService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String GetDetectionObjectDeviceJson() throws JsonProcessingException {
|
public String GetDetectionObjectDeviceJson() throws JsonProcessingException {
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
package com.dispose.dispose;
|
package com.dispose.dispose;
|
||||||
|
|
||||||
//import com.dptech.NtcRequestResultInfo;
|
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.DisposeDeviceCapacity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface DisposeEntryManager {
|
public interface DisposeEntryManager {
|
||||||
int runDispose(String ip);
|
int runDispose(String ip);
|
||||||
|
|
||||||
<T> List<T> getAllDetectionObject();
|
<T> T getAllDetectionObject();
|
||||||
|
|
||||||
<T> List<T> getAllProtectionObject();
|
<T> T getAllProtectionObject();
|
||||||
|
|
||||||
|
List<DisposeDeviceCapacity> getDeviceCapacity();
|
||||||
|
|
||||||
String getDetectionDevices();
|
String getDetectionDevices();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.dispose.mapper;
|
||||||
|
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import tk.mybatis.mapper.common.IdsMapper;
|
||||||
|
import tk.mybatis.mapper.common.Mapper;
|
||||||
|
import tk.mybatis.mapper.common.MySqlMapper;
|
||||||
|
|
||||||
|
public interface DisposeDeviceMapper extends Mapper<DisposeDevice>,
|
||||||
|
IdsMapper<DisposeDevice>, MySqlMapper<DisposeDevice> {
|
||||||
|
void addNewDisposeDevice(DisposeDevice dev);
|
||||||
|
int isDeviceExistsByIp(String ipAddr);
|
||||||
|
int isDeviceExistsById(Long id);
|
||||||
|
|
||||||
|
DisposeDevice getDeviceByIp(String ipAddr);
|
||||||
|
DisposeDevice getDeviceById(Long id);
|
||||||
|
|
||||||
|
void delDisposeDeviceByIp(String ipAddr);
|
||||||
|
void delDisposeDeviceByIp(Long id);
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package com.dispose.pojo.entity;
|
||||||
|
|
||||||
|
import com.dispose.pojo.po.DisposeDeviceCapacity;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.*;
|
||||||
|
import tk.mybatis.mapper.annotation.NameStyle;
|
||||||
|
import tk.mybatis.mapper.code.Style;
|
||||||
|
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
@Table(name = "dispose_device")
|
||||||
|
@NameStyle(Style.normal)
|
||||||
|
public class DisposeDevice implements Serializable {
|
||||||
|
/**
|
||||||
|
* The constant serialVersionUID.
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备唯一标识符
|
||||||
|
*/
|
||||||
|
@Id
|
||||||
|
//@KeySql(useGeneratedKeys = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IP地址, IPv4/IPv6
|
||||||
|
*/
|
||||||
|
private String ipAddr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 能力节点类型,能力节点类型,0:迪普UMC平台,1:浩瀚设备
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Area code.
|
||||||
|
*/
|
||||||
|
private Integer areaCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产厂商
|
||||||
|
*/
|
||||||
|
private String manufacturer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 型号
|
||||||
|
*/
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 软件版本
|
||||||
|
*/
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String readme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态,0:正常, 1:删除
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链路状态,0:断开连接, 1:正常
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
|
private Integer linkStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 能力设备支持的能力列表
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
|
private List<DisposeDeviceCapacity> devCaps;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.dispose.pojo.po;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class DisposeDeviceCapacity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0:清洗 1:高防 2:黑洞 3: 检测
|
||||||
|
*/
|
||||||
|
private Integer capacity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处置设备储备能力(MB)
|
||||||
|
*/
|
||||||
|
private Integer tolFlowCapacity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防护IPv4对象
|
||||||
|
*/
|
||||||
|
private String[] ProtectIpV4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防护IPv6对象
|
||||||
|
*/
|
||||||
|
private String[] ProtectIpV6;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.dispose.pojo.po;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class NewNodeInfo {
|
||||||
|
private String id;
|
||||||
|
private int type;
|
||||||
|
private String ipAddr;
|
||||||
|
private int areaCode;
|
||||||
|
@Nullable
|
||||||
|
private String name;
|
||||||
|
@Nullable
|
||||||
|
private String manufacturer;
|
||||||
|
@Nullable
|
||||||
|
private String model;
|
||||||
|
@Nullable
|
||||||
|
private String version;
|
||||||
|
@Nullable
|
||||||
|
private String readme;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.dispose.pojo.vo.common;
|
||||||
|
|
||||||
|
import com.dispose.pojo.po.ReturnStatus;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@JsonPropertyOrder({"id", "devId", "status", "message"})
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class IDReturnStatus extends ReturnStatus {
|
||||||
|
private String id;
|
||||||
|
private String devId;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.dispose.pojo.vo.device;
|
||||||
|
|
||||||
|
import com.dispose.pojo.po.NewNodeInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class AddNodeReq {
|
||||||
|
private List<NewNodeInfo> items;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.dispose.pojo.vo.device;
|
||||||
|
|
||||||
|
import com.dispose.pojo.vo.common.IDReturnStatus;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@JsonPropertyOrder({"id", "ipAddr", "devId", "status", "message"})
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class AddNodeRetData extends IDReturnStatus {
|
||||||
|
private String ipAddr;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.dispose.pojo.vo.device;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class AddNodeRsp {
|
||||||
|
List<AddNodeRetData> result;
|
||||||
|
|
||||||
|
public AddNodeRsp() {
|
||||||
|
this.result = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.dispose.pojo.vo.information;
|
package com.dispose.pojo.vo.information;
|
||||||
|
|
||||||
import com.dispose.pojo.po.ReturnStatus;
|
import com.dispose.pojo.po.ReturnStatus;
|
||||||
|
import com.dispose.pojo.vo.common.IDReturnStatus;
|
||||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
@ -9,8 +10,7 @@ import lombok.*;
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@JsonPropertyOrder({"id", "online", "status", "message"})
|
@JsonPropertyOrder({"id", "devId", "online", "status", "message"})
|
||||||
public class LinkStatusRsp extends ReturnStatus {
|
public class LinkStatusRsp extends IDReturnStatus {
|
||||||
private String id;
|
|
||||||
private int online;
|
private int online;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package com.dispose.service;
|
|
||||||
|
|
||||||
import com.dispose.common.ConstValue;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public interface AsyncService {
|
|
||||||
CompletableFuture<Boolean> getDisposeDeviceLinkStatus(ConstValue.DisposeDeviceType deviceType, String ip, ConstValue.IPAddrType ipType);
|
|
||||||
CompletableFuture<Boolean> getDisposeDeviceLinkStatus(ConstValue.DisposeDeviceType deviceType, String ip);
|
|
||||||
}
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.dispose.service;
|
||||||
|
|
||||||
|
import com.dispose.common.ErrorCode;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.MReturnType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DisposeNodeManager {
|
||||||
|
MReturnType<ErrorCode, String> addNewDisposeDevice(DisposeDevice dev);
|
||||||
|
|
||||||
|
ErrorCode delDisposeDeviceByIp(String ipAddr);
|
||||||
|
List<DisposeDevice> getAllDisposeDevice();
|
||||||
|
DisposeDevice getDisposeDevice(String ipAddr);
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
package com.dispose.service.impl;
|
|
||||||
|
|
||||||
import com.dispose.common.ConstValue;
|
|
||||||
import com.dispose.dispose.DeviceRouter;
|
|
||||||
import com.dispose.dispose.DisposeEntryManager;
|
|
||||||
import com.dispose.service.AsyncService;
|
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class AsyncServiceImpl implements AsyncService {
|
|
||||||
|
|
||||||
@Async("bizExecutor")
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<Boolean> getDisposeDeviceLinkStatus(
|
|
||||||
ConstValue.DisposeDeviceType deviceType,
|
|
||||||
String ip,
|
|
||||||
ConstValue.IPAddrType ipType) {
|
|
||||||
|
|
||||||
DisposeEntryManager dp = DeviceRouter.deviceRouterFactory(deviceType.getCode(), ip, ipType);
|
|
||||||
|
|
||||||
return CompletableFuture.completedFuture(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Async("bizExecutor")
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<Boolean> getDisposeDeviceLinkStatus(
|
|
||||||
ConstValue.DisposeDeviceType deviceType,
|
|
||||||
String ip) {
|
|
||||||
|
|
||||||
return getDisposeDeviceLinkStatus(deviceType, ip, ConstValue.IPAddrType.IPV4_TYPE);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.dispose.service.impl;
|
||||||
|
|
||||||
|
import com.dispose.common.ConstValue;
|
||||||
|
import com.dispose.common.ErrorCode;
|
||||||
|
import com.dispose.dispose.DeviceRouter;
|
||||||
|
import com.dispose.dispose.DisposeEntryManager;
|
||||||
|
import com.dispose.mapper.DisposeDeviceMapper;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.MReturnType;
|
||||||
|
import com.dispose.service.DisposeNodeManager;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DisposeNodeManagerImpl implements DisposeNodeManager {
|
||||||
|
@Resource
|
||||||
|
private DisposeDeviceMapper disposeDeviceMapper;
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, DisposeDevice> disposeDevMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorCode delDisposeDeviceByIp(String ipAddr) {
|
||||||
|
DisposeEntryManager dp;
|
||||||
|
|
||||||
|
if(disposeDeviceMapper.isDeviceExistsByIp(ipAddr) == 0
|
||||||
|
|| !disposeDevMap.containsKey(ipAddr)) {
|
||||||
|
return ErrorCode.ERR_NOSUCHDEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposeDevice dev = disposeDevMap.get(ipAddr);
|
||||||
|
|
||||||
|
try {
|
||||||
|
dp = DeviceRouter.deviceRouterFactory(dev.getType(), ipAddr, ConstValue.IPAddrType.getIpAddrType(ipAddr));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return ErrorCode.ERR_NOSUCHDEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dp == null) {
|
||||||
|
return ErrorCode.ERR_NOSUCHTYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
disposeDeviceMapper.delDisposeDeviceByIp(ipAddr);
|
||||||
|
disposeDevMap.remove(ipAddr);
|
||||||
|
|
||||||
|
return ErrorCode.ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MReturnType<ErrorCode, String> addNewDisposeDevice(DisposeDevice dev) {
|
||||||
|
DisposeEntryManager dp;
|
||||||
|
|
||||||
|
try {
|
||||||
|
dp = DeviceRouter.deviceRouterFactory(dev.getType(),
|
||||||
|
dev.getIpAddr(), ConstValue.IPAddrType.getIpAddrType(dev.getIpAddr()));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return new MReturnType<>(ErrorCode.ERR_NOSUCHDEVICE, dev.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dp == null) {
|
||||||
|
return new MReturnType<>(ErrorCode.ERR_NOSUCHTYPE, dev.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disposeDeviceMapper.isDeviceExistsByIp(dev.getIpAddr()) > 0) {
|
||||||
|
return new MReturnType<>(ErrorCode.ERR_DEVICEEXISTS, dev.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!dp.getDeviceLinkStatus()) {
|
||||||
|
return new MReturnType<>(ErrorCode.ERR_NOSUCHDEVICE, dev.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dev.getDevCaps() == null) {
|
||||||
|
dev.setDevCaps(dp.getDeviceCapacity());
|
||||||
|
} else {
|
||||||
|
dev.getDevCaps().addAll(dp.getDeviceCapacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
disposeDeviceMapper.addNewDisposeDevice(dev);
|
||||||
|
|
||||||
|
disposeDevMap.put(dev.getIpAddr(), dev);
|
||||||
|
return new MReturnType<>(ErrorCode.ERR_OK, dev.getIpAddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DisposeDevice> getAllDisposeDevice() {
|
||||||
|
return new ArrayList<>(disposeDevMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisposeDevice getDisposeDevice(String ipAddr) {
|
||||||
|
return disposeDevMap.get(ipAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean isDisposeDeviceExists(String ipAddr) {
|
||||||
|
return disposeDevMap.containsKey(ipAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisposeDeviceToCache(DisposeDevice dev) {
|
||||||
|
disposeDevMap.put(dev.getIpAddr(), dev);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.dispose.task;
|
||||||
|
|
||||||
|
import com.dispose.common.ConstValue;
|
||||||
|
import com.dispose.dispose.DeviceRouter;
|
||||||
|
import com.dispose.dispose.DisposeEntryManager;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.redis.RedisClient;
|
||||||
|
import com.dispose.service.DisposeNodeManager;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class DeviceManagerTask {
|
||||||
|
@Resource
|
||||||
|
private DisposeNodeManager disposeNodeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Corn 秒 分 小时 日期 月份 星期 每10秒执行
|
||||||
|
*/
|
||||||
|
@Async("bizExecutor")
|
||||||
|
@Scheduled(cron = "0/30 * * * * ?")
|
||||||
|
public void threadPoolTask() {
|
||||||
|
List<DisposeDevice> devList = disposeNodeManager.getAllDisposeDevice();
|
||||||
|
|
||||||
|
devList.forEach(v -> {
|
||||||
|
DisposeEntryManager dp = DeviceRouter.deviceRouterFactory(v.getType(),
|
||||||
|
v.getIpAddr(),
|
||||||
|
ConstValue.IPAddrType.getIpAddrType(v.getIpAddr()));
|
||||||
|
|
||||||
|
if(dp != null) {
|
||||||
|
v.setLinkStatus(dp.getDeviceLinkStatus() ? 1 : 0);
|
||||||
|
log.info("Upgrade {} Link Status", v.getIpAddr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,119 +0,0 @@
|
||||||
package com.dispose.task;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
import com.dispose.common.DateUtil;
|
|
||||||
import com.dispose.redis.RedisClient;
|
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.dispose.config.MyConfig;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 轻量级定时任务
|
|
||||||
*
|
|
||||||
* @author phoenix
|
|
||||||
* @date 2020年2月4日
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
public class MyTask {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedisClient redisClient;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MyConfig myConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试任务 秒 分 小时 日期 月份 星期 每10秒执行
|
|
||||||
*/
|
|
||||||
@Scheduled(cron = "0/10 * * * * ?")
|
|
||||||
public void task() {
|
|
||||||
log.info("Now is " + DateUtil.d2s(DateUtil.getCurrentTime(), DateUtil.YYYYMMDDHHMMSSSSSWITHSYMBOL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分布式锁场景
|
|
||||||
*/
|
|
||||||
// @Scheduled(cron = "0/10 * * * * ?")
|
|
||||||
public void lockTask() {
|
|
||||||
String lockName = "myLock";
|
|
||||||
boolean lock = false;
|
|
||||||
try {
|
|
||||||
lock = redisClient.setLock(lockName);
|
|
||||||
if (lock) {
|
|
||||||
log.info("获取锁 {} 成功", lockName);
|
|
||||||
// 做自己的业务
|
|
||||||
} else {
|
|
||||||
log.info("拿锁 {} 失败", lockName);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("XXX异常", e);
|
|
||||||
} finally {
|
|
||||||
if (lock) {
|
|
||||||
redisClient.del(lockName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用自定义线程池执行的定时任务
|
|
||||||
*/
|
|
||||||
@Async("logExecutor")
|
|
||||||
@Scheduled(cron = "0/5 * * * * ?")
|
|
||||||
public void threadPoolTask() {
|
|
||||||
log.info("我是自定义线程池执行的");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定时请求是否有新文件更新
|
|
||||||
* 威胁情报文件下载更新示例
|
|
||||||
*/
|
|
||||||
// @Async("bizExecutor")
|
|
||||||
// @Scheduled(cron = "0/5 * * * * ?")
|
|
||||||
// public void threatInfoHttpReq() {
|
|
||||||
// log.info("定时请求威胁情报,检测是否有文件更新");
|
|
||||||
// Map<String, String> header = Maps.newHashMap();
|
|
||||||
// header.put("HY-AUTH-KEY", myConfig.getThreatInfoKey());
|
|
||||||
// String str = Http.get(myConfig.getThreatInfoVersionUrl(), header);
|
|
||||||
// log.info("接口响应数据 {}", str);
|
|
||||||
// JSONObject json = JSON.parseObject(str);
|
|
||||||
// String status = json.getString("status");
|
|
||||||
// int maxVersion = -1;
|
|
||||||
// if ("0".equals(status)) {
|
|
||||||
// JSONArray ja = JSON.parseArray(json.getString("result"));
|
|
||||||
// log.info("result列表数据 {}", ja);
|
|
||||||
// for (int i = 0; i < ja.size(); i++) {
|
|
||||||
// JSONObject eachJson = ja.getJSONObject(i);
|
|
||||||
// String type = eachJson.getString("type");
|
|
||||||
// if ("1".equals(type)) {
|
|
||||||
// int version = Integer.parseInt(eachJson.getString("version"));
|
|
||||||
// if (version > maxVersion) {
|
|
||||||
// maxVersion = version;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 判断接口获得最大version是否和当前内存一致,决定是否更新文件
|
|
||||||
// if (maxVersion > GlobalVar.MAX_THREAT_INFO_VERSION) {
|
|
||||||
// GlobalVar.MAX_THREAT_INFO_VERSION = maxVersion;
|
|
||||||
// // 下载文件更新
|
|
||||||
// log.info("下载文件更新");
|
|
||||||
// Map<String, Object> body = Maps.newHashMap();
|
|
||||||
// body.put("version", GlobalVar.MAX_THREAT_INFO_VERSION);
|
|
||||||
// body.put("type", GlobalVar.THREAT_INFO_TYPE);
|
|
||||||
// String downFileRes = Http.postForm(myConfig.getThreatInfoDownload(), header, body);
|
|
||||||
// List<String> threatInfo = Utils.splitStr2List(downFileRes, "\n");
|
|
||||||
// log.info("威胁情报数据量 {}",threatInfo.size());
|
|
||||||
// log.info("下载的文件内容 {}", StringUtils.abbreviate(downFileRes, 1000));
|
|
||||||
// //将自身系统内的威胁情报变量替换成上述读取的数据,达到威胁情报数据更新的效果
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.dispose.mapper.DisposeDeviceMapper">
|
||||||
|
<insert id="addNewDisposeDevice" useGeneratedKeys="true" keyProperty="id" parameterType="com.dispose.pojo.entity.DisposeDevice">
|
||||||
|
INSERT INTO
|
||||||
|
dispose_device(ipAddr, type,
|
||||||
|
areaCode, name, manufacturer,
|
||||||
|
model, version, readme, status)
|
||||||
|
VALUES
|
||||||
|
(#{ipAddr}, #{type},
|
||||||
|
#{areaCode}, #{name}, #{manufacturer},
|
||||||
|
#{model}, #{version}, #{readme}, 0)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="getDeviceByIp" resultType="com.dispose.pojo.entity.DisposeDevice" parameterType="java.lang.String">
|
||||||
|
SELECT * FROM dispose_device
|
||||||
|
WHERE
|
||||||
|
ipAddr = #{ipAddr}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getDeviceById" resultType="com.dispose.pojo.entity.DisposeDevice" parameterType="java.lang.Long">
|
||||||
|
SELECT * FROM dispose_device
|
||||||
|
WHERE
|
||||||
|
id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="isDeviceExistsByIp" resultType="java.lang.Integer">
|
||||||
|
SELECT COUNT(*) FROM dispose_device
|
||||||
|
WHERE
|
||||||
|
ipAddr = #{ipAddr}
|
||||||
|
</select>
|
||||||
|
<select id="isDeviceExistsById" resultType="java.lang.Integer">
|
||||||
|
SELECT COUNT(*) FROM dispose_device
|
||||||
|
WHERE
|
||||||
|
id = #{id}
|
||||||
|
</select>
|
||||||
|
<delete id="delDisposeDeviceByIp" parameterType="java.lang.String">
|
||||||
|
DELETE
|
||||||
|
dispose_device
|
||||||
|
FROM
|
||||||
|
dispose_device
|
||||||
|
WHERE
|
||||||
|
dispose_device.ipAddr = #{ipAddr}
|
||||||
|
</delete>
|
||||||
|
<delete id="delDisposeDeviceById" parameterType="java.lang.Long">
|
||||||
|
DELETE
|
||||||
|
dispose_device
|
||||||
|
FROM
|
||||||
|
dispose_device
|
||||||
|
WHERE
|
||||||
|
dispose_device.id = #{id}
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
|
@ -2,6 +2,7 @@ package com.dispose.TestSuit;
|
||||||
|
|
||||||
|
|
||||||
import com.dispose.controller.AuthControllerTest;
|
import com.dispose.controller.AuthControllerTest;
|
||||||
|
import com.dispose.controller.DeviceNodeManagerControllerTest;
|
||||||
import com.dispose.dptech.DPTechInterfaceTestCase;
|
import com.dispose.dptech.DPTechInterfaceTestCase;
|
||||||
import com.dispose.mapper.UserAccountMapperTest;
|
import com.dispose.mapper.UserAccountMapperTest;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -11,7 +12,8 @@ import org.junit.runners.Suite;
|
||||||
@Suite.SuiteClasses({
|
@Suite.SuiteClasses({
|
||||||
DPTechInterfaceTestCase.class,
|
DPTechInterfaceTestCase.class,
|
||||||
UserAccountMapperTest.class,
|
UserAccountMapperTest.class,
|
||||||
AuthControllerTest.class
|
AuthControllerTest.class,
|
||||||
|
DeviceNodeManagerControllerTest.class
|
||||||
})
|
})
|
||||||
public class AllDisposePlatformTest {
|
public class AllDisposePlatformTest {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package com.dispose.controller;
|
||||||
|
|
||||||
|
import com.dispose.common.ConstValue;
|
||||||
|
import com.dispose.pojo.dto.ProtocolReqDTO;
|
||||||
|
import com.dispose.pojo.po.NewNodeInfo;
|
||||||
|
import com.dispose.pojo.vo.device.AddNodeReq;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
|
||||||
|
@Slf4j
|
||||||
|
public class DeviceNodeManagerControllerTest {
|
||||||
|
@Resource
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addDevice() throws Exception {
|
||||||
|
AddNodeReq addReq = AddNodeReq.builder()
|
||||||
|
.items(new ArrayList<>())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
addReq.getItems().add(NewNodeInfo.builder()
|
||||||
|
.id("0")
|
||||||
|
.ipAddr("10.88.77.15")
|
||||||
|
.type(ConstValue.DisposeDeviceType.DPTECH_UMC.getCode())
|
||||||
|
.areaCode(0)
|
||||||
|
.name("中移杭研实验室清洗设备")
|
||||||
|
.manufacturer("DPTech")
|
||||||
|
.model("UMC")
|
||||||
|
.version("5.7.13")
|
||||||
|
.readme("实验室测试设备")
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addReq.getItems().add(NewNodeInfo.builder()
|
||||||
|
.id("1")
|
||||||
|
.ipAddr("107.212.70.4")
|
||||||
|
.type(ConstValue.DisposeDeviceType.DPTECH_UMC.getCode())
|
||||||
|
.areaCode(0)
|
||||||
|
.name("无效设备")
|
||||||
|
.manufacturer("浩瀚")
|
||||||
|
.model("清洗")
|
||||||
|
.version("3.1.1")
|
||||||
|
.readme("实验室测试设备")
|
||||||
|
.build());
|
||||||
|
|
||||||
|
ProtocolReqDTO reqInfo = new ProtocolReqDTO();
|
||||||
|
reqInfo.setVer(ConstValue.Protocol.VERSION);
|
||||||
|
reqInfo.setCryptoType(ConstValue.Protocol.CRYPTO_NONE);
|
||||||
|
reqInfo.setTimeStamp(System.currentTimeMillis());
|
||||||
|
reqInfo.setMsgContent(objectMapper.writeValueAsString(addReq));
|
||||||
|
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders
|
||||||
|
.put("/manager/device")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.header("Authorization", "Bearer 45509b805d955cfd5ef7093e27a8bb99b3733d9a7bf90e88ba528bcbd29c6122")
|
||||||
|
.content(objectMapper.writeValueAsString(reqInfo)))
|
||||||
|
.andDo(print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.code").value(200))
|
||||||
|
.andReturn()
|
||||||
|
.getResponse()
|
||||||
|
.getContentAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,14 +3,28 @@ package com.dispose.dptech;
|
||||||
import com.dispose.common.ConstValue;
|
import com.dispose.common.ConstValue;
|
||||||
import com.dispose.dispose.DeviceRouter;
|
import com.dispose.dispose.DeviceRouter;
|
||||||
import com.dispose.dispose.DisposeEntryManager;
|
import com.dispose.dispose.DisposeEntryManager;
|
||||||
|
import com.dispose.pojo.po.DisposeDeviceCapacity;
|
||||||
import com.dptech.dispose.DetectionObjectDataForService;
|
import com.dptech.dispose.DetectionObjectDataForService;
|
||||||
import com.dptech.dispose.ProtectionObjectDataForService;
|
import com.dptech.dispose.ProtectionObjectDataForService;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@Slf4j
|
||||||
public class DPTechInterfaceTestCase {
|
public class DPTechInterfaceTestCase {
|
||||||
|
@Resource
|
||||||
|
private ObjectMapper objMapper;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllDetectionObjectFromUMC(){
|
public void getAllDetectionObjectFromUMC(){
|
||||||
|
|
||||||
|
@ -64,4 +78,17 @@ public class DPTechInterfaceTestCase {
|
||||||
|
|
||||||
Assert.assertTrue(dp.getDeviceLinkStatus());
|
Assert.assertTrue(dp.getDeviceLinkStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceCapacity() throws JsonProcessingException {
|
||||||
|
|
||||||
|
DisposeEntryManager dp = DeviceRouter.deviceRouterFactory(ConstValue.DisposeDeviceType.DPTECH_UMC.getCode(),
|
||||||
|
"10.88.77.15");
|
||||||
|
|
||||||
|
List<DisposeDeviceCapacity> capList = dp.getDeviceCapacity();
|
||||||
|
|
||||||
|
Assert.assertNotEquals(capList.size(), 0);
|
||||||
|
|
||||||
|
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(capList));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.dispose.mapper;
|
||||||
|
|
||||||
|
import com.dispose.common.ConstValue;
|
||||||
|
import com.dispose.pojo.entity.DisposeDevice;
|
||||||
|
import com.dispose.pojo.po.DisposeDeviceCapacity;
|
||||||
|
import com.dispose.service.DisposeNodeManager;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@Slf4j
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class DisposeDeviceMapperTest {
|
||||||
|
@Resource
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DisposeDeviceMapper disposeDeviceMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DisposeNodeManager disposeNodeManager;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t1_addNewDisposeDevice() throws JsonProcessingException {
|
||||||
|
Long devId = -1L;
|
||||||
|
DisposeDevice dev = new DisposeDevice();
|
||||||
|
List<DisposeDeviceCapacity> devCaps = new ArrayList<>();
|
||||||
|
dev.setId(devId);
|
||||||
|
dev.setIpAddr("10.88.77.15");
|
||||||
|
dev.setType(ConstValue.DisposeDeviceType.DPTECH_UMC.getCode());
|
||||||
|
dev.setName("中移杭研实验室清洗设备");
|
||||||
|
dev.setManufacturer("DPTech");
|
||||||
|
dev.setModel("UMC");
|
||||||
|
dev.setVersion("5.7.13");
|
||||||
|
dev.setReadme("实验室测试设备");
|
||||||
|
dev.setAreaCode(0);
|
||||||
|
dev.setDevCaps(devCaps);
|
||||||
|
|
||||||
|
disposeNodeManager.addNewDisposeDevice(dev);
|
||||||
|
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dev));
|
||||||
|
|
||||||
|
Assert.assertNotEquals(devId, dev.getId());
|
||||||
|
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t2_isDeviceExistsByIp() throws JsonProcessingException {
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
|
||||||
|
dp.forEach(v->{
|
||||||
|
Assert.assertNotEquals(disposeDeviceMapper.isDeviceExistsByIp(v.getIpAddr()), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t3_isDeviceExistsById() throws JsonProcessingException {
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
|
||||||
|
dp.forEach(v->{
|
||||||
|
Assert.assertNotEquals(disposeDeviceMapper.isDeviceExistsById(v.getId()), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t4_getDeviceExistsByIp() throws JsonProcessingException {
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
|
||||||
|
dp.forEach(v->{
|
||||||
|
DisposeDevice dev = disposeDeviceMapper.getDeviceByIp(v.getIpAddr());
|
||||||
|
Assert.assertNotNull(dp);
|
||||||
|
Assert.assertEquals(dev.getIpAddr(), v.getIpAddr());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t5_getDeviceExistsById() throws JsonProcessingException {
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
|
||||||
|
dp.forEach(v->{
|
||||||
|
DisposeDevice dev = disposeDeviceMapper.getDeviceById(v.getId());
|
||||||
|
Assert.assertNotNull(dp);
|
||||||
|
Assert.assertEquals(dev.getId(), v.getId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t100_delDisposeDeviceByIp() throws JsonProcessingException {
|
||||||
|
String ipAddr = "10.88.77.15";
|
||||||
|
disposeDeviceMapper.delDisposeDeviceByIp(ipAddr);
|
||||||
|
|
||||||
|
List<DisposeDevice> dp = disposeDeviceMapper.selectAll();
|
||||||
|
log.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(dp));
|
||||||
|
dp.forEach(v->{
|
||||||
|
if(v.getIpAddr().equals(ipAddr)) {
|
||||||
|
Assert.fail();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ public class UserAccountMapperTest {
|
||||||
private UserAccountMapper userAccountMapper;
|
private UserAccountMapper userAccountMapper;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getUserByName() throws JsonProcessingException {
|
public void t1_getUserByName() throws JsonProcessingException {
|
||||||
UserAccount user = userAccountMapper.getUserByName("admin");
|
UserAccount user = userAccountMapper.getUserByName("admin");
|
||||||
|
|
||||||
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
||||||
|
@ -37,7 +37,7 @@ public class UserAccountMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void lockUser1() throws JsonProcessingException {
|
public void t2_lockUser() throws JsonProcessingException {
|
||||||
userAccountMapper.lockUserAccount("admin");
|
userAccountMapper.lockUserAccount("admin");
|
||||||
|
|
||||||
UserAccount user = userAccountMapper.getUserByName("admin");
|
UserAccount user = userAccountMapper.getUserByName("admin");
|
||||||
|
@ -45,21 +45,22 @@ public class UserAccountMapperTest {
|
||||||
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void unlockUser2() throws JsonProcessingException {
|
|
||||||
userAccountMapper.unlockUserAccount("admin");
|
|
||||||
|
|
||||||
UserAccount user = userAccountMapper.getUserByName("admin");
|
|
||||||
Assert.assertEquals(new Long(user.getStatus()), new Long(ConstValue.UserAccountStatus.NORMAL));
|
|
||||||
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void refreshLoginTime() throws JsonProcessingException {
|
public void t3_refreshLoginTime() throws JsonProcessingException {
|
||||||
userAccountMapper.refreshLoginTime("admin");
|
userAccountMapper.refreshLoginTime("admin");
|
||||||
|
|
||||||
UserAccount user = userAccountMapper.getUserByName("admin");
|
UserAccount user = userAccountMapper.getUserByName("admin");
|
||||||
Assert.assertNotNull(user);
|
Assert.assertNotNull(user);
|
||||||
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void t4_unlockUser() throws JsonProcessingException {
|
||||||
|
userAccountMapper.unlockUserAccount("admin");
|
||||||
|
|
||||||
|
UserAccount user = userAccountMapper.getUserByName("admin");
|
||||||
|
Assert.assertEquals(new Long(user.getStatus()), new Long(ConstValue.UserAccountStatus.NORMAL));
|
||||||
|
log.info(objMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue