[server][xary] - 完成实际Xray配置更新的全流程

This commit is contained in:
zeaslity
2023-03-03 14:01:48 +08:00
parent 606c77cb10
commit 0a5941a3ff
15 changed files with 769 additions and 225 deletions

View File

@@ -14,6 +14,14 @@
</list> </list>
</option> </option>
<option name="sourceFilePath" value="server/Dockerfile-shanghai-remote-idea"/> <option name="sourceFilePath" value="server/Dockerfile-shanghai-remote-idea"/>
<option name="volumeBindings">
<list>
<DockerVolumeBindingImpl>
<option name="containerPath" value="/octopus-server"/>
<option name="hostPath" value="/octopus-server"/>
</DockerVolumeBindingImpl>
</list>
</option>
</settings> </settings>
</deployment> </deployment>
<method v="2"> <method v="2">

View File

@@ -1,5 +1,7 @@
package io.wdd.common.utils; package io.wdd.common.utils;
import org.apache.commons.lang3.ObjectUtils;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -24,6 +26,15 @@ public class TimeUtils {
private static final Map<String, Long> times = new LinkedHashMap<>(); private static final Map<String, Long> times = new LinkedHashMap<>();
private static final String FULL_SPLIT_TIME_FORMAT = "yyyy-MM-dd-HH-mm-ss";
private static final String COMMON_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* 在五秒误差内的一个统一时间
*/
private static LocalDateTime UNIFORM_TIME;
static { static {
times.put( times.put(
"year", "year",
@@ -59,7 +70,7 @@ public class TimeUtils {
byte[] timeBytes = LocalDateTime byte[] timeBytes = LocalDateTime
.now(SYSTEM_TIME_ZONE_ID) .now(SYSTEM_TIME_ZONE_ID)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) .format(DateTimeFormatter.ofPattern(COMMON_TIME_FORMAT))
.getBytes(StandardCharsets.UTF_8); .getBytes(StandardCharsets.UTF_8);
return ByteBuffer.wrap(timeBytes); return ByteBuffer.wrap(timeBytes);
@@ -70,12 +81,34 @@ public class TimeUtils {
return LocalDateTime.now(SYSTEM_TIME_ZONE_ID); return LocalDateTime.now(SYSTEM_TIME_ZONE_ID);
} }
/**
* @return 获取五秒时间误差内的统一时间
*/
public static String UniformFormatTimeString() {
if (ObjectUtils.isEmpty(UNIFORM_TIME)) {
UNIFORM_TIME = currentTime();
return currentFormatTimeString();
}
// 旧的时间和新时间之家误差小于5秒那么使用同一个时间
if (UNIFORM_TIME
.plusSeconds(5)
.isAfter(currentTime())) {
UNIFORM_TIME = currentTime();
}
return localDateTimeFormatString(UNIFORM_TIME);
}
/** /**
* @return 格式化 去掉时间中的毫秒数 * @return 格式化 去掉时间中的毫秒数
*/ */
public static LocalDateTime currentFormatTime() { public static LocalDateTime currentFormatTime() {
DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern(COMMON_TIME_FORMAT);
String format = LocalDateTime String format = LocalDateTime
.now(SYSTEM_TIME_ZONE_ID) .now(SYSTEM_TIME_ZONE_ID)
@@ -92,7 +125,7 @@ public class TimeUtils {
public static String currentFormatTimeString() { public static String currentFormatTimeString() {
return currentFormatTime() return currentFormatTime()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")); .format(DateTimeFormatter.ofPattern(FULL_SPLIT_TIME_FORMAT));
} }
public static LocalDateTime cvFromDate(Date date) { public static LocalDateTime cvFromDate(Date date) {
@@ -113,7 +146,7 @@ public class TimeUtils {
return LocalDateTime return LocalDateTime
.now(SYSTEM_TIME_ZONE_ID) .now(SYSTEM_TIME_ZONE_ID)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); .format(DateTimeFormatter.ofPattern(COMMON_TIME_FORMAT));
} }
/** /**
@@ -123,13 +156,29 @@ public class TimeUtils {
return LocalDateTime return LocalDateTime
.now(SYSTEM_TIME_ZONE_ID) .now(SYSTEM_TIME_ZONE_ID)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")); .format(DateTimeFormatter.ofPattern(FULL_SPLIT_TIME_FORMAT));
} }
/**
* 输出格式为 COMMON_TIME_FORMAT "yyyy-MM-dd HH:mm:ss"
*
* @param time
* @return
*/
public static String localDateTimeString(LocalDateTime time) { public static String localDateTimeString(LocalDateTime time) {
return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); return time.format(DateTimeFormatter.ofPattern(COMMON_TIME_FORMAT));
}
/**
* 输出格式为 FULL_SPLIT_TIME_FORMAT "yyyy-MM-dd-HH-mm-ss"
*
* @param time
* @return
*/
public static String localDateTimeFormatString(LocalDateTime time) {
return time.format(DateTimeFormatter.ofPattern(FULL_SPLIT_TIME_FORMAT));
} }
public static String toRelative(long duration, int maxLevel) { public static String toRelative(long duration, int maxLevel) {

View File

@@ -7,14 +7,15 @@ import io.swagger.annotations.ApiParam;
import io.wdd.common.beans.response.R; import io.wdd.common.beans.response.R;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.XrayConfigInfo; import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.func.xray.service.XrayConfigDistribute; import io.wdd.func.xray.service.XrayCallAgent;
import io.wdd.func.xray.service.XrayCoreService; import io.wdd.func.xray.service.XrayCoreService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.*; import java.util.HashMap;
import java.util.List;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.*; import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_TOPIC_NAME_MAP;
@RestController @RestController
@RequestMapping("/server/func/xray") @RequestMapping("/server/func/xray")
@@ -25,7 +26,7 @@ public class XrayController {
XrayCoreService xrayCoreService; XrayCoreService xrayCoreService;
@Resource @Resource
XrayConfigDistribute xrayConfigDistribute; XrayCallAgent xrayCallAgent;
@PostMapping("/chain/transform") @PostMapping("/chain/transform")
@@ -47,7 +48,7 @@ public class XrayController {
} }
@PostMapping("/chain/debug") @PostMapping("/chain/debug")
@ApiOperation("[解析] - 代理链完整配置") @ApiOperation("[解析] - debug 代理链完整配置")
public R<List<XrayConfigInfo>> debugProxyChainString( public R<List<XrayConfigInfo>> debugProxyChainString(
@ApiParam(name = "proxyChainList", value = "代理链字符串seoul2->tokyo2, 多条链使用,分隔") @ApiParam(name = "proxyChainList", value = "代理链字符串seoul2->tokyo2, 多条链使用,分隔")
@RequestParam("proxyChainList") List<String> proxyChainList, @RequestParam("proxyChainList") List<String> proxyChainList,
@@ -65,6 +66,23 @@ public class XrayController {
); );
} }
@PostMapping("/chain/procedure")
@ApiOperation("[实际] - 代理链全流程配置上传下发")
public R<List<XrayConfigInfo>> ProxyChainUpdateProcedure(
@ApiParam(name = "proxyChainList", value = "代理链字符串seoul2->tokyo2, 多条链使用,分隔")
@RequestParam("proxyChainList") List<String> proxyChainList,
@ApiParam(name = "isTopicName", value = "是否使用AgentTopicName, 默认为AgentName")
@RequestParam(value = "isTopicName", required = false, defaultValue = "false") boolean isTopicName
) {
return R.ok(
xrayCoreService.ProxyChainUpdateProcedure(
proxyChainList,
isTopicName
)
);
}
@PostMapping("/cache/manual") @PostMapping("/cache/manual")
@ApiOperation("[缓存] - 手动更新代理链缓存") @ApiOperation("[缓存] - 手动更新代理链缓存")
public R<HashMap<String, ProxyNode>> manualUpdateProxyNodeListCache() { public R<HashMap<String, ProxyNode>> manualUpdateProxyNodeListCache() {
@@ -83,7 +101,7 @@ public class XrayController {
} }
@GetMapping("/test") /*@GetMapping("/test")
public void test() { public void test() {
List<List<ProxyNode>> allNetworkPathList = new ArrayList<>(); List<List<ProxyNode>> allNetworkPathList = new ArrayList<>();
@@ -132,11 +150,11 @@ public class XrayController {
xrayCoreService.generateXrayConfigFromNodeList(allNetworkPathList); xrayCoreService.generateXrayConfigFromNodeList(allNetworkPathList);
xrayConfigDistribute.uploadXrayConfigToOSS(allNetworkPathList.get(0)); xrayCallAgent.uploadXrayConfigToOSS(allNetworkPathList.get(0));
xrayConfigDistribute.buildXrayUpdateResult(allNetworkPathList.get(0)); xrayCallAgent.buildXrayUpdateResult(allNetworkPathList.get(0));
System.out.println("Xray controller test() 结束!"); System.out.println("Xray controller test() 结束!");
} }*/
} }

View File

@@ -33,7 +33,6 @@ public class OSSConfiguration {
*/ */
public static final List<OssConfig> ALL_OSS_CONFIG = new ArrayList<>(); public static final List<OssConfig> ALL_OSS_CONFIG = new ArrayList<>();
/** /**
* 初始数据 * 初始数据
*/ */

View File

@@ -1,6 +1,5 @@
package io.wdd.func.oss.service; package io.wdd.func.oss.service;
import com.amazonaws.services.s3.AmazonS3;
import io.wdd.func.oss.config.OssConfig; import io.wdd.func.oss.config.OssConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -14,13 +13,18 @@ import static io.wdd.func.oss.config.OSSConfiguration.ALL_OSS_CONFIG;
/** /**
* 对象存储后端选择 * 对象存储后端选择
* 指定一系列的策略选出最为合适的OSS存储后端位置 * 指定一系列的策略选出最为合适的OSS存储后端位置
*/ */
@Service @Service
@Slf4j @Slf4j
public class OssBackendSelect { public class OssBackendSelect {
public OssConfig one(String BackendPrefixName){ /**
* 根据 OSS桶的名称前缀 返回一个桶
* @param BackendPrefixName OSS桶的名称前缀
* @return
*/
public OssConfig one(String BackendPrefixName) {
if (StringUtils.isEmpty(BackendPrefixName)) { if (StringUtils.isEmpty(BackendPrefixName)) {
return oneRandom(); return oneRandom();
@@ -41,8 +45,10 @@ public class OssBackendSelect {
// 随机选择一个, 也算是一个算法吧 // 随机选择一个, 也算是一个算法吧
Random random = new Random(); Random random = new Random();
int pos = random int pos = random
.ints(0, .ints(
ossConfigList.size()) 0,
ossConfigList.size()
)
.findFirst() .findFirst()
.getAsInt(); .getAsInt();
@@ -50,20 +56,31 @@ public class OssBackendSelect {
return ossConfigList.get(pos); return ossConfigList.get(pos);
} }
/**
* @return 返回 随意一个桶
*/
public OssConfig oneRandom() { public OssConfig oneRandom() {
Random random = new Random(); Random random = new Random();
int pos = random int pos = random
.ints(0, .ints(
ALL_OSS_CONFIG.size()) 0,
ALL_OSS_CONFIG.size()
)
.findFirst() .findFirst()
.getAsInt(); .getAsInt();
return ALL_OSS_CONFIG.get(pos); return ALL_OSS_CONFIG.get(pos);
} }
public List<OssConfig> all(String BackendPrefixName){ /**
* 根据 OSS桶的名称前缀 返回所有的桶
*
* @param BackendPrefixName OSS桶的名称前缀
* @return
*/
public List<OssConfig> all(String BackendPrefixName) {
return ALL_OSS_CONFIG return ALL_OSS_CONFIG
.stream() .stream()

View File

@@ -35,7 +35,7 @@ public class TcpHttpHeaderTemplate {
"/news/", "/news/",
"/finance/", "/finance/",
"/sports/", "/sports/",
"weathers" "/weathers"
); );

View File

@@ -0,0 +1,43 @@
package io.wdd.func.xray.beans.xray.share;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@NoArgsConstructor
@Data
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public class VmessShare {
@JsonProperty("v")
private String v;
@JsonProperty("ps")
private String ps;
@JsonProperty("add")
private String add;
@JsonProperty("port")
private String port;
@JsonProperty("id")
private String id;
@JsonProperty("aid")
private String aid;
@JsonProperty("scy")
private String scy;
@JsonProperty("net")
private String net;
@JsonProperty("type")
private String type;
@JsonProperty("host")
private String host;
@JsonProperty("path")
private String path;
@JsonProperty("tls")
private String tls;
@JsonProperty("sni")
private String sni;
@JsonProperty("alpn")
private String alpn;
}

View File

@@ -4,7 +4,6 @@ import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.ProxyNodeType; import io.wdd.func.xray.beans.node.ProxyNodeType;
import io.wdd.func.xray.beans.node.XrayConfigInfo; import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.server.beans.vo.ServerInfoVO; import io.wdd.server.beans.vo.ServerInfoVO;
import io.wdd.server.coreService.CoreAppService;
import io.wdd.server.coreService.CoreServerService; import io.wdd.server.coreService.CoreServerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -29,8 +28,6 @@ public class XrayDBOperator {
@Resource @Resource
CoreServerService coreServerService; CoreServerService coreServerService;
@Resource
CoreAppService coreAppService;
@PostConstruct @PostConstruct
public void cache() { public void cache() {
@@ -50,7 +47,6 @@ public class XrayDBOperator {
transferServerInfoToProxyNode(serverInfoVOList); transferServerInfoToProxyNode(serverInfoVOList);
} }
private void transferServerInfoToProxyNode(List<ServerInfoVO> serverInfoVOList) { private void transferServerInfoToProxyNode(List<ServerInfoVO> serverInfoVOList) {
@@ -141,6 +137,16 @@ public class XrayDBOperator {
} }
); );
// 缓存订阅虚拟节点
ProxyNode subscribeProxyNode = buildSubscribeProxyNode();
PROXY_NODE_MAP.put(
subscribeProxyNode.getName(),
subscribeProxyNode
);
PROXY_NODE_TOPIC_NAME_MAP.put(
subscribeProxyNode.getName(),
subscribeProxyNode
);
//help gc //help gc
bitmap = null; bitmap = null;
@@ -148,6 +154,17 @@ public class XrayDBOperator {
} }
private ProxyNode buildSubscribeProxyNode() {
return ProxyNode
.builder()
.name(SUBSCRIBE_NODE_NAME)
.num(0)
.agentName("subscribe-virtual-node")
.xrayConfigInfo(new XrayConfigInfo())
.build();
}
private ProxyNodeType convertNodeType(Integer proxyType) { private ProxyNodeType convertNodeType(Integer proxyType) {
if (null == proxyType) { if (null == proxyType) {

View File

@@ -0,0 +1,115 @@
package io.wdd.func.xray.persisit;
import io.wdd.common.handler.MyRuntimeException;
import io.wdd.func.oss.config.OctopusObjectSummary;
import io.wdd.func.oss.config.OssConfig;
import io.wdd.func.oss.service.OSSCoreService;
import io.wdd.func.oss.service.OssBackendSelect;
import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.XrayConfigInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_MAP;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.SUBSCRIBE_NODE_NAME;
@Service
@Slf4j
public class XrayOssOperator {
/**
* 订阅文件实际存储的桶的名称
* 实际为 Oracle-Seoul-2 下面的桶
*/
private static final String SUBSCRIBE_OSS_BUCKET_PREFIX = "seoul";
@Resource
OssBackendSelect ossBackendSelect;
@Resource
OSSCoreService ossCoreService;
/**
* 为代理链的每一个节点 上传配置文件到OSS中
*
* @param allProxyNodeList
*/
public void uploadXrayConfigToOSS(Collection<ProxyNode> allProxyNodeList) {
// 所有的文件全部存储至一个对象存储的后端中
OssConfig ossConfig = ossBackendSelect.oneRandom();
log.info(
"[Xray] 开始上传所有的xray config 至对象存储中 => [{}]",
ossConfig.getName() + "-" + ossConfig.getRegion()
);
// 依次存储所有的config文件
allProxyNodeList
.stream()
.forEach(
node -> {
XrayConfigInfo xrayConfigInfo = node.getXrayConfigInfo();
// 上传OSS
OctopusObjectSummary octopusObjectSummary = ossCoreService
.createObject(
ossConfig,
xrayConfigInfo.getXrayConfigFileName(),
xrayConfigInfo.getXrayConfigFile()
);
// 设置oss的相关信息
xrayConfigInfo.setObjectSummary(octopusObjectSummary);
}
);
}
/**
* 上传 订阅文件信息 件到OSS
*
* @return
*/
public XrayConfigInfo uploadSubscribeFileToOSS() {
XrayConfigInfo subscribeXrayConfigInfo = PROXY_NODE_MAP
.get(SUBSCRIBE_NODE_NAME).
getXrayConfigInfo();
// 存储到特定的桶中
OssConfig ossConfig = ossBackendSelect.one(SUBSCRIBE_OSS_BUCKET_PREFIX);
log.debug(
"开始存储 Xray订阅文件 [ {} ] 至OSS [ {} ]中",
subscribeXrayConfigInfo,
ossConfig
);
// 删除旧的订阅信息
boolean deleteObject = ossCoreService.deleteObject(
ossConfig,
SUBSCRIBE_OSS_BUCKET_PREFIX,
subscribeXrayConfigInfo.getXrayConfigFileName()
);
if (!deleteObject) {
log.error(
"删除旧的订阅信息失败! 请检查桶 => [{}]",
ossConfig
);
throw new MyRuntimeException();
}
// 上传新的订阅信息
OctopusObjectSummary objectSummary = ossCoreService.createObject(
ossConfig,
SUBSCRIBE_OSS_BUCKET_PREFIX,
subscribeXrayConfigInfo.getXrayConfigFile()
);
subscribeXrayConfigInfo.setObjectSummary(objectSummary);
return subscribeXrayConfigInfo;
}
}

View File

@@ -1,84 +1,80 @@
package io.wdd.func.xray.persisit.cache; package io.wdd.func.xray.persisit.cache;
import io.wdd.func.xray.beans.node.Edge; //public class EdgeWeightCache {
//
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.*; //
// public static Edge chengduToShanghai;
public class EdgeWeightCache { //
// public static Edge shanghaiToSeoul2;
// public static Edge shanghaiToTokyo2;
public static Edge chengduToShanghai; //
// public static Edge hongkongToSeoul2;
public static Edge shanghaiToSeoul2; // public static Edge hongkongToTokyo2;
public static Edge shanghaiToTokyo2; // public static Edge hongkongToPhoenix2;
//
public static Edge hongkongToSeoul2; // public static Edge seoul2ToTokyo2;
public static Edge hongkongToTokyo2; // public static Edge seoul2ToPhoenix2;
public static Edge hongkongToPhoenix2; // public static Edge seoul2ToLondon2;
//
public static Edge seoul2ToTokyo2; // public static Edge tokyo2ToPhoenix2;
public static Edge seoul2ToPhoenix2; // public static Edge tokyo2ToLondon2;
public static Edge seoul2ToLondon2; //
// /**
public static Edge tokyo2ToPhoenix2; // * 计算 网络路径中的路径权重
public static Edge tokyo2ToLondon2; // * 值的范围在0-100,数字越小表示阻力越小
// * 指标 1.延迟 2.丢包率 3.带宽 4.节点稳定性
/** // */
* 计算 网络路径中的路径权重 // public void EdgeWeightCalculate(){
* 值的范围在0-100,数字越小表示阻力越小 //
* 指标 1.延迟 2.丢包率 3.带宽 4.节点稳定性 //
*/ //
public void EdgeWeightCalculate(){ // }
//
// static {
//
} // chengduToShanghai = new Edge(
// chengdu,
static { // shanghai,
// 10
chengduToShanghai = new Edge( // );
chengdu, //
shanghai, // shanghaiToSeoul2 = new Edge(
10 // shanghai,
); // seoul2,
// 40
shanghaiToSeoul2 = new Edge( // );
shanghai, //
seoul2, // shanghaiToTokyo2 = new Edge(
40 // shanghai,
); // tokyo2,
// 60
shanghaiToTokyo2 = new Edge( // );
shanghai, //
tokyo2, // seoul2ToTokyo2 = new Edge(
60 // seoul2,
); // tokyo2,
// 10
seoul2ToTokyo2 = new Edge( // );
seoul2, // tokyo2ToPhoenix2 = new Edge(
tokyo2, // tokyo2,
10 // phoenix2,
); // 30
tokyo2ToPhoenix2 = new Edge( // );
tokyo2, // tokyo2ToLondon2 = new Edge(
phoenix2, // tokyo2,
30 // london2,
); // 50
tokyo2ToLondon2 = new Edge( // );
tokyo2, // hongkongToTokyo2 = new Edge(
london2, // hongkong,
50 // tokyo2,
); // 40
hongkongToTokyo2 = new Edge( // );
hongkong, // hongkongToSeoul2 = new Edge(
tokyo2, // hongkong,
40 // seoul2,
); // 20
hongkongToSeoul2 = new Edge( // );
hongkong, //
seoul2, // }
20 //}
);
}
}

View File

@@ -1,7 +1,6 @@
package io.wdd.func.xray.persisit.cache; package io.wdd.func.xray.persisit.cache;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.ProxyNodeType;
import java.util.HashMap; import java.util.HashMap;
@@ -20,21 +19,26 @@ public class ProxyNodeCache {
public static final HashMap<Integer, ProxyNode> PROXY_NODE_INDEX_MAP = new HashMap<>(); public static final HashMap<Integer, ProxyNode> PROXY_NODE_INDEX_MAP = new HashMap<>();
public static ProxyNode chengdu; /**
public static ProxyNode shanghai; * 订阅信息的虚拟节点,用于存储订阅内容的信息
public static ProxyNode hongkong; */
public static ProxyNode seoul2; public static final String SUBSCRIBE_NODE_NAME = "SUBSCRIBE";
public static ProxyNode tokyo2;
public static ProxyNode phoenix2;
public static ProxyNode london2;
// 开发使用 private static ProxyNode chengdu;
public static ProxyNode chengduAgent; private static ProxyNode shanghai;
public static ProxyNode tokyoDev; private static ProxyNode hongkong;
public static ProxyNode seoul5; private static ProxyNode seoul2;
private static ProxyNode tokyo2;
private static ProxyNode phoenix2;
private static ProxyNode london2;
static { private static ProxyNode chengduAgent;
private static ProxyNode tokyoDev;
private static ProxyNode seoul5;
/*static {
chengdu = ProxyNode chengdu = ProxyNode
.builder() .builder()
@@ -185,6 +189,6 @@ public class ProxyNodeCache {
seoul5 seoul5
); );
} }*/
} }

View File

@@ -2,11 +2,7 @@ package io.wdd.func.xray.service;
import io.wdd.common.utils.TimeUtils; import io.wdd.common.utils.TimeUtils;
import io.wdd.func.oss.config.OctopusObjectSummary; import io.wdd.func.oss.config.OctopusObjectSummary;
import io.wdd.func.oss.config.OssConfig;
import io.wdd.func.oss.service.OSSCoreService;
import io.wdd.func.oss.service.OssBackendSelect;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.rpc.execute.service.AsyncExecutionService; import io.wdd.rpc.execute.service.AsyncExecutionService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -14,6 +10,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -27,7 +24,7 @@ import java.util.stream.Collectors;
*/ */
@Service @Service
@Slf4j @Slf4j
public class XrayConfigDistribute { public class XrayCallAgent {
/** /**
* 存储更新 Xray的命令行 * 存储更新 Xray的命令行
@@ -41,24 +38,6 @@ public class XrayConfigDistribute {
static { static {
/*ArrayList<String> zero = new ArrayList<>(
List.of(
"if",
"[",
"!",
"-f",
"/usr/local/etc/xray/config.json",
"]",
";",
"then",
"touch",
"/usr/local/etc/xray/config.json",
";",
"fi"
)
);*/
ArrayList<String> first = new ArrayList<>( ArrayList<String> first = new ArrayList<>(
List.of( List.of(
"mv", "mv",
@@ -70,7 +49,7 @@ public class XrayConfigDistribute {
ArrayList<String> second = new ArrayList<>( ArrayList<String> second = new ArrayList<>(
List.of( List.of(
"wget", "wget",
"url", "AGENT_SPECIFIC_CONFIG_URL",
"-O", "-O",
"/usr/local/etc/xray/config.json" "/usr/local/etc/xray/config.json"
) )
@@ -96,7 +75,6 @@ public class XrayConfigDistribute {
) )
); );
updateXrayCommandList.add(first); updateXrayCommandList.add(first);
updateXrayCommandList.add(second); updateXrayCommandList.add(second);
updateXrayCommandList.add(third); updateXrayCommandList.add(third);
@@ -104,49 +82,17 @@ public class XrayConfigDistribute {
} }
@Resource
OssBackendSelect ossBackendSelect;
@Resource
OSSCoreService ossCoreService;
@Resource @Resource
AsyncExecutionService executionService; AsyncExecutionService executionService;
public void uploadXrayConfigToOSS(List<ProxyNode> networkPathList) { /**
* 为代理链的每一个节点 构建Xray配置更新命令然后发送至对应的Agent中
// 所有的文件全部存储至一个对象存储的后端中 */
OssConfig ossConfig = ossBackendSelect.oneRandom(); public void buildXrayUpdateCommandAndCallAgent(Collection<ProxyNode> allProxyNodeList) {
log.info(
"[Xray] 开始上传所有的xray config 至对象存储中 => [{}]",
ossConfig.getName() + "-" + ossConfig.getRegion()
);
// 依次存储所有的config文件
networkPathList
.stream()
.forEach(
node -> {
XrayConfigInfo xrayConfigInfo = node.getXrayConfigInfo();
// 上传OSS
OctopusObjectSummary octopusObjectSummary = ossCoreService
.createObject(
ossConfig,
xrayConfigInfo.getXrayConfigFileName(),
xrayConfigInfo.getXrayConfigFile()
);
// 设置oss的相关信息
xrayConfigInfo.setObjectSummary(octopusObjectSummary);
}
);
}
public void buildXrayUpdateResult(List<ProxyNode> networkPathList) {
String formatTimeString = TimeUtils.currentFormatTimeString(); String formatTimeString = TimeUtils.currentFormatTimeString();
List<String> resultKeyList = networkPathList List<String> resultKeyList = allProxyNodeList
.stream() .stream()
.map( .map(
proxyNode -> { proxyNode -> {
@@ -190,7 +136,9 @@ public class XrayConfigDistribute {
updateCommandType, updateCommandType,
null, null,
updateXrayCommandList, updateXrayCommandList,
null false,
null,
false
); );
return resultKey; return resultKey;
@@ -199,7 +147,7 @@ public class XrayConfigDistribute {
.collect(Collectors.toList()); .collect(Collectors.toList());
log.info( log.info(
"发送所有的配置到各个Agent成功 结果查看为 => {}", "为代理链的每一个节点 构建Xray配置更新命令然后发送至对应的Agent成功, 结果查看为 => {}",
resultKeyList resultKeyList
); );

View File

@@ -8,10 +8,10 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.ObjectWriter;
import io.wdd.common.handler.MyRuntimeException; import io.wdd.common.handler.MyRuntimeException;
import io.wdd.common.utils.TimeUtils;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.XrayConfigInfo; import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.func.xray.beans.xray.XrayConfig; import io.wdd.func.xray.beans.xray.XrayConfig;
import io.wdd.func.xray.beans.xray.share.VmessShare;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
@@ -22,7 +22,15 @@ import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static io.wdd.common.utils.TimeUtils.UniformFormatTimeString;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_MAP;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.SUBSCRIBE_NODE_NAME;
/** /**
* 获取rerouces目录 https://blog.csdn.net/pengpengpeng85/article/details/84785575 * 获取rerouces目录 https://blog.csdn.net/pengpengpeng85/article/details/84785575
@@ -34,6 +42,10 @@ import java.util.concurrent.atomic.AtomicInteger;
@Service @Service
public class XrayConfigPersistor { public class XrayConfigPersistor {
/**
* XRAY端口的起始位置
*/
public static final int XRAY_PORT_MAX = 20000;
// 参考 https://github.com/FasterXML/jackson-databind/issues/585 // 参考 https://github.com/FasterXML/jackson-databind/issues/585
private static final ObjectWriter objectWriter = new ObjectMapper() private static final ObjectWriter objectWriter = new ObjectMapper()
// 忽略掉 null的字段 // 忽略掉 null的字段
@@ -46,10 +58,11 @@ public class XrayConfigPersistor {
.withLinefeed("\n") .withLinefeed("\n")
)); ));
private static final String XrayResultPathPrefix = "xrayResult/"; private static final String XrayResultPathPrefix = "xrayResult/";
/** /**
* XRAY端口的起始位置 * 存储在对象存储中的订阅文件的名称
*/ */
public static final int XRAY_PORT_MAX = 20000; public static final String SUBSCRIBE_FILE_OSS_NAME = "99-subscribe-octopus-latest.txt";
/** /**
* 存储生成的Xray Config的临时文件目录 * 存储生成的Xray Config的临时文件目录
*/ */
@@ -94,6 +107,7 @@ public class XrayConfigPersistor {
} }
} }
/** /**
* 执行Xray生成配置文件的持久化工作,沈成伟临时文件保存至当前目录中 * 执行Xray生成配置文件的持久化工作,沈成伟临时文件保存至当前目录中
* *
@@ -117,7 +131,7 @@ public class XrayConfigPersistor {
.writeValueAsString(xrayConfig); .writeValueAsString(xrayConfig);
// 获得到文件名称 // 获得到文件名称
String timeString = TimeUtils.currentFormatTimeString(); String timeString = UniformFormatTimeString();
String fileName = buildXrayConfigFileName( String fileName = buildXrayConfigFileName(
proxyNode, proxyNode,
timeString timeString
@@ -144,12 +158,118 @@ public class XrayConfigPersistor {
} }
} }
public void subPersist(List<VmessShare> vmessShareList) {
Base64.Encoder encoder = Base64.getEncoder();
List<String> subscribeStringList = vmessShareList
.stream()
.map(
vmessShare -> {
try {
byte[] vmessShareBytes = objectWriter.writeValueAsBytes(vmessShare);
return "vmess://" + new String(
encoder.encode(vmessShareBytes),
StandardCharsets.UTF_8
);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
)
.collect(Collectors.toList());
// 实际进行文件的写入
File subscribeFile = subWrite(
SUBSCRIBE_FILE_OSS_NAME,
subscribeStringList
);
// 存储相应的信息
ProxyNode subscribeNode = PROXY_NODE_MAP.get(SUBSCRIBE_NODE_NAME);
XrayConfigInfo xrayConfigInfo = subscribeNode.getXrayConfigInfo();
xrayConfigInfo.setXrayConfigFile(subscribeFile);
xrayConfigInfo.setXrayConfigFileName(SUBSCRIBE_FILE_OSS_NAME);
}
private String buildXrayConfigFileName(ProxyNode proxyNode, String timeString) { private String buildXrayConfigFileName(ProxyNode proxyNode, String timeString) {
return proxyNode.getNum() + "-" + proxyNode.getAgentName() + "-" + timeString + ".json"; return proxyNode.getNum() + "-" + proxyNode.getAgentName() + "-" + timeString + ".json";
} }
/**
* 将订阅信息写入到文件中, 每一行写一个
* 由于订阅信息的生成一定是晚于代理链的,所以不进行清理工作
*
* @param fileName
* @return
*/
private File subWrite(String fileName, List<String> subsribeList) {
// 构造对象开始写入, 生成文件
File resultFile = getResultFile(fileName);
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try {
log.debug(
"开始写入 Subscribe 进入文件中,文件名为 => {}",
fileName
);
fileWriter = new FileWriter(
resultFile
);
bufferedWriter = new BufferedWriter(
fileWriter
);
for (String subsribeString : subsribeList) {
// 每一行写一个
bufferedWriter.write(subsribeString);
bufferedWriter.newLine();
}
return resultFile;
} catch (IOException e) {
log.error(
"打开文件失败写入tmp文件失败 文件为 => {}",
resultFile.getName()
);
throw new MyRuntimeException(e);
} finally {
try {
// must close
bufferedWriter.close();
fileWriter.close();
} catch (IOException e) {
log.error(
"关闭文件写入流失败!, 请检查 文件为 => [ {} ], 内容为 => {}",
fileName,
subsribeList
);
throw new MyRuntimeException(e);
}
}
}
private File write(String fileName, String content, int currentVersion) { private File write(String fileName, String content, int currentVersion) {
log.debug( log.debug(

View File

@@ -2,12 +2,14 @@ package io.wdd.func.xray.service;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.XrayConfigInfo; import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.func.xray.beans.xray.share.VmessShare;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
public interface XrayCoreService { public interface XrayCoreService {
/** /**
* 解析代理链字符串,返回完整的代理列表 * 解析代理链字符串,返回完整的代理列表
* *
@@ -18,6 +20,14 @@ public interface XrayCoreService {
List<List<ProxyNode>> transformProxyChainString(List<String> proxyChainList, boolean isTopicName); List<List<ProxyNode>> transformProxyChainString(List<String> proxyChainList, boolean isTopicName);
/**
* 根据代理链生成XrayConfig配置文件和订阅信息文件
* Config配置会返回 订阅不会返回
* Config和Subscribe都会被持久化并且上传至OSS中订阅地址为固定的地址
*
* @param allNetworkPathList 完整的代理链
* @return
*/
List<XrayConfigInfo> generateXrayConfigFromNodeList(List<List<ProxyNode>> allNetworkPathList); List<XrayConfigInfo> generateXrayConfigFromNodeList(List<List<ProxyNode>> allNetworkPathList);
@@ -28,4 +38,21 @@ public interface XrayCoreService {
*/ */
HashMap<String, ProxyNode> manualUpdateProxyNodeListCache(); HashMap<String, ProxyNode> manualUpdateProxyNodeListCache();
/**
* 根据代理链的配置生成订阅地址
*
* @param allNetworkPathList
* @param chainPortMap
*/
List<VmessShare> generateSubscribeString(List<List<ProxyNode>> allNetworkPathList, HashMap<String, Integer> chainPortMap);
/**
* [实际完整流程] - 根据代理链生成XrayConfig配置文件和订阅信息文件
* <p>
* Config配置会返回 订阅不会返回
* Config和Subscribe都会被持久化并且上传至OSS中订阅地址为固定的地址
*/
List<XrayConfigInfo> ProxyChainUpdateProcedure(List<String> proxyChainList, boolean isTopicName);
} }

View File

@@ -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.inbound.vmess.VMESS;
import io.wdd.func.xray.beans.xray.protocol.outbound.Freedom; 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.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.InboundObject;
import io.wdd.func.xray.beans.xray.transport.OutboundObject; import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import io.wdd.func.xray.persisit.XrayDBOperator; import io.wdd.func.xray.persisit.XrayDBOperator;
import io.wdd.func.xray.persisit.XrayOssOperator;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; 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.InboundVmessHTTPTemplateClass.ListenAddress;
import static io.wdd.func.xray.beans.config.LogTemplateClass.LogTemplate; 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.beans.config.OutboundVmessHTTPTemplateClass.*;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_MAP; import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.*;
import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.PROXY_NODE_TOPIC_NAME_MAP;
import static io.wdd.func.xray.service.XrayConfigPersistor.*; import static io.wdd.func.xray.service.XrayConfigPersistor.*;
@Service @Service
@@ -42,6 +45,38 @@ public class XrayCoreServiceImpl implements XrayCoreService {
@Resource @Resource
XrayDBOperator xrayDBOperator; XrayDBOperator xrayDBOperator;
@Resource
XrayCallAgent xrayCallAgent;
@Resource
XrayOssOperator xrayOssOperator;
/**
* 根据全部的代理链,获取到 独立的节点Set
*
* @param allNetworkPathList
* @return
*/
@NotNull
private static Set<ProxyNode> getAllProxyNodeSet(List<List<ProxyNode>> allNetworkPathList, boolean includeSubscribeNode) {
// 拿到所有的proxyNode
Set<ProxyNode> 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 @Override
public List<List<ProxyNode>> transformProxyChainString(List<String> proxyChainList, boolean isTopicName) { public List<List<ProxyNode>> transformProxyChainString(List<String> proxyChainList, boolean isTopicName) {
@@ -54,11 +89,19 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// 此处获取到的就是 每一个节点的名称 // 此处获取到的就是 每一个节点的名称
// AgentName 或者 AgentTopicName // AgentName 或者 AgentTopicName
agentKindOfName -> { agentKindOfName -> {
ProxyNode targetNode = null;
if (isTopicName) { if (isTopicName) {
return PROXY_NODE_TOPIC_NAME_MAP.get(agentKindOfName); targetNode = PROXY_NODE_TOPIC_NAME_MAP.get(agentKindOfName);
} else { } else {
return PROXY_NODE_MAP.get(agentKindOfName); targetNode = PROXY_NODE_MAP.get(agentKindOfName);
} }
Assert.notNull(
targetNode,
"输入的代理链字符串有误! 请检查! => " + agentKindOfName
);
return targetNode;
} }
) )
.collect(Collectors.toList()) .collect(Collectors.toList())
@@ -92,30 +135,60 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// HashMap<ProxyNode, XrayConfig> resultMap = new HashMap<>(); // HashMap<ProxyNode, XrayConfig> resultMap = new HashMap<>();
// 清除tmp目录时候使用的一个锁 // 清除tmp目录时候使用的一个锁
int currentVersion = cleanVersion.get(); int currentVersion = cleanVersion.get();
// 记录每条代理链的端口号
HashMap<String, Integer> chainPortMap = new HashMap<>();
// 需要事先清空缓存
manualUpdateProxyNodeListCache();
// 生成代理链
allNetworkPathList allNetworkPathList
.stream() .stream()
.forEach( .forEach(
networkPathList -> { networkPathList -> {
// 为每一条链生成端口
int chainPort = XRAY_PORT_POOL.decrementAndGet(); int chainPort = XRAY_PORT_POOL.decrementAndGet();
// 为每条链生成相应的tag
// 形式为 Shanghai-amd64-01->Seoul-amd64-04
String chainTag = generatePathTag(networkPathList);
// 每条链单独生成Xray Config配置文件
generateXrayJsonSinglePath( generateXrayJsonSinglePath(
chainPort, chainPort,
networkPathList, networkPathList,
currentVersion currentVersion,
chainTag
);
// 为每条代理链 缓存 对应端口
chainPortMap.put(
chainTag,
chainPort
); );
} }
); );
// 生成订阅地址链接
List<VmessShare> vmessShareList = generateSubscribeString(
allNetworkPathList,
chainPortMap
);
// 拿到所有的proxyNode log.debug(
Set<ProxyNode> proxyNodeSet = allNetworkPathList "vmessShareList is => {}",
.stream() vmessShareList
.flatMap( );
networkPathList -> networkPathList.stream()
) // 开始持久化订阅
.collect(Collectors.toSet()); xrayConfigPersistor.subPersist(vmessShareList);
Set<ProxyNode> proxyNodeSet = getAllProxyNodeSet(
allNetworkPathList,
true
);
// 返回所有的配置 // 返回所有的配置
return proxyNodeSet return proxyNodeSet
@@ -139,13 +212,123 @@ public class XrayCoreServiceImpl implements XrayCoreService {
return PROXY_NODE_TOPIC_NAME_MAP; return PROXY_NODE_TOPIC_NAME_MAP;
} }
private void generateXrayJsonSinglePath(int chainPort, List<ProxyNode> networkPathList, int currentVersion) { @Override
public List<VmessShare> generateSubscribeString(List<List<ProxyNode>> allNetworkPathList, HashMap<String, Integer> chainPortMap) {
// 运行到此时,说明配置文件已经生成了, 根据每条链生成订阅定西
return allNetworkPathList
.stream()
.map(
networkPathList -> {
// 每条链需要生成相应的唯一标识
String chainTag = generatePathTag(networkPathList);
// 拿到每条链的头节点
ProxyNode headNode = networkPathList.get(0);
List<InboundObject> 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<XrayConfigInfo> ProxyChainUpdateProcedure(List<String> proxyChainList, boolean isTopicName) {
// 解析得到全部的节点
List<List<ProxyNode>> allProxyChainNodeList = this.transformProxyChainString(
proxyChainList,
isTopicName
);
// 生成所有的配置
List<XrayConfigInfo> xrayConfigInfoList = this.generateXrayConfigFromNodeList(allProxyChainNodeList);
// 获取到全部的节点
Set<ProxyNode> 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<ProxyNode> networkPathList, int currentVersion, String chainTag) {
int pathLength = networkPathList.size(); int pathLength = networkPathList.size();
// 采用 VMESS + websocket的形式形成 链状代理 // 采用 VMESS + websocket的形式形成 链状代理
// 由于 Vlss+XTLS的形式形成 链状结构 // 由于 Vlss+XTLS的形式形成 链状结构
String tag = generatePathTag(networkPathList);
// 通用内容生成 // 通用内容生成
String uuid = UUID String uuid = UUID
@@ -157,7 +340,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
.level(0) .level(0)
// 为了进一步防止被探测,一个用户可以在主 ID 的基础上,再额外生成多个 ID。这里只需要指定额外的 ID 的数量,推荐值为 0 代表启用 VMessAEAD // 为了进一步防止被探测,一个用户可以在主 ID 的基础上,再额外生成多个 ID。这里只需要指定额外的 ID 的数量,推荐值为 0 代表启用 VMessAEAD
.alterId(0) .alterId(0)
.email(tag + "@octopus.io") .email(chainTag + "@octopus.io")
.build(); .build();
for (int pos = 0; pos < pathLength; pos++) { for (int pos = 0; pos < pathLength; pos++) {
@@ -166,7 +349,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
// 构造 xrayConfig // 构造 xrayConfig
XrayConfig xrayConfig = doBuildXrayConfig( XrayConfig xrayConfig = doBuildXrayConfig(
tag, chainTag,
clientObject, clientObject,
chainPort, chainPort,
networkPathList, networkPathList,
@@ -185,7 +368,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
} }
private XrayConfig doBuildXrayConfig(String tag, ClientObject clientObject, int chainPort, List<ProxyNode> networkPathList, int pos) { private XrayConfig doBuildXrayConfig(String chainTag, ClientObject clientObject, int chainPort, List<ProxyNode> networkPathList, int pos) {
// 需要从现有的XrayConfig基础上进行生成 // 需要从现有的XrayConfig基础上进行生成
// 尝试从 缓存层获取 // 尝试从 缓存层获取
@@ -205,7 +388,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
xrayConfig, xrayConfig,
clientObject, clientObject,
chainPort, chainPort,
tag chainTag
); );
// 中间节点,需要有特定的输出 // 中间节点,需要有特定的输出
@@ -215,23 +398,23 @@ public class XrayCoreServiceImpl implements XrayCoreService {
networkPathList, networkPathList,
pos, pos,
clientObject, clientObject,
tag, chainTag,
chainPort chainPort
); );
// 设置 路由信息 // 设置 路由信息
buildRouting( buildRouting(
xrayConfig, xrayConfig,
tag chainTag
); );
return xrayConfig; return xrayConfig;
} }
private void buildOutboundFree(XrayConfig xrayConfig, String tag) { private void buildOutboundFree(XrayConfig xrayConfig, String chainTag) {
OutboundObject freeOut = new Freedom(); OutboundObject freeOut = new Freedom();
freeOut.setTag(tag); freeOut.setTag(chainTag);
xrayConfig.setOutbounds(new ArrayList<>( xrayConfig.setOutbounds(new ArrayList<>(
List.of(freeOut) 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(); RoutingObject routingObject = xrayConfig.getRouting();
@@ -252,8 +435,8 @@ public class XrayCoreServiceImpl implements XrayCoreService {
RuleObject ruleObject = RuleObject RuleObject ruleObject = RuleObject
.builder() .builder()
.type("field") .type("field")
.inboundTag(List.of(tag)) .inboundTag(List.of(chainTag))
.outboundTag(tag) .outboundTag(chainTag)
.build(); .build();
List<RuleObject> ruleObjectList = routingObject.getRules(); List<RuleObject> ruleObjectList = routingObject.getRules();
@@ -265,7 +448,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
ruleObjectList.add(ruleObject); ruleObjectList.add(ruleObject);
} }
private void buildOutbound(XrayConfig xrayConfig, List<ProxyNode> networkPathList, int pos, ClientObject clientObject, String tag, Integer chainPort) { private void buildOutbound(XrayConfig xrayConfig, List<ProxyNode> networkPathList, int pos, ClientObject clientObject, String chainTag, Integer chainPort) {
// 从缓存中获取 // 从缓存中获取
List<OutboundObject> outboundObjectList = xrayConfig.getOutbounds(); List<OutboundObject> outboundObjectList = xrayConfig.getOutbounds();
@@ -302,7 +485,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
} }
// 设置Tag信息 // 设置Tag信息
vmessOutbound.setTag(tag); vmessOutbound.setTag(chainTag);
// 设置出口信息 // 设置出口信息
OutboundConfigurationObject.ServerObject serverObject = vmessOutbound OutboundConfigurationObject.ServerObject serverObject = vmessOutbound
@@ -325,7 +508,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
outboundObjectList.add(vmessOutbound); 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<InboundObject> inboundObjectList = xrayConfig.getInbounds(); List<InboundObject> inboundObjectList = xrayConfig.getInbounds();
@@ -345,7 +528,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
inboundObject.setTag(tag); inboundObject.setTag(chainTag);
// todo port怎么办 // todo port怎么办
inboundObject.setPort(chainPort); inboundObject.setPort(chainPort);
@@ -365,7 +548,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
} }
/** /**
* shanghai->seoul2->tokyo2 * Shanghai-amd64-01->Seoul-amd64-04
* *
* @param networkPathList 网络路径节点 * @param networkPathList 网络路径节点
* @return 路径Tag * @return 路径Tag
@@ -377,7 +560,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
.stream() .stream()
.forEach( .forEach(
networkPath -> { networkPath -> {
sb.append(networkPath.getName()); sb.append(networkPath.getAgentName());
sb.append("->"); sb.append("->");
} }
); );