diff --git a/common/src/main/java/io/wdd/common/utils/TimeUtils.java b/common/src/main/java/io/wdd/common/utils/TimeUtils.java index aadb0ef..f85627b 100644 --- a/common/src/main/java/io/wdd/common/utils/TimeUtils.java +++ b/common/src/main/java/io/wdd/common/utils/TimeUtils.java @@ -85,6 +85,16 @@ public class TimeUtils { } + + /** + * @return UTC+8 [ yyyy-MM-dd-HH-mm-ss ] Time String + */ + public static String currentFormatTimeString() { + + return currentFormatTime() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")); + } + public static LocalDateTime cvFromDate(Date date) { // fix bug diff --git a/server/src/main/java/io/wdd/func/controller/OSSController.java b/server/src/main/java/io/wdd/func/controller/OSSController.java index 05bb4ac..9b2b5a1 100644 --- a/server/src/main/java/io/wdd/func/controller/OSSController.java +++ b/server/src/main/java/io/wdd/func/controller/OSSController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.util.HashMap; import java.util.List; @RestController @@ -104,7 +105,7 @@ public class OSSController { @PostMapping("/object/create") @ApiOperation("[对象] - 创建, 外部上传 [todo 分片上传]") - public R objectCreate( + public R> objectCreate( @RequestParam(value = "BackendPrefixName", required = true) @ApiParam(value = "BackendPrefixName") String BackendPrefixName, @RequestParam(value = "bucketName", required = true) diff --git a/server/src/main/java/io/wdd/func/oss/service/OSSCoreService.java b/server/src/main/java/io/wdd/func/oss/service/OSSCoreService.java index b4ae484..75b070e 100644 --- a/server/src/main/java/io/wdd/func/oss/service/OSSCoreService.java +++ b/server/src/main/java/io/wdd/func/oss/service/OSSCoreService.java @@ -8,6 +8,7 @@ import io.wdd.func.oss.config.OssConfig; import org.springframework.web.multipart.MultipartFile; import java.io.File; +import java.util.HashMap; import java.util.List; public interface OSSCoreService { @@ -135,7 +136,7 @@ public interface OSSCoreService { * @param objectName * @return */ - ObjectMetadata createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file); + HashMap createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file); /** * Creates a new object or overwrites an existing one. diff --git a/server/src/main/java/io/wdd/func/oss/service/OSSCoreServiceImpl.java b/server/src/main/java/io/wdd/func/oss/service/OSSCoreServiceImpl.java index 4b79d95..fab678c 100644 --- a/server/src/main/java/io/wdd/func/oss/service/OSSCoreServiceImpl.java +++ b/server/src/main/java/io/wdd/func/oss/service/OSSCoreServiceImpl.java @@ -12,6 +12,8 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @@ -162,13 +164,18 @@ public class OSSCoreServiceImpl implements OSSCoreService { } @Override - public ObjectMetadata createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file) { + public HashMap createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file) { AmazonS3 client = ossConfig.getClient(); try { ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(file.getSize()); + + long contentLength = Math.max( + file.getBytes().length, + file.getSize() + ); + metadata.setContentLength(contentLength); PutObjectResult putObjectResult = client.putObject( bucketName, @@ -177,10 +184,27 @@ public class OSSCoreServiceImpl implements OSSCoreService { metadata ); - return putObjectResult.getMetadata(); + HashMap map = new HashMap<>(); + // 需要返回下载地址 + S3Object s3Object = this.getObject( + ossConfig, + bucketName, + objectName + ); + + URI uri = s3Object + .getObjectContent() + .getHttpRequest() + .getURI(); + map.put("origin", + String.valueOf(uri)); + + + return map; } catch (IOException e) { + log.error("文件-创建一个对象失败,原因为 => {}", e.getMessage()); throw new RuntimeException(e); } } diff --git a/server/src/main/java/io/wdd/func/xray/result/simple.json b/server/src/main/java/io/wdd/func/xray/result/simple.json deleted file mode 100644 index 0e0dcd2..0000000 --- a/server/src/main/java/io/wdd/func/xray/result/simple.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} \ No newline at end of file diff --git a/server/src/main/java/io/wdd/func/xray/result/test.json b/server/src/main/java/io/wdd/func/xray/result/test.json deleted file mode 100644 index 39a3747..0000000 --- a/server/src/main/java/io/wdd/func/xray/result/test.json +++ /dev/null @@ -1,465 +0,0 @@ -{ - "log": { - "access": "/var/log/xray/access.log", - "error": "/var/log/xray/error.log", - "loglevel": "warning" - }, - "inbounds": [ - { - "protocol": "vmess", - "listen": "0.0.0.0", - "port": 19999, - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "response": { - "version": "1.1", - "status": "200", - "reason": "Accept", - "headers": { - "Content-Type": [ - "application/octet-stream", - "video/mpeg" - ], - "Transfer-Encoding": [ - "chunked" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "settings": { - "clients": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ], - "disableInsecureEncryption": false - } - } - ], - "outbounds": [ - { - "protocol": "vmess", - "settings": { - "vnext": [ - { - "address": "140.238.30.110", - "port": 19999, - "users": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ] - } - ] - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "request": { - "version": "1.1", - "method": "GET", - "path": [ - "/news/", - "/finance/", - "/sports/", - "weathers" - ], - "headers": { - "Host": [ - "www.baidu.com", - "www.google.com", - "www.bing.com", - "www.github.com" - ], - "User-Agent": [ - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" - ], - "Accept-Encoding": [ - "gzip", - "deflate" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "mux": { - "enabled": false, - "concurrency": -1 - } - }, - { - "protocol": "freedom" - }, - { - "protocol": "blackhole", - "tag": "block" - } - ], - "routing": { - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "inboundTag": [ - "tc-sh->seoul-2->tokyo-2->phoenix-2" - ], - "outboundTag": "tc-sh->seoul-2->tokyo-2->phoenix-2" - } - ] - } -}, -{ - "log": { - "access": "/var/log/xray/access.log", - "error": "/var/log/xray/error.log", - "loglevel": "warning" - }, - "inbounds": [ - { - "protocol": "vmess", - "listen": "0.0.0.0", - "port": 19999, - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "response": { - "version": "1.1", - "status": "200", - "reason": "Accept", - "headers": { - "Content-Type": [ - "application/octet-stream", - "video/mpeg" - ], - "Transfer-Encoding": [ - "chunked" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "settings": { - "clients": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ], - "disableInsecureEncryption": false - } - } - ], - "outbounds": [ - { - "protocol": "vmess", - "settings": { - "vnext": [ - { - "address": "140.238.52.228", - "port": 19999, - "users": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ] - } - ] - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "request": { - "version": "1.1", - "method": "GET", - "path": [ - "/news/", - "/finance/", - "/sports/", - "weathers" - ], - "headers": { - "Host": [ - "www.baidu.com", - "www.google.com", - "www.bing.com", - "www.github.com" - ], - "User-Agent": [ - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" - ], - "Accept-Encoding": [ - "gzip", - "deflate" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "mux": { - "enabled": false, - "concurrency": -1 - } - }, - { - "protocol": "freedom" - }, - { - "protocol": "blackhole", - "tag": "block" - } - ], - "routing": { - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "inboundTag": [ - "tc-sh->seoul-2->tokyo-2->phoenix-2" - ], - "outboundTag": "tc-sh->seoul-2->tokyo-2->phoenix-2" - } - ] - } -} ------------------------------------ -{ - "log": { - "access": "/var/log/xray/access.log", - "error": "/var/log/xray/error.log", - "loglevel": "warning" - }, - "inbounds": [ - { - "protocol": "vmess", - "listen": "0.0.0.0", - "port": 19999, - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "response": { - "version": "1.1", - "status": "200", - "reason": "Accept", - "headers": { - "Content-Type": [ - "application/octet-stream", - "video/mpeg" - ], - "Transfer-Encoding": [ - "chunked" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "settings": { - "clients": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ], - "disableInsecureEncryption": false - } - } - ], - "outbounds": [ - { - "protocol": "vmess", - "settings": { - "vnext": [ - { - "address": "129.146.171.163", - "port": 19999, - "users": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ] - } - ] - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "request": { - "version": "1.1", - "method": "GET", - "path": [ - "/news/", - "/finance/", - "/sports/", - "weathers" - ], - "headers": { - "Host": [ - "www.baidu.com", - "www.google.com", - "www.bing.com", - "www.github.com" - ], - "User-Agent": [ - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" - ], - "Accept-Encoding": [ - "gzip", - "deflate" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "mux": { - "enabled": false, - "concurrency": -1 - } - }, - { - "protocol": "freedom" - }, - { - "protocol": "blackhole", - "tag": "block" - } - ], - "routing": { - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "inboundTag": [ - "tc-sh->seoul-2->tokyo-2->phoenix-2" - ], - "outboundTag": "tc-sh->seoul-2->tokyo-2->phoenix-2" - } - ] - } -} ------------------------------------ -{ - "inbounds": [ - { - "protocol": "vmess", - "listen": "0.0.0.0", - "port": 19999, - "streamSettings": { - "tcpSettings": { - "header": { - "type": "http", - "response": { - "version": "1.1", - "status": "200", - "reason": "Accept", - "headers": { - "Content-Type": [ - "application/octet-stream", - "video/mpeg" - ], - "Transfer-Encoding": [ - "chunked" - ], - "Connection": [ - "keep-alive" - ], - "Pragma": "no-cache" - } - } - } - } - }, - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2", - "settings": { - "clients": [ - { - "id": "402df401-6a63-444b-9386-f3b6d8e1b769", - "email": "tc-sh->seoul-2->tokyo-2->phoenix-2@octopus.io", - "level": 0, - "alterId": 23 - } - ], - "disableInsecureEncryption": false - } - } - ], - "outbounds": [ - { - "protocol": "freedom", - "tag": "tc-sh->seoul-2->tokyo-2->phoenix-2" - } - ], - "routing": { - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "inboundTag": [ - "tc-sh->seoul-2->tokyo-2->phoenix-2" - ], - "outboundTag": "tc-sh->seoul-2->tokyo-2->phoenix-2" - } - ] - } -} diff --git a/server/src/main/java/io/wdd/func/xray/service/XrayConfigDistribute.java b/server/src/main/java/io/wdd/func/xray/service/XrayConfigDistribute.java new file mode 100644 index 0000000..3fb323b --- /dev/null +++ b/server/src/main/java/io/wdd/func/xray/service/XrayConfigDistribute.java @@ -0,0 +1,9 @@ +package io.wdd.func.xray.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class XrayConfigDistribute { +} diff --git a/server/src/main/java/io/wdd/func/xray/service/XrayConfigPersistor.java b/server/src/main/java/io/wdd/func/xray/service/XrayConfigPersistor.java new file mode 100644 index 0000000..1f15d51 --- /dev/null +++ b/server/src/main/java/io/wdd/func/xray/service/XrayConfigPersistor.java @@ -0,0 +1,110 @@ +package io.wdd.func.xray.service; + + +import io.wdd.common.handler.MyRuntimeException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 获取rerouces目录 https://blog.csdn.net/pengpengpeng85/article/details/84785575 + * + * 写入文件的教程 https://cloud.tencent.com/developer/article/1895274 + */ +@Slf4j +@Service +public class XrayConfigPersistor { + + private static String XrayResultPath = "xrayResult/"; + + + public static AtomicInteger cleanVersion = new AtomicInteger(0); + + + public void write(String fileName , String content, int currentVersion) { + + System.out.println("currentVersion = " + currentVersion); + + if (cleanVersion.get() == currentVersion) { + // 清除旧的内容 + clearOldRemainStaff(); + // 自增1,避免后续继续清除tmp目录 + cleanVersion.incrementAndGet(); + } + + // 构造对象开始写入, 生成文件 + File resultFile = getResultFile(fileName); + try { + + + log.debug("开始写入XrayConfig进入文件中,文件名为 => {}",fileName); + FileWriter fileWriter = new FileWriter( + resultFile + ); + BufferedWriter bufferedWriter = new BufferedWriter( + fileWriter + ); + + log.debug("文件内容为 => {}", content); + bufferedWriter.write(content); + + // must close + bufferedWriter.close(); + fileWriter.close(); + + } catch (IOException e) { + log.error("打开文件失败,写入tmp文件失败! 文件为 => {}", resultFile.getName()); + throw new MyRuntimeException(e); + } + + + } + + private void clearOldRemainStaff() { + + try { + FileUtils.cleanDirectory( + new ClassPathResource(XrayResultPath).getFile() + ); + } catch (IOException e) { + log.error("清楚旧的目录失败! 请检查问题!"); + throw new MyRuntimeException(e); + } + + + } + + /** + * 根据文件名,需要创建一个文件 + * @param fileName 文件名,如 xxx.json + * @return + */ + private File getResultFile(String fileName ){ + + ClassPathResource classPathResource = new ClassPathResource(XrayResultPath); + + + try { + // 需要创建一个文件 + return new File( + classPathResource.getFile(), + fileName + ); + + } catch (IOException e) { + log.error("获取文件失败请检查! fileName is => {}", fileName); + throw new MyRuntimeException(e); + } + + } + + +} 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 a3c9b19..c320822 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 @@ -3,6 +3,7 @@ package io.wdd.func.xray.service; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import io.wdd.common.utils.TimeUtils; import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.xray.RoutingObject; import io.wdd.func.xray.beans.xray.RuleObject; @@ -26,6 +27,7 @@ import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.Listen 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.node.ProxyNodeSet.*; +import static io.wdd.func.xray.service.XrayConfigPersistor.cleanVersion; @Service @Slf4j @@ -34,6 +36,9 @@ public class XrayCoreServiceImpl implements XrayCoreService { @Resource ObjectMapper objectMapper; + @Resource + XrayConfigPersistor xrayConfigPersistor; + @Override public void generateXrayJsonFromNodeList(ArrayList> allNetworkPathList) { @@ -113,7 +118,6 @@ public class XrayCoreServiceImpl implements XrayCoreService { return; } - // 忽略掉 null的字段 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); @@ -137,66 +141,88 @@ public class XrayCoreServiceImpl implements XrayCoreService { .email(tag + "@octopus.io") .build(); - Integer port = 19999; + int port = 19999; + + // 清楚tmp目录时候使用的一个锁 + int currentVersion = cleanVersion.get(); for (int pos = 0; pos < pathLength; pos++) { - XrayConfig xrayConfig = new XrayConfig(); + ProxyNode proxyNode = networkPathList.get(pos); - if (pos == pathLength - 1) { - - // 最后一个节点,形式不一样 - buildInbound( - xrayConfig, - clientObject, - port, - tag - ); - - // 设置FreeOut - buildOutboundFree( - xrayConfig, - tag - ); - - // 设置 路由信息 - buildRouting( - xrayConfig, - tag - ); - - // 添加到临时缓存中 - tmpXrayConfigList.add(xrayConfig); - - // 调试 - try { - String s = objectMapper - .writerWithDefaultPrettyPrinter() - .writeValueAsString(xrayConfig); - - System.out.println(s); - System.out.println("-----------------------------------"); - - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - - return; - } - - - // 设置Log属性 - xrayConfig.setLog(LogTemplate); - - // 初始化 InBound - buildInbound( - xrayConfig, + boolean isOutBoundFree = pos == pathLength - 1; + XrayConfig xrayConfig = doBuildXrayConfig( + isOutBoundFree, + tag, clientObject, port, - tag + networkPathList, + pos ); + // 添加到临时缓存中 + tmpXrayConfigList.add(xrayConfig); + + // 持久化 + try { + String resultContent = objectMapper + .writerWithDefaultPrettyPrinter() + .writeValueAsString(xrayConfig); + + // 获得到文件名称 + String timeString = TimeUtils.currentFormatTimeString(); + String fileName = buildXrayConfigFileName( + proxyNode, + timeString + ); + + // 文件持久化! + xrayConfigPersistor.write( + fileName, + resultContent, + currentVersion + ); + + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + + } + + private String buildXrayConfigFileName(ProxyNode proxyNode, String timeString) { + + return proxyNode.getNum() + "-" + proxyNode.getAgentTopicName() + "-" + timeString + ".json"; + + } + + + private XrayConfig doBuildXrayConfig(boolean isOutBoundFree, String tag, ClientObject clientObject, int port, ArrayList networkPathList, int pos) { + + XrayConfig xrayConfig = new XrayConfig(); + + // 设置Log属性 + xrayConfig.setLog(LogTemplate); + + // 初始化 InBound + buildInbound( + xrayConfig, + clientObject, + port, + tag + ); + + if (isOutBoundFree) { + // 最后一个直接出去就行了 + // 设置FreeOut + buildOutboundFree( + xrayConfig, + tag + ); + } else { + // 中间节点,需要有特定的输出 // 设置 outbounds的信息 buildOutbound( xrayConfig, @@ -206,31 +232,16 @@ public class XrayCoreServiceImpl implements XrayCoreService { tag, port ); - - // 设置 路由信息 - buildRouting( - xrayConfig, - tag - ); - - // 添加到临时缓存中 - tmpXrayConfigList.add(xrayConfig); - - // 调试 - try { - String s = objectMapper - .writerWithDefaultPrettyPrinter() - .writeValueAsString(xrayConfig); - - System.out.println(s); - System.out.println("-----------------------------------"); - - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } } + // 设置 路由信息 + buildRouting( + xrayConfig, + tag + ); + + return xrayConfig; } private void buildOutboundFree(XrayConfig xrayConfig, String tag) { diff --git a/server/src/main/resources/xrayResult/1.json b/server/src/main/resources/xrayResult/1.json new file mode 100644 index 0000000..e69de29