开发frpc接口、增加网卡绑定触发逻辑。
This commit is contained in:
+6
@@ -180,5 +180,11 @@ public class RmResourceRegistrationRemote extends BaseEntity
|
|||||||
private Date onboardTime;
|
private Date onboardTime;
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date delAlarmTime;
|
private Date delAlarmTime;
|
||||||
|
/** FRP连接地址生成状态(0-未生成,1-生成中,2已生成) */
|
||||||
|
private String frpcConnectionStatus;
|
||||||
|
/** FRPC远程端口 */
|
||||||
|
private String frpcRemotePort;
|
||||||
|
/** FRPC服务器地址 */
|
||||||
|
private String frpcServerAddr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -266,4 +266,10 @@ public class RmResourceRegistration extends BaseEntity
|
|||||||
/** 取消告警时间 */
|
/** 取消告警时间 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date delAlarmTime;
|
private Date delAlarmTime;
|
||||||
|
/** FRP连接地址生成状态(0-未生成,1-生成中,2已生成) */
|
||||||
|
private String frpcConnectionStatus;
|
||||||
|
/** FRPC远程端口 */
|
||||||
|
private String frpcRemotePort;
|
||||||
|
/** FRPC服务器地址 */
|
||||||
|
private String frpcServerAddr;
|
||||||
}
|
}
|
||||||
+7
@@ -25,6 +25,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="updateBy" column="update_by" />
|
<result property="updateBy" column="update_by" />
|
||||||
<result property="reportedBandwidth" column="reported_bandwidth" />
|
<result property="reportedBandwidth" column="reported_bandwidth" />
|
||||||
<result property="delAlarmTime" column="del_alarm_time" />
|
<result property="delAlarmTime" column="del_alarm_time" />
|
||||||
|
<result property="frpcConnectionStatus" column="frpc_connection_status" />
|
||||||
|
<result property="frpcRemotePort" column="frpc_remote_port" />
|
||||||
|
<result property="frpcServerAddr" column="frpc_server_addr" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectRmResourceRegistrationVo">
|
<sql id="selectRmResourceRegistrationVo">
|
||||||
@@ -239,11 +242,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
a.reported_bandwidth as reportedBandwidth,
|
a.reported_bandwidth as reportedBandwidth,
|
||||||
a.del_alarm_time as delAlarmTime,
|
a.del_alarm_time as delAlarmTime,
|
||||||
b.machine_code as machineCode,
|
b.machine_code as machineCode,
|
||||||
|
c.frpc_connection_status frpcConnectionStatus,
|
||||||
|
c.frpc_remote_port frpcRemotePort,
|
||||||
|
c.frpc_server_addr frpcServerAddr,
|
||||||
(select bandwidth_result from eps_node_bandwidth
|
(select bandwidth_result from eps_node_bandwidth
|
||||||
where client_id=a.client_id and calculation_mode='1000' and bandwidth_type='1'
|
where client_id=a.client_id and calculation_mode='1000' and bandwidth_type='1'
|
||||||
AND create_time = DATE(DATE_SUB(NOW(), INTERVAL 1 DAY)) limit 1) as bandwidthResult
|
AND create_time = DATE(DATE_SUB(NOW(), INTERVAL 1 DAY)) limit 1) as bandwidthResult
|
||||||
from rm_resource_registration a
|
from rm_resource_registration a
|
||||||
left join rm_registration_machine b on a.client_id = b.client_id
|
left join rm_registration_machine b on a.client_id = b.client_id
|
||||||
|
left join rm_frpc_config_manage c on a.client_id=c.client_id
|
||||||
<where>
|
<where>
|
||||||
<if test="hardwareSn != null and hardwareSn != ''"> and a.hardware_sn = #{hardwareSn}</if>
|
<if test="hardwareSn != null and hardwareSn != ''"> and a.hardware_sn = #{hardwareSn}</if>
|
||||||
<if test="resourceType != null and resourceType != ''"> and a.resource_type = #{resourceType}</if>
|
<if test="resourceType != null and resourceType != ''"> and a.resource_type = #{resourceType}</if>
|
||||||
|
|||||||
-5
@@ -47,7 +47,6 @@ public class RmFrpcConfigManageController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 导出FRPC配置管理列表
|
* 导出FRPC配置管理列表
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcConfigManage:export")
|
|
||||||
@Log(title = "FRPC配置管理", businessType = BusinessType.EXPORT)
|
@Log(title = "FRPC配置管理", businessType = BusinessType.EXPORT)
|
||||||
@PostMapping("/export")
|
@PostMapping("/export")
|
||||||
public void export(HttpServletResponse response, @RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
public void export(HttpServletResponse response, @RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
||||||
@@ -61,7 +60,6 @@ public class RmFrpcConfigManageController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 获取FRPC配置管理详细信息
|
* 获取FRPC配置管理详细信息
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcConfigManage:query")
|
|
||||||
@GetMapping(value = "/{id}")
|
@GetMapping(value = "/{id}")
|
||||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
{
|
{
|
||||||
@@ -71,7 +69,6 @@ public class RmFrpcConfigManageController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 新增FRPC配置管理
|
* 新增FRPC配置管理
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcConfigManage:add")
|
|
||||||
@Log(title = "FRPC配置管理", businessType = BusinessType.INSERT)
|
@Log(title = "FRPC配置管理", businessType = BusinessType.INSERT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
public AjaxResult add(@RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
||||||
@@ -82,7 +79,6 @@ public class RmFrpcConfigManageController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 修改FRPC配置管理
|
* 修改FRPC配置管理
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcConfigManage:edit")
|
|
||||||
@Log(title = "FRPC配置管理", businessType = BusinessType.UPDATE)
|
@Log(title = "FRPC配置管理", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
public AjaxResult edit(@RequestBody RmFrpcConfigManage rmFrpcConfigManage)
|
||||||
@@ -93,7 +89,6 @@ public class RmFrpcConfigManageController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 删除FRPC配置管理
|
* 删除FRPC配置管理
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcConfigManage:remove")
|
|
||||||
@Log(title = "FRPC配置管理", businessType = BusinessType.DELETE)
|
@Log(title = "FRPC配置管理", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping("/{ids}")
|
@DeleteMapping("/{ids}")
|
||||||
public AjaxResult remove(@PathVariable Long[] ids)
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
|||||||
+1
-1
@@ -20,6 +20,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/frpcPortMapping")
|
@RequestMapping("/frpcPortMapping")
|
||||||
|
@RequiresPermissions("rocketmq:frpcConfigManage")
|
||||||
public class RmFrpcPortMappingController extends BaseController
|
public class RmFrpcPortMappingController extends BaseController
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -28,7 +29,6 @@ public class RmFrpcPortMappingController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 查询FRPC端口映射配置列表
|
* 查询FRPC端口映射配置列表
|
||||||
*/
|
*/
|
||||||
@RequiresPermissions("rocketmq:frpcPortMapping:list")
|
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public AjaxResult list(@RequestBody RmFrpcPortMapping rmFrpcPortMapping)
|
public AjaxResult list(@RequestBody RmFrpcPortMapping rmFrpcPortMapping)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.time.Instant;
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class FrpRspVo {
|
public class FrpRspVo {
|
||||||
/**
|
/**
|
||||||
* 状态码,0、失败;1、成功
|
* 状态码,0、失败;1、成功;2、端口冲突;3、frpc状态上报;
|
||||||
*/
|
*/
|
||||||
private Integer resCode;
|
private Integer resCode;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public class MessageHandler {
|
|||||||
String HEARTBEAT_RECOVERY_COUNT_PREFIX = "heartbeat:recovery:count:";
|
String HEARTBEAT_RECOVERY_COUNT_PREFIX = "heartbeat:recovery:count:";
|
||||||
|
|
||||||
String HEARTBEAT_COUNT_PREFIX = "heartbeat:count:";
|
String HEARTBEAT_COUNT_PREFIX = "heartbeat:count:";
|
||||||
|
|
||||||
|
// Redis key定义
|
||||||
|
private static final String USED_PORTS_KEY = "frpc:used_ports";
|
||||||
private static final long HEARTBEAT_TIMEOUT = 30000; // 3分钟超时
|
private static final long HEARTBEAT_TIMEOUT = 30000; // 3分钟超时
|
||||||
|
|
||||||
|
|
||||||
@@ -149,12 +152,44 @@ public class MessageHandler {
|
|||||||
RmFrpcConfigManage configManage = new RmFrpcConfigManage();
|
RmFrpcConfigManage configManage = new RmFrpcConfigManage();
|
||||||
configManage.setFrpcRemotePort(rsp.getRemotePort());
|
configManage.setFrpcRemotePort(rsp.getRemotePort());
|
||||||
rmFrpcConfigManageService.addFrpConnect(configManage);
|
rmFrpcConfigManageService.addFrpConnect(configManage);
|
||||||
|
} else if(rsp.getResCode() == 3){
|
||||||
|
// frpc状态上报
|
||||||
|
RmFrpcConfigManage frpcData = new RmFrpcConfigManage();
|
||||||
|
frpcData.setClientId(message.getClientId());
|
||||||
|
frpcData.setFrpcName(rsp.getName());
|
||||||
|
frpcData.setFrpcStatus(rsp.getIsRunning());
|
||||||
|
frpcData.setFrpcLocalPort(rsp.getLocalPort());
|
||||||
|
frpcData.setFrpcLocalIp(rsp.getLocalIP());
|
||||||
|
frpcData.setFrpcCreateTime(createTime);
|
||||||
|
frpcData.setFrpcRemotePort(rsp.getRemotePort());
|
||||||
|
frpcData.setFrpcServerAddr(rsp.getServerAddr());
|
||||||
|
frpcData.setFrpcServerPort(rsp.getServerPort());
|
||||||
|
rmFrpcConfigManageService.insertRmFrpcConfigManage(frpcData);
|
||||||
} else{
|
} else{
|
||||||
|
if(rsp.getRemotePort() != null){
|
||||||
|
// 生成失败 ,释放端口资源
|
||||||
|
removeUsedPort(Integer.parseInt(rsp.getRemotePort()));
|
||||||
|
}
|
||||||
log.error("生成连接失败:{}",rsp.getResMsg());
|
log.error("生成连接失败:{}",rsp.getResMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加端口到已用集合
|
||||||
|
*/
|
||||||
|
public boolean addUsedPort(int port) {
|
||||||
|
Long result = redisTemplate.opsForSet().add(USED_PORTS_KEY, String.valueOf(port));
|
||||||
|
return result != null && result > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从已用集合中移除端口
|
||||||
|
*/
|
||||||
|
public boolean removeUsedPort(int port) {
|
||||||
|
Long result = redisTemplate.opsForSet().remove(USED_PORTS_KEY, String.valueOf(port));
|
||||||
|
return result != null && result > 0;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 保存网卡信息
|
* 保存网卡信息
|
||||||
* @param message
|
* @param message
|
||||||
@@ -1070,6 +1105,20 @@ public class MessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isSingleInterface = networkInfoList.size() == 1;
|
boolean isSingleInterface = networkInfoList.size() == 1;
|
||||||
|
boolean isMultiInterface = networkInfoList.size() > 1;
|
||||||
|
|
||||||
|
// 查询数据库中当前的网卡数量
|
||||||
|
RmNetworkInterface countQuery = new RmNetworkInterface();
|
||||||
|
countQuery.setClientId(clientId);
|
||||||
|
countQuery.setNewFlag(1);
|
||||||
|
List<RmNetworkInterface> currentInterfaces = rmNetworkInterfaceService.selectRmNetworkInterfaceList(countQuery);
|
||||||
|
int currentInterfaceCount = currentInterfaces.size();
|
||||||
|
|
||||||
|
// 判断网卡数量是否发生变化
|
||||||
|
boolean interfaceCountChanged = false;
|
||||||
|
if (!isRegister && currentInterfaceCount != networkInfoList.size()) {
|
||||||
|
interfaceCountChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (NetworkInfo networkInfo : networkInfoList) {
|
for (NetworkInfo networkInfo : networkInfoList) {
|
||||||
List<NetworkInfo> childList = networkInfo.getSubInterfaces();
|
List<NetworkInfo> childList = networkInfo.getSubInterfaces();
|
||||||
@@ -1101,13 +1150,20 @@ public class MessageHandler {
|
|||||||
rmNetworkInterfaceChildService.insertRmNetworkInterfaceChild(insertChild);
|
rmNetworkInterfaceChildService.insertRmNetworkInterfaceChild(insertChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 如果网卡数量有变动,需要更新网卡绑定状态
|
||||||
|
if (!isRegister && interfaceCountChanged) {
|
||||||
|
RmResourceRegistrationRemote updateParam = new RmResourceRegistrationRemote();
|
||||||
|
updateParam.setClientId(clientId);
|
||||||
|
updateParam.setMultiPublicIpStatus("0");
|
||||||
|
remoteRevenueConfigService.updateStatusByResource(updateParam, SecurityConstants.INNER);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 更新网卡信息
|
// 更新网卡信息
|
||||||
RmNetworkInterface oldInterfaceMsg = exits.get(0);
|
RmNetworkInterface oldInterfaceMsg = exits.get(0);
|
||||||
cleanChildOldRecords(clientId, networkInfo.getMac());
|
cleanChildOldRecords(clientId, networkInfo.getMac());
|
||||||
// 判断是否需要创建新记录
|
// 判断是否需要创建新记录
|
||||||
boolean needCreateNew = !StringUtils.equals(networkInfo.getName(), oldInterfaceMsg.getInterfaceName())
|
boolean needCreateNew = (!StringUtils.equals(networkInfo.getName(), oldInterfaceMsg.getInterfaceName())
|
||||||
|| !StringUtils.equals(networkInfo.getGateway(), oldInterfaceMsg.getGateway());
|
|| !StringUtils.equals(networkInfo.getGateway(), oldInterfaceMsg.getGateway())) && StringUtils.equals(networkInfo.getMac(), oldInterfaceMsg.getMacAddress());
|
||||||
if(childList != null && !childList.isEmpty()){
|
if(childList != null && !childList.isEmpty()){
|
||||||
for (NetworkInfo info : childList) {
|
for (NetworkInfo info : childList) {
|
||||||
RmNetworkInterfaceChild insertChild = new RmNetworkInterfaceChild();
|
RmNetworkInterfaceChild insertChild = new RmNetworkInterfaceChild();
|
||||||
@@ -1130,6 +1186,13 @@ public class MessageHandler {
|
|||||||
RmNetworkInterface insertData = new RmNetworkInterface();
|
RmNetworkInterface insertData = new RmNetworkInterface();
|
||||||
setNetworkInterfaceData(insertData, networkInfo, clientId);
|
setNetworkInterfaceData(insertData, networkInfo, clientId);
|
||||||
rmNetworkInterfaceService.insertRmNetworkInterface(insertData);
|
rmNetworkInterfaceService.insertRmNetworkInterface(insertData);
|
||||||
|
// 如果网卡名称有变化,需要更新网卡绑定状态
|
||||||
|
if(!isRegister && !StringUtils.equals(networkInfo.getName(), oldInterfaceMsg.getInterfaceName())){
|
||||||
|
RmResourceRegistrationRemote updateParam = new RmResourceRegistrationRemote();
|
||||||
|
updateParam.setClientId(clientId);
|
||||||
|
updateParam.setMultiPublicIpStatus("0");
|
||||||
|
remoteRevenueConfigService.updateStatusByResource(updateParam, SecurityConstants.INNER);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 更新现有记录
|
// 更新现有记录
|
||||||
updateNetworkInterface(networkInfo, clientId, oldInterfaceMsg, isSingleInterface, isRegister);
|
updateNetworkInterface(networkInfo, clientId, oldInterfaceMsg, isSingleInterface, isRegister);
|
||||||
|
|||||||
+34
-3
@@ -159,10 +159,12 @@ public class RmFrpcConfigManageServiceImpl implements IRmFrpcConfigManageService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int addFrpConnect(RmFrpcConfigManage rmFrpcConfigManage) {
|
public int addFrpConnect(RmFrpcConfigManage rmFrpcConfigManage) {
|
||||||
|
rmFrpcConfigManage.setFrpcConnectionStatus(1L);
|
||||||
|
int rows = rmFrpcConfigManageMapper.insertRmFrpcConfigManage(rmFrpcConfigManage);
|
||||||
// 查询frps配置
|
// 查询frps配置
|
||||||
List<RmFrpcPortMapping> portMappingList = rmFrpcPortMappingMapper.selectRmFrpcPortMappingList(new RmFrpcPortMapping());
|
List<RmFrpcPortMapping> portMappingList = rmFrpcPortMappingMapper.selectRmFrpcPortMappingList(new RmFrpcPortMapping());
|
||||||
Integer startRemotePort = rmFrpcConfigManage.getStartRemotePort();
|
Integer startRemotePort = null;
|
||||||
Integer endRemotePort = rmFrpcConfigManage.getEndRemotePort();
|
Integer endRemotePort = null;
|
||||||
String serverPort = null;
|
String serverPort = null;
|
||||||
String serverAddr = null;
|
String serverAddr = null;
|
||||||
if(portMappingList != null && !portMappingList.isEmpty()){
|
if(portMappingList != null && !portMappingList.isEmpty()){
|
||||||
@@ -181,7 +183,7 @@ public class RmFrpcConfigManageServiceImpl implements IRmFrpcConfigManageService
|
|||||||
addUsedPort(Integer.parseInt(rmFrpcConfigManage.getFrpcRemotePort()));
|
addUsedPort(Integer.parseInt(rmFrpcConfigManage.getFrpcRemotePort()));
|
||||||
}
|
}
|
||||||
// 获取一个可用的随机端口
|
// 获取一个可用的随机端口
|
||||||
int availablePort = getRandomAvailablePort(startRemotePort, endRemotePort);
|
int availablePort = getRandomAvailablePort(clientId, startRemotePort, endRemotePort);
|
||||||
|
|
||||||
if (availablePort != -1) {
|
if (availablePort != -1) {
|
||||||
// 将端口标记为已使用
|
// 将端口标记为已使用
|
||||||
@@ -243,6 +245,35 @@ public class RmFrpcConfigManageServiceImpl implements IRmFrpcConfigManageService
|
|||||||
|
|
||||||
return -1; // 没有可用端口
|
return -1; // 没有可用端口
|
||||||
}
|
}
|
||||||
|
public int getRandomAvailablePort(String clientId, int startPort, int endPort) {
|
||||||
|
// 1. 先清理这个客户端可能存在的旧端口
|
||||||
|
cleanupClientOldPorts(clientId);
|
||||||
|
|
||||||
|
// 2. 获取新端口
|
||||||
|
int newPort = getRandomAvailablePort(startPort, endPort);
|
||||||
|
|
||||||
|
// 3. 记录客户端与端口的关联
|
||||||
|
if (newPort != -1) {
|
||||||
|
redisTemplate.opsForHash().put(
|
||||||
|
"client:port:mapping",
|
||||||
|
clientId,
|
||||||
|
String.valueOf(newPort)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理客户端旧端口
|
||||||
|
*/
|
||||||
|
private void cleanupClientOldPorts(String clientId) {
|
||||||
|
Object oldPortObj = redisTemplate.opsForHash().get("client:port:mapping", clientId);
|
||||||
|
if (oldPortObj != null) {
|
||||||
|
int oldPort = Integer.parseInt(oldPortObj.toString());
|
||||||
|
removeUsedPort(oldPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断端口是否可用(只检查Redis中是否存在)
|
* 判断端口是否可用(只检查Redis中是否存在)
|
||||||
|
|||||||
@@ -149,7 +149,6 @@
|
|||||||
<if test="city != null">city = #{city},</if>
|
<if test="city != null">city = #{city},</if>
|
||||||
<if test="publicIp != null">public_ip = #{publicIp},</if>
|
<if test="publicIp != null">public_ip = #{publicIp},</if>
|
||||||
<if test="interfaceName != null and interfaceName != ''">interface_name = #{interfaceName},</if>
|
<if test="interfaceName != null and interfaceName != ''">interface_name = #{interfaceName},</if>
|
||||||
<if test="macAddress != null">mac_address = #{macAddress},</if>
|
|
||||||
<if test="interfaceType != null">interface_type = #{interfaceType},</if>
|
<if test="interfaceType != null">interface_type = #{interfaceType},</if>
|
||||||
<if test="ipv4Address != null">ipv4_address = #{ipv4Address},</if>
|
<if test="ipv4Address != null">ipv4_address = #{ipv4Address},</if>
|
||||||
<if test="ipv6Address != null">ipv6_address = #{ipv6Address},</if>
|
<if test="ipv6Address != null">ipv6_address = #{ipv6Address},</if>
|
||||||
|
|||||||
Reference in New Issue
Block a user