chainPortMap);
+
+ /**
+ * [实际完整流程] - 根据代理链生成XrayConfig配置文件和订阅信息文件
+ *
+ * Config配置会返回, 订阅不会返回
+ * Config和Subscribe都会被持久化,并且上传至OSS中,订阅地址为固定的地址
+ */
+ List ProxyChainUpdateProcedure(List proxyChainList, boolean isTopicName);
+
}
diff --git a/server/src/main/java/io/wdd/func/xray/service/XrayCoreServiceImpl.java b/server/src/main/java/io/wdd/func/xray/service/XrayCoreServiceImpl.java
index 6d29651..fcd7ace 100644
--- a/server/src/main/java/io/wdd/func/xray/service/XrayCoreServiceImpl.java
+++ b/server/src/main/java/io/wdd/func/xray/service/XrayCoreServiceImpl.java
@@ -10,13 +10,17 @@ import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.InboundConfigurationOb
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.VMESS;
import io.wdd.func.xray.beans.xray.protocol.outbound.Freedom;
import io.wdd.func.xray.beans.xray.protocol.outbound.OutboundConfigurationObject;
+import io.wdd.func.xray.beans.xray.share.VmessShare;
import io.wdd.func.xray.beans.xray.transport.InboundObject;
import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import io.wdd.func.xray.persisit.XrayDBOperator;
+import io.wdd.func.xray.persisit.XrayOssOperator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ObjectUtils;
+import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
@@ -28,8 +32,7 @@ import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.Inboun
import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.ListenAddress;
import static io.wdd.func.xray.beans.config.LogTemplateClass.LogTemplate;
import static io.wdd.func.xray.beans.config.OutboundVmessHTTPTemplateClass.*;
-import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_MAP;
-import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_TOPIC_NAME_MAP;
+import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.*;
import static io.wdd.func.xray.service.XrayConfigPersistor.*;
@Service
@@ -42,6 +45,38 @@ public class XrayCoreServiceImpl implements XrayCoreService {
@Resource
XrayDBOperator xrayDBOperator;
+ @Resource
+ XrayCallAgent xrayCallAgent;
+
+ @Resource
+ XrayOssOperator xrayOssOperator;
+
+ /**
+ * 根据全部的代理链,获取到 独立的节点Set
+ *
+ * @param allNetworkPathList
+ * @return
+ */
+ @NotNull
+ private static Set getAllProxyNodeSet(List> allNetworkPathList, boolean includeSubscribeNode) {
+ // 拿到所有的proxyNode
+ Set proxyNodeSet = allNetworkPathList
+ .stream()
+ .flatMap(
+ networkPathList -> networkPathList.stream()
+ )
+ .collect(Collectors.toSet());
+ // 增加虚拟节点
+ if (includeSubscribeNode) {
+ proxyNodeSet.add(
+ PROXY_NODE_TOPIC_NAME_MAP.get(
+ SUBSCRIBE_NODE_NAME
+ )
+ );
+ }
+ return proxyNodeSet;
+ }
+
@Override
public List> transformProxyChainString(List proxyChainList, boolean isTopicName) {
@@ -54,11 +89,19 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// 此处获取到的就是 每一个节点的名称
// AgentName 或者 AgentTopicName
agentKindOfName -> {
+ ProxyNode targetNode = null;
+
if (isTopicName) {
- return PROXY_NODE_TOPIC_NAME_MAP.get(agentKindOfName);
+ targetNode = PROXY_NODE_TOPIC_NAME_MAP.get(agentKindOfName);
} else {
- return PROXY_NODE_MAP.get(agentKindOfName);
+ targetNode = PROXY_NODE_MAP.get(agentKindOfName);
}
+
+ Assert.notNull(
+ targetNode,
+ "输入的代理链字符串有误! 请检查! => " + agentKindOfName
+ );
+ return targetNode;
}
)
.collect(Collectors.toList())
@@ -92,30 +135,60 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// HashMap resultMap = new HashMap<>();
// 清除tmp目录时候使用的一个锁
-
int currentVersion = cleanVersion.get();
+
+ // 记录每条代理链的端口号
+ HashMap chainPortMap = new HashMap<>();
+
+ // 需要事先清空缓存
+ manualUpdateProxyNodeListCache();
+
+ // 生成代理链
allNetworkPathList
.stream()
.forEach(
networkPathList -> {
+ // 为每一条链生成端口
int chainPort = XRAY_PORT_POOL.decrementAndGet();
+ // 为每条链生成相应的tag
+ // 形式为 Shanghai-amd64-01->Seoul-amd64-04
+ String chainTag = generatePathTag(networkPathList);
+
+ // 每条链单独生成Xray Config配置文件
generateXrayJsonSinglePath(
chainPort,
networkPathList,
- currentVersion
+ currentVersion,
+ chainTag
+ );
+
+ // 为每条代理链 缓存 对应端口
+ chainPortMap.put(
+ chainTag,
+ chainPort
);
}
);
+ // 生成订阅地址链接
+ List vmessShareList = generateSubscribeString(
+ allNetworkPathList,
+ chainPortMap
+ );
- // 拿到所有的proxyNode
- Set proxyNodeSet = allNetworkPathList
- .stream()
- .flatMap(
- networkPathList -> networkPathList.stream()
- )
- .collect(Collectors.toSet());
+ log.debug(
+ "vmessShareList is => {}",
+ vmessShareList
+ );
+
+ // 开始持久化订阅
+ xrayConfigPersistor.subPersist(vmessShareList);
+
+ Set proxyNodeSet = getAllProxyNodeSet(
+ allNetworkPathList,
+ true
+ );
// 返回所有的配置
return proxyNodeSet
@@ -139,13 +212,123 @@ public class XrayCoreServiceImpl implements XrayCoreService {
return PROXY_NODE_TOPIC_NAME_MAP;
}
- private void generateXrayJsonSinglePath(int chainPort, List networkPathList, int currentVersion) {
+ @Override
+ public List generateSubscribeString(List> allNetworkPathList, HashMap chainPortMap) {
+
+ // 运行到此时,说明配置文件已经生成了, 根据每条链生成订阅定西
+ return allNetworkPathList
+ .stream()
+ .map(
+ networkPathList -> {
+
+ // 每条链需要生成相应的唯一标识
+ String chainTag = generatePathTag(networkPathList);
+
+ // 拿到每条链的头节点
+ ProxyNode headNode = networkPathList.get(0);
+
+ List inboundObjectList = headNode
+ .getXrayConfigInfo()
+ .getXrayConfig()
+ .getInbounds();
+
+ VMESS realInboundObject = (VMESS) inboundObjectList
+ .stream()
+ .filter(
+ inboundObject -> inboundObject
+ .getPort()
+ .equals(
+ // 拿到每条链的唯一标识
+ chainPortMap.get(
+ chainTag
+ ))
+ )
+ .findFirst()
+ .get();
+
+ return convertInboundToShare(
+ realInboundObject,
+ headNode
+ );
+
+ }
+ )
+ .collect(Collectors.toList());
+
+ }
+
+ @Override
+ public List ProxyChainUpdateProcedure(List proxyChainList, boolean isTopicName) {
+
+ // 解析得到全部的节点
+ List> allProxyChainNodeList = this.transformProxyChainString(
+ proxyChainList,
+ isTopicName
+ );
+
+ // 生成所有的配置
+ List xrayConfigInfoList = this.generateXrayConfigFromNodeList(allProxyChainNodeList);
+
+ // 获取到全部的节点
+ Set allProxyNodeSet = getAllProxyNodeSet(
+ allProxyChainNodeList,
+ false
+ );
+
+ // 上传至OSS中
+ xrayOssOperator.uploadXrayConfigToOSS(allProxyNodeSet);
+ xrayOssOperator.uploadSubscribeFileToOSS();
+
+ // 执行Xray更新操作`
+ xrayCallAgent.buildXrayUpdateCommandAndCallAgent(allProxyNodeSet);
+
+
+ return xrayConfigInfoList;
+ }
+
+
+ /**
+ * 目前只进行 VMESS协议的转换
+ *
+ * @param realInboundObject
+ * @param headNode
+ * @return
+ */
+ private VmessShare convertInboundToShare(VMESS realInboundObject, ProxyNode headNode) {
+
+ // 通常这里只有一个配置
+ ClientObject clientObject = realInboundObject
+ .getSettings()
+ .getClients()
+ .get(0);
+
+
+ return VmessShare
+ .builder()
+ .v("2")
+ .ps(realInboundObject.getTag())
+ .add(headNode.getPublicIPv4())
+ .port(String.valueOf(realInboundObject.getPort()))
+ .id(clientObject.getId())
+ .aid(String.valueOf(clientObject.getAlterId()))
+ .scy("auto")
+ .net("tcp")
+ .type("http")
+ .host("www.baidu.com,www.google.com,www.bing.com,www.github.com")
+ .path("/news/,/finance/,/sports/,/weathers")
+ .tls("")
+ .sni("")
+ .alpn("")
+ .build();
+
+ }
+
+ private void generateXrayJsonSinglePath(int chainPort, List networkPathList, int currentVersion, String chainTag) {
int pathLength = networkPathList.size();
// 采用 VMESS + websocket的形式形成 链状代理
// 由于 Vlss+XTLS的形式形成 链状结构
- String tag = generatePathTag(networkPathList);
// 通用内容生成
String uuid = UUID
@@ -157,7 +340,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
.level(0)
// 为了进一步防止被探测,一个用户可以在主 ID 的基础上,再额外生成多个 ID。这里只需要指定额外的 ID 的数量,推荐值为 0 代表启用 VMessAEAD
.alterId(0)
- .email(tag + "@octopus.io")
+ .email(chainTag + "@octopus.io")
.build();
for (int pos = 0; pos < pathLength; pos++) {
@@ -166,7 +349,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// 构造 xrayConfig
XrayConfig xrayConfig = doBuildXrayConfig(
- tag,
+ chainTag,
clientObject,
chainPort,
networkPathList,
@@ -185,7 +368,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
}
- private XrayConfig doBuildXrayConfig(String tag, ClientObject clientObject, int chainPort, List networkPathList, int pos) {
+ private XrayConfig doBuildXrayConfig(String chainTag, ClientObject clientObject, int chainPort, List networkPathList, int pos) {
// 需要从现有的XrayConfig基础上进行生成
// 尝试从 缓存层获取
@@ -205,7 +388,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
xrayConfig,
clientObject,
chainPort,
- tag
+ chainTag
);
// 中间节点,需要有特定的输出
@@ -215,23 +398,23 @@ public class XrayCoreServiceImpl implements XrayCoreService {
networkPathList,
pos,
clientObject,
- tag,
+ chainTag,
chainPort
);
// 设置 路由信息
buildRouting(
xrayConfig,
- tag
+ chainTag
);
return xrayConfig;
}
- private void buildOutboundFree(XrayConfig xrayConfig, String tag) {
+ private void buildOutboundFree(XrayConfig xrayConfig, String chainTag) {
OutboundObject freeOut = new Freedom();
- freeOut.setTag(tag);
+ freeOut.setTag(chainTag);
xrayConfig.setOutbounds(new ArrayList<>(
List.of(freeOut)
@@ -239,7 +422,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
}
- private void buildRouting(XrayConfig xrayConfig, String tag) {
+ private void buildRouting(XrayConfig xrayConfig, String chainTag) {
// 从缓存中获取
RoutingObject routingObject = xrayConfig.getRouting();
@@ -252,8 +435,8 @@ public class XrayCoreServiceImpl implements XrayCoreService {
RuleObject ruleObject = RuleObject
.builder()
.type("field")
- .inboundTag(List.of(tag))
- .outboundTag(tag)
+ .inboundTag(List.of(chainTag))
+ .outboundTag(chainTag)
.build();
List ruleObjectList = routingObject.getRules();
@@ -265,7 +448,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
ruleObjectList.add(ruleObject);
}
- private void buildOutbound(XrayConfig xrayConfig, List networkPathList, int pos, ClientObject clientObject, String tag, Integer chainPort) {
+ private void buildOutbound(XrayConfig xrayConfig, List networkPathList, int pos, ClientObject clientObject, String chainTag, Integer chainPort) {
// 从缓存中获取
List outboundObjectList = xrayConfig.getOutbounds();
@@ -302,7 +485,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
}
// 设置Tag信息
- vmessOutbound.setTag(tag);
+ vmessOutbound.setTag(chainTag);
// 设置出口信息
OutboundConfigurationObject.ServerObject serverObject = vmessOutbound
@@ -325,7 +508,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
outboundObjectList.add(vmessOutbound);
}
- private void buildInbound(XrayConfig xrayConfig, ClientObject clientObject, Integer chainPort, String tag) {
+ private void buildInbound(XrayConfig xrayConfig, ClientObject clientObject, Integer chainPort, String chainTag) {
// 从缓存中获取
List inboundObjectList = xrayConfig.getInbounds();
@@ -345,7 +528,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
throw new RuntimeException(e);
}
- inboundObject.setTag(tag);
+ inboundObject.setTag(chainTag);
// todo port怎么办
inboundObject.setPort(chainPort);
@@ -365,7 +548,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
}
/**
- * shanghai->seoul2->tokyo2
+ * Shanghai-amd64-01->Seoul-amd64-04
*
* @param networkPathList 网络路径节点
* @return 路径Tag
@@ -377,7 +560,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
.stream()
.forEach(
networkPath -> {
- sb.append(networkPath.getName());
+ sb.append(networkPath.getAgentName());
sb.append("->");
}
);