From 25a1d0daa04a0fcf18fb21acc19f91fe9e2508d9 Mon Sep 17 00:00:00 2001 From: qaq <1937228092@qq.com> Date: Thu, 19 Jun 2025 11:34:24 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8Dh5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- springboot-backend/.gitignore | 33 ---- .../java/com/admin/common/dto/ConfigItem.java | 11 ++ .../com/admin/common/dto/GostConfigDto.java | 19 ++ .../common/task/CheckGostConfigAsync.java | 176 ++++++++++++++++++ 5 files changed, 207 insertions(+), 35 deletions(-) delete mode 100644 springboot-backend/.gitignore create mode 100644 springboot-backend/src/main/java/com/admin/common/dto/ConfigItem.java create mode 100644 springboot-backend/src/main/java/com/admin/common/dto/GostConfigDto.java create mode 100644 springboot-backend/src/main/java/com/admin/common/task/CheckGostConfigAsync.java diff --git a/.gitignore b/.gitignore index b36f060..3b00d91 100644 --- a/.gitignore +++ b/.gitignore @@ -237,8 +237,7 @@ go-gost/gost.json gitee/ -# 错误位置的Java构建产物 -java/ + # ========================================== # 其他 diff --git a/springboot-backend/.gitignore b/springboot-backend/.gitignore deleted file mode 100644 index 549e00a..0000000 --- a/springboot-backend/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-backend/src/main/java/com/admin/common/dto/ConfigItem.java b/springboot-backend/src/main/java/com/admin/common/dto/ConfigItem.java new file mode 100644 index 0000000..b8dae8e --- /dev/null +++ b/springboot-backend/src/main/java/com/admin/common/dto/ConfigItem.java @@ -0,0 +1,11 @@ +package com.admin.common.dto; + + +import lombok.Data; + +@Data +public class ConfigItem { + private String name; +} + + diff --git a/springboot-backend/src/main/java/com/admin/common/dto/GostConfigDto.java b/springboot-backend/src/main/java/com/admin/common/dto/GostConfigDto.java new file mode 100644 index 0000000..edcde19 --- /dev/null +++ b/springboot-backend/src/main/java/com/admin/common/dto/GostConfigDto.java @@ -0,0 +1,19 @@ +package com.admin.common.dto; + + +import lombok.Data; + +import java.util.List; + +@Data +public class GostConfigDto { + + private List limiters; + + private List chains; + + private List services; + + +} + diff --git a/springboot-backend/src/main/java/com/admin/common/task/CheckGostConfigAsync.java b/springboot-backend/src/main/java/com/admin/common/task/CheckGostConfigAsync.java new file mode 100644 index 0000000..f0b3204 --- /dev/null +++ b/springboot-backend/src/main/java/com/admin/common/task/CheckGostConfigAsync.java @@ -0,0 +1,176 @@ +package com.admin.common.task; + +import com.admin.common.dto.ConfigItem; +import com.admin.common.dto.GostConfigDto; +import com.admin.common.utils.GostUtil; +import com.admin.entity.Forward; +import com.admin.entity.Node; +import com.admin.entity.SpeedLimit; +import com.admin.service.ForwardService; +import com.admin.service.NodeService; +import com.admin.service.SpeedLimitService; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Configuration +@EnableScheduling +public class CheckGostConfigAsync { + + @Resource + private NodeService nodeService; + + @Resource + private ForwardService forwardService; + + @Resource + private SpeedLimitService speedLimitService; + + /** + * 启动后10秒执行一次,然后每10分钟执行一次 + * 清理孤立的Gost配置项 + */ + @Scheduled(initialDelay = 10000, fixedRate = 600000) + public void cleanOrphanedGostConfigs() { + log.info("开始清理孤立的Gost配置项"); + + List activeNodes = nodeService.list(new QueryWrapper().eq("status", 1)); + log.info("找到 {} 个活跃节点", activeNodes.size()); + + for (Node node : activeNodes) { + cleanNodeConfigs(node); + } + + log.info("Gost配置清理任务完成"); + } + + /** + * 清理单个节点的配置 + */ + private void cleanNodeConfigs(Node node) { + String nodeAddress = node.getIp() + ":" + node.getPort(); + + try { + GostConfigDto gostConfig = GostUtil.GetConfig(nodeAddress, node.getSecret()); + + cleanOrphanedServices(gostConfig, node); + cleanOrphanedChains(gostConfig, node); + cleanOrphanedLimiters(gostConfig, node); + + } catch (Exception e) { + log.error("清理节点 {} 配置时发生错误", nodeAddress, e); + } + } + + /** + * 清理孤立的服务 + */ + private void cleanOrphanedServices(GostConfigDto gostConfig, Node node) { + if (gostConfig.getServices() == null) { + return; + } + + String nodeAddress = node.getIp() + ":" + node.getPort(); + + for (ConfigItem service : gostConfig.getServices()) { + safeExecute(() -> { + if (Objects.equals(service.getName(), "web_api")) { + return; // 排除API服务 + } + + String[] serviceIds = parseServiceName(service.getName()); + if (serviceIds.length == 4) { + String forwardId = serviceIds[0]; + String userId = serviceIds[1]; + String userTunnelId = serviceIds[2]; + String type = serviceIds[3]; + + if (Objects.equals(type, "tcp")) { // 只处理TCP,避免重复处理 + Forward forward = forwardService.getById(forwardId); + if (forward == null) { + log.warn("删除孤立的服务: {} (节点: {})", service.getName(), nodeAddress); + GostUtil.DeleteService(nodeAddress, forwardId+"_"+userId+"_"+userTunnelId, node.getSecret()); + } + } + } + }, "清理服务 " + service.getName()); + } + } + + /** + * 清理孤立的链 + */ + private void cleanOrphanedChains(GostConfigDto gostConfig, Node node) { + if (gostConfig.getChains() == null) { + return; + } + + String nodeAddress = node.getIp() + ":" + node.getPort(); + + for (ConfigItem chain : gostConfig.getChains()) { + safeExecute(() -> { + String[] serviceIds = parseServiceName(chain.getName()); + if (serviceIds.length == 4) { + String forwardId = serviceIds[0]; + String userId = serviceIds[1]; + String userTunnelId = serviceIds[2]; + String type = serviceIds[3]; + + if (Objects.equals(type, "chains")) { + Forward forward = forwardService.getById(forwardId); + if (forward == null) { + log.warn("删除孤立的链: {} (节点: {})", chain.getName(), nodeAddress); + GostUtil.DeleteChains(nodeAddress, forwardId+"_"+userId+"_"+userTunnelId, node.getSecret()); + } + } + } + }, "清理链 " + chain.getName()); + } + } + + /** + * 清理孤立的限流器 + */ + private void cleanOrphanedLimiters(GostConfigDto gostConfig, Node node) { + if (gostConfig.getLimiters() == null) { + return; + } + + String nodeAddress = node.getIp() + ":" + node.getPort(); + + for (ConfigItem limiter : gostConfig.getLimiters()) { + safeExecute(() -> { + SpeedLimit speedLimit = speedLimitService.getById(limiter.getName()); + if (speedLimit == null) { + log.warn("删除孤立的限流器: {} (节点: {})", limiter.getName(), nodeAddress); + GostUtil.DeleteLimiters(nodeAddress, Long.parseLong(limiter.getName()), node.getSecret()); + } + }, "清理限流器 " + limiter.getName()); + } + } + + /** + * 安全执行操作,捕获异常 + */ + private void safeExecute(Runnable operation, String operationDesc) { + try { + operation.run(); + } catch (Exception e) { + log.error("执行操作失败: {}", operationDesc, e); + } + } + + /** + * 解析服务名称 + */ + private String[] parseServiceName(String serviceName) { + return serviceName.split("_"); + } +}