mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-30 00:06:38 +08:00
feat: add batch operations for forwards, tunnels, and nodes
- Add batch delete, redeploy, and change-tunnel for forwards - Add batch delete and redeploy for tunnels - Add batch delete for nodes - Add multi-select UI with floating toolbar on all three pages - Create DTOs: BatchDeleteDto, BatchRedeployDto, BatchChangeTunnelDto, BatchOperationResultDto
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package com.admin.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BatchChangeTunnelDto {
|
||||
|
||||
@NotEmpty(message = "转发ID列表不能为空")
|
||||
private List<Long> forwardIds;
|
||||
|
||||
@NotNull(message = "目标隧道ID不能为空")
|
||||
private Long targetTunnelId;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.admin.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BatchDeleteDto {
|
||||
|
||||
@NotEmpty(message = "ID列表不能为空")
|
||||
private List<Long> ids;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.admin.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Data
|
||||
public class BatchOperationResultDto {
|
||||
|
||||
private int successCount;
|
||||
private int failCount;
|
||||
private List<FailedItem> failedItems = new ArrayList<>();
|
||||
|
||||
@Data
|
||||
public static class FailedItem {
|
||||
private Long id;
|
||||
private String reason;
|
||||
|
||||
public FailedItem() {}
|
||||
|
||||
public FailedItem(Long id, String reason) {
|
||||
this.id = id;
|
||||
this.reason = reason;
|
||||
}
|
||||
}
|
||||
|
||||
public void addFailedItem(Long id, String reason) {
|
||||
this.failedItems.add(new FailedItem(id, reason));
|
||||
this.failCount++;
|
||||
}
|
||||
|
||||
public void incrementSuccess() {
|
||||
this.successCount++;
|
||||
}
|
||||
|
||||
public boolean isAllSuccess() {
|
||||
return failCount == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.admin.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BatchRedeployDto {
|
||||
|
||||
@NotEmpty(message = "ID列表不能为空")
|
||||
private List<Long> ids;
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.admin.controller;
|
||||
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.dto.ForwardDto;
|
||||
import com.admin.common.dto.ForwardUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.BatchRedeployDto;
|
||||
import com.admin.common.dto.BatchChangeTunnelDto;
|
||||
import com.admin.common.dto.ForwardDto;
|
||||
import com.admin.common.dto.ForwardUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.service.ForwardService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -91,10 +94,28 @@ public class ForwardController extends BaseController {
|
||||
* @param params 包含forwards数组的参数,每个元素包含id和inx
|
||||
* @return 更新结果
|
||||
*/
|
||||
@LogAnnotation
|
||||
@PostMapping("/update-order")
|
||||
public R updateForwardOrder(@RequestBody Map<String, Object> params) {
|
||||
return forwardService.updateForwardOrder(params);
|
||||
}
|
||||
|
||||
}
|
||||
@LogAnnotation
|
||||
@PostMapping("/update-order")
|
||||
public R updateForwardOrder(@RequestBody Map<String, Object> params) {
|
||||
return forwardService.updateForwardOrder(params);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@PostMapping("/batch-delete")
|
||||
public R batchDelete(@Validated @RequestBody BatchDeleteDto batchDeleteDto) {
|
||||
return forwardService.batchDeleteForwards(batchDeleteDto);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@PostMapping("/batch-redeploy")
|
||||
public R batchRedeploy(@Validated @RequestBody BatchRedeployDto batchRedeployDto) {
|
||||
return forwardService.batchRedeployForwards(batchRedeployDto);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@PostMapping("/batch-change-tunnel")
|
||||
public R batchChangeTunnel(@Validated @RequestBody BatchChangeTunnelDto batchChangeTunnelDto) {
|
||||
return forwardService.batchChangeTunnel(batchChangeTunnelDto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package com.admin.controller;
|
||||
|
||||
|
||||
import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
package com.admin.controller;
|
||||
|
||||
|
||||
import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -74,4 +75,11 @@ public class NodeController extends BaseController {
|
||||
return nodeService.updateNodeOrder(params);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@RequireRole
|
||||
@PostMapping("/batch-delete")
|
||||
public R batchDelete(@Validated @RequestBody BatchDeleteDto batchDeleteDto) {
|
||||
return nodeService.batchDeleteNodes(batchDeleteDto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.admin.controller;
|
||||
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.BatchRedeployDto;
|
||||
import com.admin.common.dto.TunnelDto;
|
||||
import com.admin.common.dto.TunnelUpdateDto;
|
||||
|
||||
@@ -157,4 +159,18 @@ public class TunnelController extends BaseController {
|
||||
return tunnelService.updateTunnelOrder(params);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@RequireRole
|
||||
@PostMapping("/batch-delete")
|
||||
public R batchDelete(@Validated @RequestBody BatchDeleteDto batchDeleteDto) {
|
||||
return tunnelService.batchDeleteTunnels(batchDeleteDto);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@RequireRole
|
||||
@PostMapping("/batch-redeploy")
|
||||
public R batchRedeploy(@Validated @RequestBody BatchRedeployDto batchRedeployDto) {
|
||||
return tunnelService.batchRedeployTunnels(batchRedeployDto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.BatchRedeployDto;
|
||||
import com.admin.common.dto.BatchChangeTunnelDto;
|
||||
import com.admin.common.dto.ForwardDto;
|
||||
import com.admin.common.dto.ForwardUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
@@ -80,4 +83,10 @@ public interface ForwardService extends IService<Forward> {
|
||||
* @return 更新结果
|
||||
*/
|
||||
R updateForwardOrder(Map<String, Object> params);
|
||||
|
||||
R batchDeleteForwards(BatchDeleteDto batchDeleteDto);
|
||||
|
||||
R batchRedeployForwards(BatchRedeployDto batchRedeployDto);
|
||||
|
||||
R batchChangeTunnel(BatchChangeTunnelDto batchChangeTunnelDto);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.Node;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
@@ -34,4 +35,6 @@ public interface NodeService extends IService<Node> {
|
||||
*/
|
||||
R updateNodeOrder(Map<String, Object> params);
|
||||
|
||||
R batchDeleteNodes(BatchDeleteDto batchDeleteDto);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.TunnelDto;
|
||||
import com.admin.common.dto.TunnelUpdateDto;
|
||||
|
||||
import com.admin.common.lang.R;
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.BatchRedeployDto;
|
||||
import com.admin.common.dto.TunnelDto;
|
||||
import com.admin.common.dto.TunnelUpdateDto;
|
||||
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.Tunnel;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
@@ -64,4 +66,18 @@ public interface TunnelService extends IService<Tunnel> {
|
||||
* @param params 包含tunnels数组的参数,每个元素包含id和inx
|
||||
*/
|
||||
R updateTunnelOrder(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 批量删除隧道
|
||||
* @param batchDeleteDto 批量删除数据
|
||||
* @return 操作结果
|
||||
*/
|
||||
R batchDeleteTunnels(BatchDeleteDto batchDeleteDto);
|
||||
|
||||
/**
|
||||
* 批量重新下发隧道配置
|
||||
* @param batchRedeployDto 批量重新下发数据
|
||||
* @return 操作结果
|
||||
*/
|
||||
R batchRedeployTunnels(BatchRedeployDto batchRedeployDto);
|
||||
}
|
||||
|
||||
@@ -1244,4 +1244,222 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
|
||||
private Integer toInx;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchDeleteForwards(BatchDeleteDto batchDeleteDto) {
|
||||
UserInfo currentUser = getCurrentUserInfo();
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
for (Long id : batchDeleteDto.getIds()) {
|
||||
try {
|
||||
Forward forward = validateForwardExists(id, currentUser);
|
||||
if (forward == null) {
|
||||
result.addFailedItem(id, "转发不存在或无权限");
|
||||
continue;
|
||||
}
|
||||
|
||||
Tunnel tunnel = validateTunnel(forward.getTunnelId());
|
||||
if (tunnel == null) {
|
||||
result.addFailedItem(id, "隧道不存在");
|
||||
continue;
|
||||
}
|
||||
|
||||
UserTunnel userTunnel = null;
|
||||
if (currentUser.getRoleId() != 0) {
|
||||
userTunnel = getUserTunnel(currentUser.getUserId(), tunnel.getId().intValue());
|
||||
if (userTunnel == null) {
|
||||
result.addFailedItem(id, "没有该隧道权限");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
userTunnel = getUserTunnel(forward.getUserId(), tunnel.getId().intValue());
|
||||
}
|
||||
|
||||
List<ChainTunnel> chainTunnels = chainTunnelService.list(
|
||||
new QueryWrapper<ChainTunnel>().eq("tunnel_id", tunnel.getId()).eq("chain_type", 1)
|
||||
);
|
||||
|
||||
boolean deleteSuccess = true;
|
||||
for (ChainTunnel chainTunnel : chainTunnels) {
|
||||
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), userTunnel);
|
||||
Node node = nodeService.getById(chainTunnel.getNodeId());
|
||||
if (node != null) {
|
||||
JSONArray services = new JSONArray();
|
||||
services.add(serviceName + "_tcp");
|
||||
services.add(serviceName + "_udp");
|
||||
GostUtil.DeleteService(node.getId(), services);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteSuccess) {
|
||||
forwardPortService.remove(new QueryWrapper<ForwardPort>().eq("forward_id", id));
|
||||
this.removeById(id);
|
||||
result.incrementSuccess();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(id, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isAllSuccess()) {
|
||||
return R.ok(result);
|
||||
} else {
|
||||
return R.ok("部分操作失败", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchRedeployForwards(BatchRedeployDto batchRedeployDto) {
|
||||
UserInfo currentUser = getCurrentUserInfo();
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
for (Long id : batchRedeployDto.getIds()) {
|
||||
try {
|
||||
Forward forward = validateForwardExists(id, currentUser);
|
||||
if (forward == null) {
|
||||
result.addFailedItem(id, "转发不存在或无权限");
|
||||
continue;
|
||||
}
|
||||
|
||||
Tunnel tunnel = validateTunnel(forward.getTunnelId());
|
||||
if (tunnel == null) {
|
||||
result.addFailedItem(id, "隧道不存在");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tunnel.getStatus() != 1) {
|
||||
result.addFailedItem(id, "隧道已禁用");
|
||||
continue;
|
||||
}
|
||||
|
||||
UserPermissionResult permissionResult = checkUserPermissions(currentUser, tunnel, id);
|
||||
if (permissionResult.isHasError()) {
|
||||
result.addFailedItem(id, permissionResult.getErrorMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ForwardPort> forwardPorts = forwardPortService.list(
|
||||
new QueryWrapper<ForwardPort>().eq("forward_id", id)
|
||||
);
|
||||
|
||||
for (ForwardPort forwardPort : forwardPorts) {
|
||||
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), permissionResult.getUserTunnel());
|
||||
Node node = nodeService.getById(forwardPort.getNodeId());
|
||||
if (node != null) {
|
||||
GostUtil.AddAndUpdateService(serviceName, permissionResult.getLimiter(),
|
||||
node, forward, forwardPort, tunnel, "UpdateService");
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementSuccess();
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(id, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isAllSuccess()) {
|
||||
return R.ok(result);
|
||||
} else {
|
||||
return R.ok("部分操作失败", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchChangeTunnel(BatchChangeTunnelDto batchChangeTunnelDto) {
|
||||
UserInfo currentUser = getCurrentUserInfo();
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
Long targetTunnelId = batchChangeTunnelDto.getTargetTunnelId();
|
||||
Tunnel targetTunnel = tunnelService.getById(targetTunnelId);
|
||||
if (targetTunnel == null) {
|
||||
return R.err("目标隧道不存在");
|
||||
}
|
||||
if (targetTunnel.getStatus() != 1) {
|
||||
return R.err("目标隧道已禁用");
|
||||
}
|
||||
|
||||
for (Long forwardId : batchChangeTunnelDto.getForwardIds()) {
|
||||
try {
|
||||
Forward forward = validateForwardExists(forwardId, currentUser);
|
||||
if (forward == null) {
|
||||
result.addFailedItem(forwardId, "转发不存在或无权限");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (forward.getTunnelId().equals(targetTunnelId.intValue())) {
|
||||
result.addFailedItem(forwardId, "已是目标隧道");
|
||||
continue;
|
||||
}
|
||||
|
||||
Tunnel oldTunnel = validateTunnel(forward.getTunnelId());
|
||||
if (oldTunnel != null) {
|
||||
UserTunnel oldUserTunnel = null;
|
||||
if (currentUser.getRoleId() != 0) {
|
||||
oldUserTunnel = getUserTunnel(currentUser.getUserId(), oldTunnel.getId().intValue());
|
||||
} else {
|
||||
oldUserTunnel = getUserTunnel(forward.getUserId(), oldTunnel.getId().intValue());
|
||||
}
|
||||
|
||||
List<ChainTunnel> oldChainTunnels = chainTunnelService.list(
|
||||
new QueryWrapper<ChainTunnel>().eq("tunnel_id", oldTunnel.getId()).eq("chain_type", 1)
|
||||
);
|
||||
for (ChainTunnel chainTunnel : oldChainTunnels) {
|
||||
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), oldUserTunnel);
|
||||
Node node = nodeService.getById(chainTunnel.getNodeId());
|
||||
if (node != null) {
|
||||
JSONArray services = new JSONArray();
|
||||
services.add(serviceName + "_tcp");
|
||||
services.add(serviceName + "_udp");
|
||||
GostUtil.DeleteService(node.getId(), services);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forwardPortService.remove(new QueryWrapper<ForwardPort>().eq("forward_id", forwardId));
|
||||
|
||||
forward.setTunnelId(targetTunnelId.intValue());
|
||||
forward.setUpdatedTime(System.currentTimeMillis());
|
||||
this.updateById(forward);
|
||||
|
||||
UserPermissionResult permissionResult = checkUserPermissions(currentUser, targetTunnel, forwardId);
|
||||
if (permissionResult.isHasError()) {
|
||||
result.addFailedItem(forwardId, "切换成功但无法下发: " + permissionResult.getErrorMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ChainTunnel> newChainTunnels = chainTunnelService.list(
|
||||
new QueryWrapper<ChainTunnel>().eq("tunnel_id", targetTunnel.getId()).eq("chain_type", 1)
|
||||
);
|
||||
List<ChainTunnel> chainTunnelsWithPort = get_port(newChainTunnels, null, forwardId);
|
||||
|
||||
for (ChainTunnel chainTunnel : chainTunnelsWithPort) {
|
||||
ForwardPort forwardPort = new ForwardPort();
|
||||
forwardPort.setForwardId(forwardId);
|
||||
forwardPort.setNodeId(chainTunnel.getNodeId());
|
||||
forwardPort.setPort(chainTunnel.getPort());
|
||||
forwardPortService.save(forwardPort);
|
||||
|
||||
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), permissionResult.getUserTunnel());
|
||||
Node node = nodeService.getById(chainTunnel.getNodeId());
|
||||
if (node != null) {
|
||||
GostUtil.AddAndUpdateService(serviceName, permissionResult.getLimiter(),
|
||||
node, forward, forwardPort, targetTunnel, "AddService");
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementSuccess();
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(forwardId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isAllSuccess()) {
|
||||
return R.ok(result);
|
||||
} else {
|
||||
return R.ok("部分操作失败", result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package com.admin.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.admin.common.dto.GostDto;
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.dto.BatchDeleteDto;
|
||||
import com.admin.common.dto.BatchOperationResultDto;
|
||||
import com.admin.common.dto.GostDto;
|
||||
import com.admin.common.dto.NodeDto;
|
||||
import com.admin.common.dto.NodeUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.common.utils.GostUtil;
|
||||
import com.admin.common.utils.WebSocketServer;
|
||||
@@ -479,34 +481,59 @@ public class NodeServiceImpl extends ServiceImpl<NodeMapper, Node> implements No
|
||||
}
|
||||
|
||||
|
||||
private void validatePortRange(String port) {
|
||||
Pattern PORT_PATTERN = Pattern.compile( "([0-9]{1,5})(-([0-9]{1,5}))?");
|
||||
if (port == null || port.isEmpty()) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
String[] parts = port.split(",");
|
||||
for (String part : parts) {
|
||||
part = part.trim();
|
||||
if (!PORT_PATTERN.matcher(part).matches()) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
if (part.contains("-")) {
|
||||
String[] range = part.split("-");
|
||||
int start = Integer.parseInt(range[0]);
|
||||
int end = Integer.parseInt(range[1]);
|
||||
if (start < 0 || end < 0 || end > 65535 || start > end) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
} else {
|
||||
int ports = Integer.parseInt(part);
|
||||
if (ports < 0 || ports > 65535) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void validatePortRange(String port) {
|
||||
Pattern PORT_PATTERN = Pattern.compile( "([0-9]{1,5})(-([0-9]{1,5}))?");
|
||||
if (port == null || port.isEmpty()) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
String[] parts = port.split(",");
|
||||
for (String part : parts) {
|
||||
part = part.trim();
|
||||
if (!PORT_PATTERN.matcher(part).matches()) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
if (part.contains("-")) {
|
||||
String[] range = part.split("-");
|
||||
int start = Integer.parseInt(range[0]);
|
||||
int end = Integer.parseInt(range[1]);
|
||||
if (start < 0 || end < 0 || end > 65535 || start > end) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
} else {
|
||||
int ports = Integer.parseInt(part);
|
||||
if (ports < 0 || ports > 65535) {
|
||||
throw new RuntimeException("可用端口不合法");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchDeleteNodes(BatchDeleteDto batchDeleteDto) {
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
for (Long id : batchDeleteDto.getIds()) {
|
||||
try {
|
||||
R deleteResult = deleteNode(id);
|
||||
if (deleteResult.getCode() == 0) {
|
||||
result.incrementSuccess();
|
||||
} else {
|
||||
result.addFailedItem(id, deleteResult.getMsg());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(id, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isAllSuccess()) {
|
||||
return R.ok(result);
|
||||
} else {
|
||||
return R.ok("部分操作失败", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1342,5 +1342,91 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
|
||||
return forwardId + "_" + userId + "_" + userTunnelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchDeleteTunnels(BatchDeleteDto batchDeleteDto) {
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
for (Long id : batchDeleteDto.getIds()) {
|
||||
try {
|
||||
Tunnel tunnel = this.getById(id);
|
||||
if (tunnel == null) {
|
||||
result.addFailedItem(id, "隧道不存在");
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Forward> forwardList = forwardService.list(new QueryWrapper<Forward>().eq("tunnel_id", id));
|
||||
for (Forward forward : forwardList) {
|
||||
forwardService.deleteForward(forward.getId());
|
||||
}
|
||||
forwardService.remove(new QueryWrapper<Forward>().eq("tunnel_id", id));
|
||||
userTunnelService.remove(new QueryWrapper<UserTunnel>().eq("tunnel_id", id));
|
||||
this.removeById(id);
|
||||
|
||||
List<ChainTunnel> chainTunnels = chainTunnelService.list(new QueryWrapper<ChainTunnel>().eq("tunnel_id", id));
|
||||
for (ChainTunnel chainTunnel : chainTunnels) {
|
||||
if (chainTunnel.getChainType() == 1) {
|
||||
GostUtil.DeleteChains(chainTunnel.getNodeId(), "chains_" + chainTunnel.getTunnelId());
|
||||
} else if (chainTunnel.getChainType() == 2) {
|
||||
GostUtil.DeleteChains(chainTunnel.getNodeId(), "chains_" + chainTunnel.getTunnelId());
|
||||
JSONArray services = new JSONArray();
|
||||
services.add(chainTunnel.getTunnelId() + "_tls");
|
||||
GostUtil.DeleteService(chainTunnel.getNodeId(), services);
|
||||
} else {
|
||||
JSONArray services = new JSONArray();
|
||||
services.add(chainTunnel.getTunnelId() + "_tls");
|
||||
GostUtil.DeleteService(chainTunnel.getNodeId(), services);
|
||||
}
|
||||
}
|
||||
chainTunnelService.remove(new QueryWrapper<ChainTunnel>().eq("tunnel_id", id));
|
||||
|
||||
result.incrementSuccess();
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(id, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public R batchRedeployTunnels(BatchRedeployDto batchRedeployDto) {
|
||||
BatchOperationResultDto result = new BatchOperationResultDto();
|
||||
|
||||
for (Long id : batchRedeployDto.getIds()) {
|
||||
try {
|
||||
Tunnel tunnel = this.getById(id);
|
||||
if (tunnel == null) {
|
||||
result.addFailedItem(id, "隧道不存在");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tunnel.getType() != 2) {
|
||||
result.incrementSuccess();
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ChainTunnel> chainTunnels = chainTunnelService.list(
|
||||
new QueryWrapper<ChainTunnel>().eq("tunnel_id", id)
|
||||
);
|
||||
|
||||
if (chainTunnels.isEmpty()) {
|
||||
result.addFailedItem(id, "隧道配置不完整");
|
||||
continue;
|
||||
}
|
||||
|
||||
cleanupGostConfig(chainTunnels, id);
|
||||
rebuildGostConfig(chainTunnels, tunnel);
|
||||
|
||||
result.incrementSuccess();
|
||||
} catch (Exception e) {
|
||||
result.addFailedItem(id, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user