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);
|
||||
// 加载、过滤所有实例
|
||||
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)));
|
||||
@@ -119,9 +121,12 @@ public abstract class AbstractInstanceContext implements InstanceContext, Multip
|
||||
* 缓存清理
|
||||
*/
|
||||
protected void clearCache(){
|
||||
int size = cacheInstanceMap.size();
|
||||
cacheInstanceMap.clear();
|
||||
log.debug("缓存信息清理 => {} 条", size);
|
||||
if(cacheInstanceMap != null
|
||||
&& !cacheInstanceMap.isEmpty()){
|
||||
int size = cacheInstanceMap.size();
|
||||
cacheInstanceMap.clear();
|
||||
log.debug("缓存信息清理 => {} 条", size);
|
||||
}
|
||||
// 清理实例工厂的缓存信息
|
||||
listableInstanceFactories.forEach(Refreshable::afterRefresh);
|
||||
}
|
||||
|
||||
@@ -77,9 +77,12 @@ public abstract class AbstractInstanceFactory implements InstanceFactory, Listab
|
||||
|
||||
@Override
|
||||
public void afterRefresh() {
|
||||
int size = instanceMap.size();
|
||||
instanceMap.clear();
|
||||
log.debug("缓存信息清理 => {} 条", size);
|
||||
if(instanceMap != null
|
||||
&& !instanceMap.isEmpty()){
|
||||
int size = instanceMap.size();
|
||||
instanceMap.clear();
|
||||
log.debug("缓存信息清理 => {} 条", size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,14 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
import com.serliunx.ddns.constant.InstanceSource;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 实例抽象实现
|
||||
* @author SerLiunx
|
||||
* @since 1.0
|
||||
*/
|
||||
@@ -17,6 +21,7 @@ import static com.serliunx.ddns.constant.SystemConstants.XML_ROOT_INSTANCE_NAME;
|
||||
@JacksonXmlRootElement(localName = XML_ROOT_INSTANCE_NAME)
|
||||
public abstract class AbstractInstance implements Instance {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractInstance.class);
|
||||
/**
|
||||
* 实例名称
|
||||
* <li> 全局唯一
|
||||
@@ -56,8 +61,30 @@ public abstract class AbstractInstance implements Instance {
|
||||
|
||||
@Override
|
||||
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();
|
||||
}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
|
||||
@@ -105,15 +132,6 @@ public abstract class AbstractInstance implements Instance {
|
||||
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();
|
||||
|
||||
/**
|
||||
* 更新前检查是否需要更新
|
||||
* @return 无需更新返回假, 否则返回真
|
||||
* 获取解析当前的ip地址
|
||||
* <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.provider.StaticCredentialProvider;
|
||||
import com.aliyun.sdk.service.alidns20150109.AsyncClient;
|
||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoRequest;
|
||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoResponse;
|
||||
import com.aliyun.sdk.service.alidns20150109.models.DescribeDomainRecordInfoResponseBody;
|
||||
import com.aliyun.sdk.service.alidns20150109.models.*;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
import com.serliunx.ddns.support.NetworkContextHolder;
|
||||
import darabonba.core.client.ClientOverrideConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -107,12 +105,34 @@ public class AliyunInstance extends AbstractInstance {
|
||||
|
||||
@Override
|
||||
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
|
||||
protected boolean query() {
|
||||
debug("正在校验是否需要更新记录.");
|
||||
protected String query() {
|
||||
DescribeDomainRecordInfoRequest describeDomainRecordInfoRequest = DescribeDomainRecordInfoRequest.builder()
|
||||
.recordId(recordId)
|
||||
.build();
|
||||
@@ -122,24 +142,15 @@ public class AliyunInstance extends AbstractInstance {
|
||||
DescribeDomainRecordInfoResponse response = responseCompletableFuture.get(5, TimeUnit.SECONDS);
|
||||
DescribeDomainRecordInfoResponseBody body = response.getBody();
|
||||
if(body != null){
|
||||
String recordValue = 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 body.getValue();
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
error("出现了不应该出现的异常 => {}", e);
|
||||
return false;
|
||||
return null;
|
||||
} catch (TimeoutException e) {
|
||||
error("记录查询超时! 将跳过查询直接执行更新操作.");
|
||||
return true;
|
||||
error("记录查询超时!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +217,25 @@ public class AliyunInstance extends AbstractInstance {
|
||||
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){
|
||||
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;
|
||||
|
||||
/**
|
||||
* 腾讯云实例定义
|
||||
* @author SerLiunx
|
||||
* @since 1.0
|
||||
*/
|
||||
@@ -17,8 +18,8 @@ public class TencentInstance extends AbstractInstance {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean query() {
|
||||
return false;
|
||||
protected String query() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,6 @@ public final class NetworkContextHolder {
|
||||
}
|
||||
|
||||
public static String getIpAddress(){
|
||||
log.debug("正在尝试获取最新的IP地址.");
|
||||
if(IP_ADDRESS != null)
|
||||
return IP_ADDRESS;
|
||||
try {
|
||||
@@ -46,7 +45,6 @@ public final class NetworkContextHolder {
|
||||
log.error("IP地址获取超时.");
|
||||
return null;
|
||||
}
|
||||
log.debug("最新的IP地址获取成功.");
|
||||
return IP_ADDRESS;
|
||||
} catch (InterruptedException e) {
|
||||
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.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -38,6 +39,7 @@ public final class SystemInitializer implements Refreshable{
|
||||
|
||||
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
|
||||
private Set<Instance> instances;
|
||||
private Map<String, Instance> runningInstances;
|
||||
|
||||
SystemInitializer(Configuration configuration, MultipleSourceInstanceContext instanceContext) {
|
||||
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