[server] [func.xray] - 完成xray 的对象存储,任务分发全流程 - 1
This commit is contained in:
@@ -14,4 +14,6 @@ public enum OctopusMessageType {
|
|||||||
// update or report agent status
|
// update or report agent status
|
||||||
STATUS
|
STATUS
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.swagger.annotations.Api;
|
|||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.ApiParam;
|
import io.swagger.annotations.ApiParam;
|
||||||
import io.wdd.common.beans.response.R;
|
import io.wdd.common.beans.response.R;
|
||||||
|
import io.wdd.func.oss.config.OctopusObjectSummary;
|
||||||
import io.wdd.func.oss.config.OssConfig;
|
import io.wdd.func.oss.config.OssConfig;
|
||||||
import io.wdd.func.oss.service.OSSCoreService;
|
import io.wdd.func.oss.service.OSSCoreService;
|
||||||
import io.wdd.func.oss.service.OssBackendSelect;
|
import io.wdd.func.oss.service.OssBackendSelect;
|
||||||
@@ -125,9 +126,29 @@ public class OSSController {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/object/simple")
|
||||||
|
@ApiOperation("[对象] - 简单查询")
|
||||||
|
public R<OctopusObjectSummary> objectDetailSimple(
|
||||||
|
@RequestParam(value = "BackendPrefixName", required = true)
|
||||||
|
@ApiParam(value = "BackendPrefixName") String BackendPrefixName,
|
||||||
|
@RequestParam(value = "bucketName", required = true)
|
||||||
|
@ApiParam(value = "bucketName") String bucketName,
|
||||||
|
@RequestParam(value = "objectName", required = true)
|
||||||
|
@ApiParam(value = "objectName") String objectName
|
||||||
|
) {
|
||||||
|
|
||||||
|
OssConfig ossConfig = ossBackendSelect.one(BackendPrefixName);
|
||||||
|
|
||||||
|
return R.ok(OSSCoreService.getObjectSimple(
|
||||||
|
ossConfig,
|
||||||
|
bucketName,
|
||||||
|
objectName
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/object/one")
|
@PostMapping("/object/one")
|
||||||
@ApiOperation("[对象] - 查询下载地址")
|
@ApiOperation("[对象] - 默认查询")
|
||||||
public R<S3Object> objectDetailOne(
|
public R<S3Object> objectDetailOne(
|
||||||
@RequestParam(value = "BackendPrefixName", required = true)
|
@RequestParam(value = "BackendPrefixName", required = true)
|
||||||
@ApiParam(value = "BackendPrefixName") String BackendPrefixName,
|
@ApiParam(value = "BackendPrefixName") String BackendPrefixName,
|
||||||
|
|||||||
@@ -1,25 +1,67 @@
|
|||||||
package io.wdd.func.controller;
|
package io.wdd.func.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import io.wdd.func.xray.beans.node.ProxyNode;
|
||||||
|
import io.wdd.func.xray.service.XrayConfigDistribute;
|
||||||
import io.wdd.func.xray.service.XrayCoreService;
|
import io.wdd.func.xray.service.XrayCoreService;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static io.wdd.func.xray.beans.node.ProxyNodeSet.*;
|
||||||
|
import static io.wdd.func.xray.beans.node.ProxyNodeSet.phoenix2;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/server/func/xray/")
|
@RequestMapping("/server/func/xray")
|
||||||
public class XrayController {
|
public class XrayController {
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
XrayCoreService xrayCoreService;
|
XrayCoreService xrayCoreService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
XrayConfigDistribute xrayConfigDistribute;
|
||||||
|
|
||||||
@GetMapping("/test")
|
@GetMapping("/test")
|
||||||
public void test(){
|
public void test(){
|
||||||
|
|
||||||
xrayCoreService.generateXrayJsonFromNodeList(null);
|
ArrayList<ArrayList<ProxyNode>> allNetworkPathList = new ArrayList<>();
|
||||||
|
|
||||||
|
ArrayList<ProxyNode> pathA = new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
shanghai,
|
||||||
|
seoul2,
|
||||||
|
tokyo2,
|
||||||
|
phoenix2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*ArrayList<ProxyNode> pathB = new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
shanghai,
|
||||||
|
seoul2,
|
||||||
|
london2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ArrayList<ProxyNode> pathC = new ArrayList<>(
|
||||||
|
Arrays.asList(
|
||||||
|
seoul2,
|
||||||
|
phoenix2
|
||||||
|
)
|
||||||
|
);*/
|
||||||
|
|
||||||
|
allNetworkPathList.add(pathA);
|
||||||
|
// allNetworkPathList.add(pathB);
|
||||||
|
// allNetworkPathList.add(pathC);
|
||||||
|
|
||||||
|
xrayCoreService.generateXrayJsonFromNodeList(allNetworkPathList);
|
||||||
|
|
||||||
|
xrayConfigDistribute.uploadXrayConfigToOSS(allNetworkPathList.get(0));
|
||||||
|
|
||||||
System.out.println("结束!");
|
System.out.println("结束!");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package io.wdd.func.oss.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.amazonaws.services.s3.model.Owner;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参考 com.amazonaws.services.s3.model.S3ObjectSummary
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
@ApiModel("Octopus项目使用的对象存储的标准模型")
|
||||||
|
public class OctopusObjectSummary {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the bucket in which this object is stored
|
||||||
|
*/
|
||||||
|
String bucketName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key under which this object is stored
|
||||||
|
*/
|
||||||
|
String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex encoded MD5 hash of this object's contents, as computed by Amazon S3
|
||||||
|
*/
|
||||||
|
String eTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of this object, in bytes
|
||||||
|
*/
|
||||||
|
long size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date, according to Amazon S3, when this object was last modified
|
||||||
|
*/
|
||||||
|
Date lastModified;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class of storage used by Amazon S3 to store this object
|
||||||
|
*/
|
||||||
|
String storageClass;
|
||||||
|
|
||||||
|
String contentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The owner of this object - can be null if the requester doesn't have
|
||||||
|
* permission to view object ownership information
|
||||||
|
*/
|
||||||
|
Owner owner;
|
||||||
|
|
||||||
|
AccessDTO access;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
public static class AccessDTO {
|
||||||
|
URI originUrl;
|
||||||
|
|
||||||
|
String cloudflareUrl;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.amazonaws.services.s3.model.Bucket;
|
|||||||
import com.amazonaws.services.s3.model.ObjectListing;
|
import com.amazonaws.services.s3.model.ObjectListing;
|
||||||
import com.amazonaws.services.s3.model.ObjectMetadata;
|
import com.amazonaws.services.s3.model.ObjectMetadata;
|
||||||
import com.amazonaws.services.s3.model.S3Object;
|
import com.amazonaws.services.s3.model.S3Object;
|
||||||
|
import io.wdd.func.oss.config.OctopusObjectSummary;
|
||||||
import io.wdd.func.oss.config.OssConfig;
|
import io.wdd.func.oss.config.OssConfig;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -93,6 +94,18 @@ public interface OSSCoreService {
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an object.
|
||||||
|
* https://docs.oracle.com/en-us/iaas/api/#/en/s3objectstorage/20160918/Object/GetObject
|
||||||
|
*
|
||||||
|
* @param ossConfig
|
||||||
|
* @param bucketName
|
||||||
|
* @param objectName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
OctopusObjectSummary getObjectSimple(OssConfig ossConfig, String bucketName, String objectName);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves an object.
|
* Retrieves an object.
|
||||||
* https://docs.oracle.com/en-us/iaas/api/#/en/s3objectstorage/20160918/Object/GetObject
|
* https://docs.oracle.com/en-us/iaas/api/#/en/s3objectstorage/20160918/Object/GetObject
|
||||||
@@ -138,6 +151,17 @@ public interface OSSCoreService {
|
|||||||
*/
|
*/
|
||||||
HashMap<String, String> createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file);
|
HashMap<String, String> createObject(OssConfig ossConfig, String bucketName, String objectName, MultipartFile file);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ossConfig查询得到一个随机公开的桶,然后上传
|
||||||
|
*
|
||||||
|
* @param ossConfig
|
||||||
|
* @param objectName
|
||||||
|
* @param file
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
OctopusObjectSummary createObject(OssConfig ossConfig, String objectName, File file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new object or overwrites an existing one.
|
* Creates a new object or overwrites an existing one.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -148,7 +172,7 @@ public interface OSSCoreService {
|
|||||||
* @param objectName
|
* @param objectName
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ObjectMetadata createObject(OssConfig ossConfig, String bucketName, String objectName, File file);
|
OctopusObjectSummary createObject(OssConfig ossConfig, String bucketName, String objectName, File file);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import com.amazonaws.SdkClientException;
|
|||||||
import com.amazonaws.services.s3.AmazonS3;
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
import com.amazonaws.services.s3.model.*;
|
import com.amazonaws.services.s3.model.*;
|
||||||
import io.wdd.common.handler.MyRuntimeException;
|
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.config.OssConfig;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -102,6 +104,15 @@ public class OSSCoreServiceImpl implements OSSCoreService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OctopusObjectSummary getObjectSimple(OssConfig ossConfig, String bucketName, String objectName) {
|
||||||
|
return buildOctopusObjectSummary(
|
||||||
|
ossConfig,
|
||||||
|
bucketName,
|
||||||
|
objectName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S3Object getObject(OssConfig ossConfig, String bucketName, String objectName) {
|
public S3Object getObject(OssConfig ossConfig, String bucketName, String objectName) {
|
||||||
|
|
||||||
@@ -113,7 +124,10 @@ public class OSSCoreServiceImpl implements OSSCoreService {
|
|||||||
objectName
|
objectName
|
||||||
);
|
);
|
||||||
} catch (SdkClientException e) {
|
} catch (SdkClientException e) {
|
||||||
log.error("出查询单个对象 出现错误, 错误原因为 => {}", e.getMessage());
|
log.error(
|
||||||
|
"出查询单个对象 出现错误, 错误原因为 => {}",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
throw new MyRuntimeException(e.getMessage());
|
throw new MyRuntimeException(e.getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -156,7 +170,10 @@ public class OSSCoreServiceImpl implements OSSCoreService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("查询对象的Head信息错误, 错误原因 => {}", e.getMessage());
|
log.error(
|
||||||
|
"查询对象的Head信息错误, 错误原因 => {}",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
throw new MyRuntimeException(e.getMessage());
|
throw new MyRuntimeException(e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -197,29 +214,122 @@ public class OSSCoreServiceImpl implements OSSCoreService {
|
|||||||
.getObjectContent()
|
.getObjectContent()
|
||||||
.getHttpRequest()
|
.getHttpRequest()
|
||||||
.getURI();
|
.getURI();
|
||||||
map.put("origin",
|
map.put(
|
||||||
String.valueOf(uri));
|
"origin",
|
||||||
|
String.valueOf(uri)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("文件-创建一个对象失败,原因为 => {}", e.getMessage());
|
log.error(
|
||||||
|
"文件-创建一个对象失败,原因为 => {}",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectMetadata createObject(OssConfig ossConfig, String bucketName, String objectName, File file) {
|
public OctopusObjectSummary createObject(OssConfig ossConfig, String objectName, File file) {
|
||||||
AmazonS3 client = ossConfig.getClient();
|
|
||||||
|
|
||||||
PutObjectResult putObjectResult = client.putObject(
|
AmazonS3 client = ossConfig.getClient();
|
||||||
bucketName,
|
List<Bucket> bucketList = client.listBuckets(
|
||||||
|
);
|
||||||
|
|
||||||
|
Bucket randomBucket = bucketList
|
||||||
|
.stream()
|
||||||
|
// 理论上此处应该增加筛选公开的桶的策略
|
||||||
|
.findAny()
|
||||||
|
.get();
|
||||||
|
|
||||||
|
Assert.notNull(
|
||||||
|
randomBucket,
|
||||||
|
"[对象]-创建失败! 未获取到有效的 bucketName"
|
||||||
|
);
|
||||||
|
|
||||||
|
return createObject(
|
||||||
|
ossConfig,
|
||||||
|
randomBucket.getName(),
|
||||||
objectName,
|
objectName,
|
||||||
file
|
file
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return putObjectResult.getMetadata();
|
@Override
|
||||||
|
public OctopusObjectSummary createObject(OssConfig ossConfig, String bucketName, String objectName, File file) {
|
||||||
|
|
||||||
|
AmazonS3 client = ossConfig.getClient();
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"[对象]-创建新的对象,OSS后端为 [ {} ], 桶名称为 [ {} ], 文件名称为 [ {} ]",
|
||||||
|
ossConfig.getName() + "-" + ossConfig.getRegion(),
|
||||||
|
bucketName,
|
||||||
|
objectName
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 调用sdk上传文件
|
||||||
|
client.putObject(
|
||||||
|
bucketName,
|
||||||
|
objectName,
|
||||||
|
file
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (SdkClientException e) {
|
||||||
|
log.error(
|
||||||
|
"[对象]-创建对象失败! OSS后端为 [ {} ], 桶名称为 [ {} ], 文件名称为 [ {} ] 原因为 {}",
|
||||||
|
ossConfig.getName() + "-" + ossConfig.getRegion(),
|
||||||
|
bucketName,
|
||||||
|
objectName,
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
throw new MyRuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询对象的相关信息返回不一样的内容
|
||||||
|
return buildOctopusObjectSummary(
|
||||||
|
ossConfig,
|
||||||
|
bucketName,
|
||||||
|
objectName
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private OctopusObjectSummary buildOctopusObjectSummary(OssConfig ossConfig, String bucketName, String objectName) {
|
||||||
|
|
||||||
|
S3Object s3Object = this.getObject(
|
||||||
|
ossConfig,
|
||||||
|
bucketName,
|
||||||
|
objectName
|
||||||
|
);
|
||||||
|
|
||||||
|
return convertOOSFromS3Object(s3Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OctopusObjectSummary convertOOSFromS3Object(S3Object s3Object) {
|
||||||
|
S3ObjectInputStream objectContent = s3Object.getObjectContent();
|
||||||
|
ObjectMetadata objectMetadata = s3Object.getObjectMetadata();
|
||||||
|
|
||||||
|
OctopusObjectSummary.AccessDTO accessDTO = OctopusObjectSummary.AccessDTO
|
||||||
|
.builder()
|
||||||
|
.originUrl(objectContent
|
||||||
|
.getHttpRequest()
|
||||||
|
.getURI())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return OctopusObjectSummary
|
||||||
|
.builder()
|
||||||
|
.key(s3Object.getKey())
|
||||||
|
.size(objectMetadata.getContentLength())
|
||||||
|
.lastModified(objectMetadata.getLastModified())
|
||||||
|
.contentType(objectMetadata.getContentType())
|
||||||
|
.eTag(objectMetadata.getETag())
|
||||||
|
.bucketName(s3Object.getBucketName())
|
||||||
|
.access(accessDTO)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -234,7 +344,6 @@ public class OSSCoreServiceImpl implements OSSCoreService {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return restoreObjectResult.getRestoreOutputPath();
|
return restoreObjectResult.getRestoreOutputPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
package io.wdd.func.xray.beans.node;
|
package io.wdd.func.xray.beans.node;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@SuperBuilder(toBuilder = true)
|
@SuperBuilder(toBuilder = true)
|
||||||
|
@ApiModel("代理节点的信息")
|
||||||
public class ProxyNode {
|
public class ProxyNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,8 +36,11 @@ public class ProxyNode {
|
|||||||
|
|
||||||
String publicIPv6;
|
String publicIPv6;
|
||||||
|
|
||||||
|
@ApiModelProperty("保存生成的Xray Config信息")
|
||||||
|
XrayConfigInfo xrayConfigInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ProxyNode: [ "+ agentTopicName + " ]";
|
return "ProxyNode: [ " + agentTopicName + " ]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package io.wdd.func.xray.beans.node;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import io.wdd.func.oss.config.OctopusObjectSummary;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
@ApiModel("保存ProxyNode对应生成的 Config信息")
|
||||||
|
public class XrayConfigInfo {
|
||||||
|
|
||||||
|
@ApiModelProperty("文件名称,为1-<agentTopicName>-<timeString>.json")
|
||||||
|
String xrayConfigFileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存生成的XrayConfig文件的全路径
|
||||||
|
*/
|
||||||
|
@ApiModelProperty("保存生成的XrayConfig文件,全路径")
|
||||||
|
File xrayConfigFile;
|
||||||
|
|
||||||
|
|
||||||
|
@ApiModelProperty("xray config file的对象存储的相关信息")
|
||||||
|
OctopusObjectSummary objectSummary;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,173 @@
|
|||||||
package io.wdd.func.xray.service;
|
package io.wdd.func.xray.service;
|
||||||
|
|
||||||
|
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 io.wdd.rpc.execute.service.CoreExecutionService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要完成 Tmp目录中Xray文件的上传工作,上传至 OSS中
|
||||||
|
* <p>
|
||||||
|
* 生成操作命令
|
||||||
|
* 调用rpc,执行命令下发操作,等待agent进行相关操作
|
||||||
|
* <p>
|
||||||
|
* 检查任务流程的结果,判断是否符合预期
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class XrayConfigDistribute {
|
public class XrayConfigDistribute {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储更新 Xray的命令行
|
||||||
|
*/
|
||||||
|
private static final List<List<String>> updateXrayCommandList = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送至agent的操作类型
|
||||||
|
*/
|
||||||
|
private static final String updateCommandType = "OctopusXray";
|
||||||
|
|
||||||
|
static {
|
||||||
|
ArrayList<String> first = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
"cp",
|
||||||
|
"/usr/local/etc/xray/config.json",
|
||||||
|
"/usr/local/etc/xray/config-bak-$(date +%Y-%m-%d-%H-%M-%S)"
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ArrayList<String> second = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
"wget",
|
||||||
|
"url",
|
||||||
|
"-O",
|
||||||
|
"/usr/local/etc/xray/config.json"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ArrayList<String> third = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
"systemctl",
|
||||||
|
"restart",
|
||||||
|
"xray"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ArrayList<String> fourth = new ArrayList<>(
|
||||||
|
List.of(
|
||||||
|
"systemctl",
|
||||||
|
"status",
|
||||||
|
"xray",
|
||||||
|
"|",
|
||||||
|
"grep",
|
||||||
|
"-c",
|
||||||
|
"active,(running)"
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
updateXrayCommandList.add(first);
|
||||||
|
updateXrayCommandList.add(second);
|
||||||
|
updateXrayCommandList.add(third);
|
||||||
|
updateXrayCommandList.add(fourth);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
OssBackendSelect ossBackendSelect;
|
||||||
|
@Resource
|
||||||
|
OSSCoreService ossCoreService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
CoreExecutionService executionService;
|
||||||
|
|
||||||
|
public void uploadXrayConfigToOSS(ArrayList<ProxyNode> networkPathList) {
|
||||||
|
|
||||||
|
// 所有的文件全部存储至一个对象存储的后端中
|
||||||
|
OssConfig ossConfig = ossBackendSelect.oneRandom();
|
||||||
|
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(ArrayList<ProxyNode> networkPathList) {
|
||||||
|
|
||||||
|
|
||||||
|
List<String> resultKeyList = networkPathList
|
||||||
|
.stream()
|
||||||
|
.map(
|
||||||
|
proxyNode -> {
|
||||||
|
OctopusObjectSummary.AccessDTO access = proxyNode
|
||||||
|
.getXrayConfigInfo()
|
||||||
|
.getObjectSummary()
|
||||||
|
.getAccess();
|
||||||
|
|
||||||
|
String realUrl = access
|
||||||
|
.getOriginUrl()
|
||||||
|
.getPath();
|
||||||
|
if (StringUtils.isNotEmpty(access.getCloudflareUrl())) {
|
||||||
|
// 优先使用 被cloudflare包装过的的下载网址
|
||||||
|
realUrl = access.getCloudflareUrl();
|
||||||
|
}
|
||||||
|
// 修改命令中的下载url
|
||||||
|
updateXrayCommandList
|
||||||
|
.get(1)
|
||||||
|
.set(
|
||||||
|
1,
|
||||||
|
realUrl
|
||||||
|
);
|
||||||
|
|
||||||
|
// 向Agent发送命令,执行更新操作!
|
||||||
|
String resultKey = executionService.SendCommandToAgent(
|
||||||
|
proxyNode.getAgentTopicName(),
|
||||||
|
updateCommandType,
|
||||||
|
null,
|
||||||
|
updateXrayCommandList,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
return resultKey;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
log.debug("发送所有的配置到各个Agent成功, 结果查看为 => {}", resultKeyList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ 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.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +28,7 @@ public class XrayConfigPersistor {
|
|||||||
public static AtomicInteger cleanVersion = new AtomicInteger(0);
|
public static AtomicInteger cleanVersion = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
public void write(String fileName , String content, int currentVersion) {
|
public File write(String fileName , String content, int currentVersion) {
|
||||||
|
|
||||||
System.out.println("currentVersion = " + currentVersion);
|
System.out.println("currentVersion = " + currentVersion);
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ public class XrayConfigPersistor {
|
|||||||
File resultFile = getResultFile(fileName);
|
File resultFile = getResultFile(fileName);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
log.debug("开始写入XrayConfig进入文件中,文件名为 => {}",fileName);
|
log.debug("开始写入XrayConfig进入文件中,文件名为 => {}",fileName);
|
||||||
FileWriter fileWriter = new FileWriter(
|
FileWriter fileWriter = new FileWriter(
|
||||||
resultFile
|
resultFile
|
||||||
@@ -60,12 +58,13 @@ public class XrayConfigPersistor {
|
|||||||
bufferedWriter.close();
|
bufferedWriter.close();
|
||||||
fileWriter.close();
|
fileWriter.close();
|
||||||
|
|
||||||
|
|
||||||
|
return resultFile;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("打开文件失败,写入tmp文件失败! 文件为 => {}", resultFile.getName());
|
log.error("打开文件失败,写入tmp文件失败! 文件为 => {}", resultFile.getName());
|
||||||
throw new MyRuntimeException(e);
|
throw new MyRuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearOldRemainStaff() {
|
private void clearOldRemainStaff() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.wdd.common.utils.TimeUtils;
|
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.xray.RoutingObject;
|
import io.wdd.func.xray.beans.xray.RoutingObject;
|
||||||
import io.wdd.func.xray.beans.xray.RuleObject;
|
import io.wdd.func.xray.beans.xray.RuleObject;
|
||||||
import io.wdd.func.xray.beans.xray.XrayConfig;
|
import io.wdd.func.xray.beans.xray.XrayConfig;
|
||||||
@@ -19,14 +20,17 @@ import org.apache.commons.beanutils.BeanUtils;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.InboundVmessHTTPTemplate;
|
import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.InboundVmessHTTPTemplate;
|
||||||
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.beans.node.ProxyNodeSet.*;
|
|
||||||
import static io.wdd.func.xray.service.XrayConfigPersistor.cleanVersion;
|
import static io.wdd.func.xray.service.XrayConfigPersistor.cleanVersion;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -43,38 +47,6 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
@Override
|
@Override
|
||||||
public void generateXrayJsonFromNodeList(ArrayList<ArrayList<ProxyNode>> allNetworkPathList) {
|
public void generateXrayJsonFromNodeList(ArrayList<ArrayList<ProxyNode>> allNetworkPathList) {
|
||||||
|
|
||||||
|
|
||||||
allNetworkPathList = new ArrayList<>();
|
|
||||||
|
|
||||||
ArrayList<ProxyNode> pathA = new ArrayList<>(
|
|
||||||
Arrays.asList(
|
|
||||||
shanghai,
|
|
||||||
seoul2,
|
|
||||||
tokyo2,
|
|
||||||
phoenix2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/*ArrayList<ProxyNode> pathB = new ArrayList<>(
|
|
||||||
Arrays.asList(
|
|
||||||
shanghai,
|
|
||||||
seoul2,
|
|
||||||
london2
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
ArrayList<ProxyNode> pathC = new ArrayList<>(
|
|
||||||
Arrays.asList(
|
|
||||||
seoul2,
|
|
||||||
phoenix2
|
|
||||||
)
|
|
||||||
);*/
|
|
||||||
|
|
||||||
allNetworkPathList.add(pathA);
|
|
||||||
// allNetworkPathList.add(pathB);
|
|
||||||
// allNetworkPathList.add(pathC);
|
|
||||||
|
|
||||||
|
|
||||||
// 需要根据所有的交叉链路进行计算
|
// 需要根据所有的交叉链路进行计算
|
||||||
// A -> B -> C -> D
|
// A -> B -> C -> D
|
||||||
// B -> D
|
// B -> D
|
||||||
@@ -87,12 +59,11 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
|
|
||||||
// 返回每一条的结果至于 Map中 key => shanghai->seoul2->tokyo2
|
// 返回每一条的结果至于 Map中 key => shanghai->seoul2->tokyo2
|
||||||
// value => xray配置信息
|
// value => xray配置信息
|
||||||
HashMap<String, String> interfaceMap = new HashMap<>();
|
// HashMap<String, String> interfaceMap = new HashMap<>();
|
||||||
|
|
||||||
// 最终Xray Json配置应该放置于 Map中 key => ProxyNode
|
// 最终Xray Json配置应该放置于 Map中 key => ProxyNode
|
||||||
// value => Xray Config Json
|
// value => Xray Config Json
|
||||||
HashMap<ProxyNode, XrayConfig> resultMap = new HashMap<>();
|
// HashMap<ProxyNode, XrayConfig> resultMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
allNetworkPathList
|
allNetworkPathList
|
||||||
.stream()
|
.stream()
|
||||||
@@ -100,9 +71,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
networkPathList -> {
|
networkPathList -> {
|
||||||
// 每一条每一条的执行,依次添加相应的 in-out 连接
|
// 每一条每一条的执行,依次添加相应的 in-out 连接
|
||||||
generateXrayJsonSinglePath(
|
generateXrayJsonSinglePath(
|
||||||
networkPathList,
|
networkPathList
|
||||||
interfaceMap,
|
|
||||||
resultMap
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -110,7 +79,7 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateXrayJsonSinglePath(ArrayList<ProxyNode> networkPathList, HashMap<String, String> interfaceMap, HashMap<ProxyNode, XrayConfig> resultMap) {
|
private void generateXrayJsonSinglePath(ArrayList<ProxyNode> networkPathList) {
|
||||||
int pathLength = networkPathList.size();
|
int pathLength = networkPathList.size();
|
||||||
if (pathLength == 1) {
|
if (pathLength == 1) {
|
||||||
log.error("网络路径节点仅为一个");
|
log.error("网络路径节点仅为一个");
|
||||||
@@ -146,7 +115,6 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
// 清楚tmp目录时候使用的一个锁
|
// 清楚tmp目录时候使用的一个锁
|
||||||
int currentVersion = cleanVersion.get();
|
int currentVersion = cleanVersion.get();
|
||||||
|
|
||||||
|
|
||||||
for (int pos = 0; pos < pathLength; pos++) {
|
for (int pos = 0; pos < pathLength; pos++) {
|
||||||
|
|
||||||
ProxyNode proxyNode = networkPathList.get(pos);
|
ProxyNode proxyNode = networkPathList.get(pos);
|
||||||
@@ -178,12 +146,19 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 文件持久化!
|
// 文件持久化!
|
||||||
xrayConfigPersistor.write(
|
File xrayConfigFile = xrayConfigPersistor.write(
|
||||||
fileName,
|
fileName,
|
||||||
resultContent,
|
resultContent,
|
||||||
currentVersion
|
currentVersion
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 文件写入完成,保存文件信息
|
||||||
|
XrayConfigInfo xrayConfigInfo = new XrayConfigInfo();
|
||||||
|
xrayConfigInfo.setXrayConfigFile(xrayConfigFile);
|
||||||
|
xrayConfigInfo.setXrayConfigFileName(fileName);
|
||||||
|
|
||||||
|
proxyNode.setXrayConfigInfo(xrayConfigInfo);
|
||||||
|
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -376,7 +351,6 @@ public class XrayCoreServiceImpl implements XrayCoreService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 去掉末尾的 ->
|
// 去掉末尾的 ->
|
||||||
|
|
||||||
String s = sb.toString();
|
String s = sb.toString();
|
||||||
|
|
||||||
return s.substring(
|
return s.substring(
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public interface CoreExecutionService {
|
|||||||
String SendCommandToAgent(String agentTopicName, List<String> commandList);
|
String SendCommandToAgent(String agentTopicName, List<String> commandList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 调用 单行命令脚本的 最底层函数
|
||||||
|
*
|
||||||
* @param agentTopicName agent唯一表示名
|
* @param agentTopicName agent唯一表示名
|
||||||
* @param type 任务执行类型
|
* @param type 任务执行类型
|
||||||
* @param commandList 任务列表内容
|
* @param commandList 任务列表内容
|
||||||
@@ -21,10 +23,20 @@ public interface CoreExecutionService {
|
|||||||
|
|
||||||
String SendCommandToAgent(String agentTopicName, String type, List<String> commandList, List<List<String>> commandListComplete);
|
String SendCommandToAgent(String agentTopicName, String type, List<String> commandList, List<List<String>> commandListComplete);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 调用 完整脚本的 最底层函数
|
||||||
|
*
|
||||||
|
* @param agentTopicName
|
||||||
|
* @param type
|
||||||
|
* @param commandList
|
||||||
|
* @param commandListComplete
|
||||||
|
* @param futureKey
|
||||||
|
* @return resultKey 本次操作在Redis中记录的结果Key
|
||||||
|
*/
|
||||||
String SendCommandToAgent(String agentTopicName, String type, List<String> commandList, List<List<String>> commandListComplete, String futureKey);
|
String SendCommandToAgent(String agentTopicName, String type, List<String> commandList, List<List<String>> commandListComplete, String futureKey);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<String> SendCommandToAgent(List<String> agentTopicNameList, String type, List<String> command);
|
List<String> SendCommandToAgent(List<String> agentTopicNameList, String type, List<String> command);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package io.wdd.rpc.openfeign;
|
|
||||||
|
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
|
||||||
|
|
||||||
@FeignClient(url = "")
|
|
||||||
public interface AgentOperationFeign {
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user