feat: support aliyun instance and more.
This commit is contained in:
@@ -48,9 +48,11 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip
|
|||||||
.forEach(ListableInstanceFactory::refresh);
|
.forEach(ListableInstanceFactory::refresh);
|
||||||
// 加载、过滤所有实例
|
// 加载、过滤所有实例
|
||||||
Set<Instance> instances = new HashSet<>();
|
Set<Instance> instances = new HashSet<>();
|
||||||
listableInstanceFactories.forEach(f -> instances.addAll(f.getInstances()));
|
|
||||||
|
|
||||||
// TODO 加载实例, 按照实例工厂的优先级从低到高优先级排, 高优先级的实例会覆盖低优先级的实例信息(如果存在重复的实例信息)
|
// 高优先级的实例工厂会覆盖低优先级实例工厂所加载的实例
|
||||||
|
listableInstanceFactories.stream()
|
||||||
|
.sorted()
|
||||||
|
.forEach(f -> instances.addAll(f.getInstances()));
|
||||||
|
|
||||||
// 初次载入
|
// 初次载入
|
||||||
cacheInstanceMap = new HashMap<>(instances.stream().collect(Collectors.toMap(Instance::getName, i -> i)));
|
cacheInstanceMap = new HashMap<>(instances.stream().collect(Collectors.toMap(Instance::getName, i -> i)));
|
||||||
@@ -119,9 +121,12 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip
|
|||||||
* 缓存清理
|
* 缓存清理
|
||||||
*/
|
*/
|
||||||
protected void clearCache(){
|
protected void clearCache(){
|
||||||
|
if(cacheInstanceMap != null
|
||||||
|
&& !cacheInstanceMap.isEmpty()){
|
||||||
int size = cacheInstanceMap.size();
|
int size = cacheInstanceMap.size();
|
||||||
cacheInstanceMap.clear();
|
cacheInstanceMap.clear();
|
||||||
log.debug("缓存信息清理 => {} 条", size);
|
log.debug("缓存信息清理 => {} 条", size);
|
||||||
|
}
|
||||||
// 清理实例工厂的缓存信息
|
// 清理实例工厂的缓存信息
|
||||||
listableInstanceFactories.forEach(Refreshable::afterRefresh);
|
listableInstanceFactories.forEach(Refreshable::afterRefresh);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,10 +77,13 @@ public abstract class AbstractInstanceFactory implements InstanceFactory, Listab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterRefresh() {
|
public void afterRefresh() {
|
||||||
|
if(instanceMap != null
|
||||||
|
&& !instanceMap.isEmpty()){
|
||||||
int size = instanceMap.size();
|
int size = instanceMap.size();
|
||||||
instanceMap.clear();
|
instanceMap.clear();
|
||||||
log.debug("缓存信息清理 => {} 条", size);
|
log.debug("缓存信息清理 => {} 条", size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交由子类去加载实例信息
|
* 交由子类去加载实例信息
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
|||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
import com.serliunx.ddns.constant.InstanceSource;
|
import com.serliunx.ddns.constant.InstanceSource;
|
||||||
import com.serliunx.ddns.constant.InstanceType;
|
import com.serliunx.ddns.constant.InstanceType;
|
||||||
|
import com.serliunx.ddns.support.NetworkContextHolder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static com.serliunx.ddns.constant.SystemConstants.XML_ROOT_INSTANCE_NAME;
|
import static com.serliunx.ddns.constant.SystemConstants.XML_ROOT_INSTANCE_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 实例抽象实现
|
||||||
* @author SerLiunx
|
* @author SerLiunx
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
@@ -17,6 +21,7 @@ import static com.serliunx.ddns.constant.SystemConstants.XML_ROOT_INSTANCE_NAME;
|
|||||||
@JacksonXmlRootElement(localName = XML_ROOT_INSTANCE_NAME)
|
@JacksonXmlRootElement(localName = XML_ROOT_INSTANCE_NAME)
|
||||||
public abstract class AbstractInstance implements Instance {
|
public abstract class AbstractInstance implements Instance {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AbstractInstance.class);
|
||||||
/**
|
/**
|
||||||
* 实例名称
|
* 实例名称
|
||||||
* <li> 全局唯一
|
* <li> 全局唯一
|
||||||
@@ -56,8 +61,30 @@ public abstract class AbstractInstance implements Instance {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(query())
|
value = query();
|
||||||
|
final String ipAddress = NetworkContextHolder.getIpAddress();
|
||||||
|
try {
|
||||||
|
if (value != null && !value.isEmpty()
|
||||||
|
&& ipAddress != null && !ipAddress.isEmpty()) {
|
||||||
|
if (value.equals(ipAddress))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
value = ipAddress;
|
||||||
run0();
|
run0();
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}finally {
|
||||||
|
this.value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validate() {
|
||||||
|
// 校验通用参数, 具体子类的参数交由子类校验
|
||||||
|
if(name == null || name.isEmpty() || interval <= 0 || type == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return validate0();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,15 +132,6 @@ public abstract class AbstractInstance implements Instance {
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean validate() {
|
|
||||||
// 校验通用参数, 具体子类的参数交由子类校验
|
|
||||||
if(name == null || name.isEmpty() || interval <= 0 || type == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return validate0();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 具体的初始化逻辑
|
* 具体的初始化逻辑
|
||||||
*/
|
*/
|
||||||
@@ -125,10 +143,14 @@ public abstract class AbstractInstance implements Instance {
|
|||||||
protected abstract boolean validate0();
|
protected abstract boolean validate0();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新前检查是否需要更新
|
* 获取解析当前的ip地址
|
||||||
* @return 无需更新返回假, 否则返回真
|
* <li> 由子类完成具体逻辑
|
||||||
|
* @return 返回当前解析记录的ip地址, 由子类决定.
|
||||||
|
* @see AliyunInstance
|
||||||
|
* @see TencentInstance
|
||||||
|
* @see HuaweiInstance
|
||||||
*/
|
*/
|
||||||
protected abstract boolean query();
|
protected abstract String query();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 具体执行逻辑
|
* 具体执行逻辑
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ package com.serliunx.ddns.core.instance;
|
|||||||
import com.aliyun.auth.credentials.Credential;
|
import com.aliyun.auth.credentials.Credential;
|
||||||
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
|
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
|
||||||
import com.aliyun.sdk.service.alidns20150109.AsyncClient;
|
import com.aliyun.sdk.service.alidns20150109.AsyncClient;
|
||||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoRequest;
|
import com.aliyun.sdk.service.alidns20150109.models.*;
|
||||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoResponse;
|
|
||||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoResponseBody;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
import com.serliunx.ddns.support.NetworkContextHolder;
|
|
||||||
import darabonba.core.client.ClientOverrideConfiguration;
|
import darabonba.core.client.ClientOverrideConfiguration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -107,12 +105,34 @@ public class AliyunInstance extends AbstractInstance {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void run0() {
|
protected void run0() {
|
||||||
log("test");
|
UpdateDomainRecordRequest request = UpdateDomainRecordRequest.builder()
|
||||||
|
.recordId(recordId)
|
||||||
|
.rr(rr)
|
||||||
|
.type(recordType)
|
||||||
|
.value(value)
|
||||||
|
.build();
|
||||||
|
debug("正在更新解析记录.");
|
||||||
|
CompletableFuture<UpdateDomainRecordResponse> requestResponse = client.updateDomainRecord(request);
|
||||||
|
try {
|
||||||
|
requestResponse.whenComplete((v, t) -> {
|
||||||
|
if(t != null){ //出现异常
|
||||||
|
handleThrowable(t);
|
||||||
|
}else{
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
result = jsonMapper.writeValueAsString(v.getBody());
|
||||||
|
} catch (JsonProcessingException ignored) {} finally {
|
||||||
|
debug("操作结束, 结果: {}", result == null ? v : result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean query() {
|
protected String query() {
|
||||||
debug("正在校验是否需要更新记录.");
|
|
||||||
DescribeDomainRecordInfoRequest describeDomainRecordInfoRequest = DescribeDomainRecordInfoRequest.builder()
|
DescribeDomainRecordInfoRequest describeDomainRecordInfoRequest = DescribeDomainRecordInfoRequest.builder()
|
||||||
.recordId(recordId)
|
.recordId(recordId)
|
||||||
.build();
|
.build();
|
||||||
@@ -122,24 +142,15 @@ public class AliyunInstance extends AbstractInstance {
|
|||||||
DescribeDomainRecordInfoResponse response = responseCompletableFuture.get(5, TimeUnit.SECONDS);
|
DescribeDomainRecordInfoResponse response = responseCompletableFuture.get(5, TimeUnit.SECONDS);
|
||||||
DescribeDomainRecordInfoResponseBody body = response.getBody();
|
DescribeDomainRecordInfoResponseBody body = response.getBody();
|
||||||
if(body != null){
|
if(body != null){
|
||||||
String recordValue = body.getValue();
|
return body.getValue();
|
||||||
String ipAddress = NetworkContextHolder.getIpAddress();
|
|
||||||
debug("当前记录值 => {}", recordValue);
|
|
||||||
boolean result = !(recordValue != null && !recordValue.isEmpty()
|
|
||||||
&& recordValue.equals(ipAddress));
|
|
||||||
if(result)
|
|
||||||
debug("需要更新IP地址: {} => {}", recordValue, ipAddress);
|
|
||||||
else
|
|
||||||
debug("无需更新.");
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
error("出现了不应该出现的异常 => {}", e);
|
error("出现了不应该出现的异常 => {}", e);
|
||||||
return false;
|
return null;
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
error("记录查询超时! 将跳过查询直接执行更新操作.");
|
error("记录查询超时!");
|
||||||
return true;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +217,25 @@ public class AliyunInstance extends AbstractInstance {
|
|||||||
this.jsonMapper = jsonMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AliyunInstance{" +
|
||||||
|
"accessKeyId='" + accessKeyId + '\'' +
|
||||||
|
", accessKeySecret='" + accessKeySecret + '\'' +
|
||||||
|
", recordId='" + recordId + '\'' +
|
||||||
|
", rr='" + rr + '\'' +
|
||||||
|
", recordType='" + recordType + '\'' +
|
||||||
|
", client=" + client +
|
||||||
|
", jsonMapper=" + jsonMapper +
|
||||||
|
", name='" + name + '\'' +
|
||||||
|
", fatherName='" + fatherName + '\'' +
|
||||||
|
", interval=" + interval +
|
||||||
|
", type=" + type +
|
||||||
|
", source=" + source +
|
||||||
|
", value='" + value + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
private void handleThrowable(Throwable t){
|
private void handleThrowable(Throwable t){
|
||||||
error("出现异常 {}:", t.getCause(), t.getMessage());
|
error("出现异常 {}:", t.getCause(), t.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.serliunx.ddns.core.instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 华为云实例定义
|
||||||
|
* @author SerLiunx
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class HuaweiInstance extends AbstractInstance {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean validate0() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String query() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run0() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.serliunx.ddns.core.instance;
|
package com.serliunx.ddns.core.instance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 腾讯云实例定义
|
||||||
* @author SerLiunx
|
* @author SerLiunx
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
@@ -17,8 +18,8 @@ public class TencentInstance extends AbstractInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean query() {
|
protected String query() {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ public final class NetworkContextHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getIpAddress(){
|
public static String getIpAddress(){
|
||||||
log.debug("正在尝试获取最新的IP地址.");
|
|
||||||
if(IP_ADDRESS != null)
|
if(IP_ADDRESS != null)
|
||||||
return IP_ADDRESS;
|
return IP_ADDRESS;
|
||||||
try {
|
try {
|
||||||
@@ -46,7 +45,6 @@ public final class NetworkContextHolder {
|
|||||||
log.error("IP地址获取超时.");
|
log.error("IP地址获取超时.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
log.debug("最新的IP地址获取成功.");
|
|
||||||
return IP_ADDRESS;
|
return IP_ADDRESS;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
log.error("IP地址获取出现异常 => {}", e.getMessage());
|
log.error("IP地址获取出现异常 => {}", e.getMessage());
|
||||||
|
|||||||
@@ -16,7 +16,5 @@ public interface Refreshable {
|
|||||||
/**
|
/**
|
||||||
* 刷新后逻辑定义, 一般用于资源清理
|
* 刷新后逻辑定义, 一般用于资源清理
|
||||||
*/
|
*/
|
||||||
default void afterRefresh(){
|
default void afterRefresh(){}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import java.io.OutputStream;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -38,6 +39,7 @@ public final class SystemInitializer implements Refreshable{
|
|||||||
|
|
||||||
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
||||||
private Set<Instance> instances;
|
private Set<Instance> instances;
|
||||||
|
private Map<String, Instance> runningInstances;
|
||||||
|
|
||||||
SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext) {
|
SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
|
|||||||
19
src/test/java/com/serliunx/ddns/test/FactoryTest.java
Normal file
19
src/test/java/com/serliunx/ddns/test/FactoryTest.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.serliunx.ddns.test;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.constant.SystemConstants;
|
||||||
|
import com.serliunx.ddns.core.factory.YamlFileInstanceFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author SerLiunx
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class FactoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testYamlFileFactory(){
|
||||||
|
YamlFileInstanceFactory factory = new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR);
|
||||||
|
factory.refresh();
|
||||||
|
factory.getInstances().forEach(System.out::println);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/test/java/com/serliunx/ddns/test/support/ClientTest.java
Normal file
17
src/test/java/com/serliunx/ddns/test/support/ClientTest.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.serliunx.ddns.test.support;
|
||||||
|
|
||||||
|
import com.serliunx.ddns.support.feign.client.IPAddressClient;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author SerLiunx
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
public class ClientTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
IPAddressClient client = IPAddressClient.instance;
|
||||||
|
System.out.println(client.getIPAddress().getQuery());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user