feat: 新增icanhazip IP地址查询、调整HttpClient职能.

This commit is contained in:
2024-12-06 15:50:45 +08:00
parent c7ea252159
commit 048c358800
7 changed files with 99 additions and 33 deletions

View File

@@ -0,0 +1,17 @@
package com.serliunx.ddns.support.ipprovider;
import com.serliunx.ddns.support.okhttp.HttpClient;
/**
* ip数据提供商 <a href="https://icanhazip.com/">icanhazip</a>
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2024/12/6
*/
public final class IcanhazipProvider extends AbstractProvider {
@Override
protected String doGet() {
return HttpClient.httpGet("https://icanhazip.com/");
}
}

View File

@@ -1,5 +1,8 @@
package com.serliunx.ddns.support.ipprovider; package com.serliunx.ddns.support.ipprovider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.serliunx.ddns.support.okhttp.HttpClient; import com.serliunx.ddns.support.okhttp.HttpClient;
import com.serliunx.ddns.support.okhttp.IPAddressResponse; import com.serliunx.ddns.support.okhttp.IPAddressResponse;
@@ -13,12 +16,22 @@ import com.serliunx.ddns.support.okhttp.IPAddressResponse;
*/ */
public final class IpApiProvider extends AbstractProvider { public final class IpApiProvider extends AbstractProvider {
private static final ObjectMapper JSON_MAPPER = new JsonMapper();
@Override @Override
protected String doGet() { protected String doGet() {
IPAddressResponse response = HttpClient.getIPAddress(); final String response = HttpClient.httpGet("http://ip-api.com/json");
if (response == null) { if (response == null
|| response.isEmpty()) {
return null; return null;
} }
return response.getQuery();
try {
IPAddressResponse ipAddressResponse = JSON_MAPPER.readValue(response, IPAddressResponse.class);
return ipAddressResponse.getQuery();
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
} }
} }

View File

@@ -1,12 +1,11 @@
package com.serliunx.ddns.support.okhttp; package com.serliunx.ddns.support.okhttp;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.serliunx.ddns.config.Configuration; import com.serliunx.ddns.config.Configuration;
import com.serliunx.ddns.config.ConfigurationKeys; import com.serliunx.ddns.config.ConfigurationKeys;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import okhttp3.ResponseBody;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -22,10 +21,9 @@ import java.util.concurrent.TimeUnit;
*/ */
public final class HttpClient { public final class HttpClient {
private static OkHttpClient CLIENT = null; private static OkHttpClient CLIENT;
private static final Logger log = LoggerFactory.getLogger(HttpClient.class); private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
private static final ObjectMapper JSON_MAPPER = new JsonMapper();
private static final int DEFAULT_OVERTIME = 3; private static final int DEFAULT_OVERTIME = 3;
private HttpClient() {throw new UnsupportedOperationException();} private HttpClient() {throw new UnsupportedOperationException();}
@@ -39,29 +37,28 @@ public final class HttpClient {
} }
/** /**
* 获取本机的ip地址 * 发送GET请求
* *
* @return 响应结果 * @param url 请求地址
* @return 响应
*/ */
public static IPAddressResponse getIPAddress() { public static String httpGet(String url) {
Request request = new Request.Builder() final Request request = new Request.Builder()
.url("http://ip-api.com/json") .url(url)
.get() .get()
.build(); .build();
try (Response response = CLIENT.newCall(request).execute()) { try (Response response = CLIENT.newCall(request).execute()) {
if (!response.isSuccessful() || response.body() == null) { if (!response.isSuccessful()
|| response.body() == null) {
return null; return null;
} }
String body = response.body().string(); final ResponseBody responseBody = response.body();
if (body.isEmpty()) {
return null;
}
return JSON_MAPPER.readValue(body, IPAddressResponse.class); return responseBody.string();
} catch (Exception e) { } catch (Exception e) {
log.error("ip地址获取异常:", e); log.error("http 接口异常:", e);
} }
return null; return null;
} }

View File

@@ -20,11 +20,10 @@ import java.util.concurrent.locks.ReentrantLock;
public final class SQLiteConnector implements Refreshable { public final class SQLiteConnector implements Refreshable {
private volatile Connection connection; private volatile Connection connection;
private volatile boolean initialized = false;
private final Lock initLock = new ReentrantLock(); private final Lock initLock = new ReentrantLock();
private volatile boolean initialized = false;
private static final Logger log = LoggerFactory.getLogger(SQLiteConnector.class); private static final Logger log = LoggerFactory.getLogger(SQLiteConnector.class);
private static final SQLiteConnector INSTANCE = new SQLiteConnector(); private static final SQLiteConnector INSTANCE = new SQLiteConnector();
@@ -53,6 +52,9 @@ public final class SQLiteConnector implements Refreshable {
log.info("initialing sqlite connection."); log.info("initialing sqlite connection.");
connection = DriverManager.getConnection(SystemConstants.SQLITE_URL); connection = DriverManager.getConnection(SystemConstants.SQLITE_URL);
// 尝试创建数据库表, 只会执行一次
tryCreateTables();
initialized = true; initialized = true;
log.info("sqlite connection successfully initialized."); log.info("sqlite connection successfully initialized.");
} catch (Exception e) { } catch (Exception e) {
@@ -63,6 +65,16 @@ public final class SQLiteConnector implements Refreshable {
} }
} }
/**
* 尝试创建数据库表
* <li> 不存在时创建
*/
private void tryCreateTables() {
if (connection == null) {
throw new IllegalStateException("sql connection not initialized");
}
}
/** /**
* 是否已经初始化 * 是否已经初始化
*/ */

View File

@@ -35,14 +35,25 @@ public final class ThreadFactoryBuilder {
* @return 线程工厂 * @return 线程工厂
*/ */
public ThreadFactory ofNamePattern(final String pattern) { public ThreadFactory ofNamePattern(final String pattern) {
return new ThreadFactory() { return new NamePatternThreadFactory(pattern);
}
/**
* 线程工厂之模板名称
*/
private static class NamePatternThreadFactory implements ThreadFactory {
private final AtomicInteger counter = new AtomicInteger(0); private final AtomicInteger counter = new AtomicInteger(0);
private final String pattern;
public NamePatternThreadFactory(String pattern) {
this.pattern = pattern;
}
@Override @Override
public Thread newThread(@NotNull Runnable r) { public Thread newThread(@NotNull Runnable r) {
return new Thread(r, String.format(pattern, counter.getAndIncrement())); return new Thread(r, String.format(pattern, counter.getAndIncrement()));
} }
};
} }
} }

View File

@@ -5,11 +5,10 @@ import com.serliunx.ddns.constant.SystemConstants;
import com.serliunx.ddns.core.context.FileInstanceContext; import com.serliunx.ddns.core.context.FileInstanceContext;
import com.serliunx.ddns.core.context.GenericInstanceContext; import com.serliunx.ddns.core.context.GenericInstanceContext;
import com.serliunx.ddns.core.context.MultipleSourceInstanceContext; import com.serliunx.ddns.core.context.MultipleSourceInstanceContext;
import com.serliunx.ddns.core.factory.JsonFileInstanceFactory; import com.serliunx.ddns.core.factory.*;
import com.serliunx.ddns.core.factory.XmlFileInstanceFactory;
import com.serliunx.ddns.core.factory.YamlFileInstanceFactory;
import com.serliunx.ddns.core.instance.AliyunInstance; import com.serliunx.ddns.core.instance.AliyunInstance;
import com.serliunx.ddns.core.instance.Instance; import com.serliunx.ddns.core.instance.Instance;
import com.serliunx.ddns.support.sqlite.SQLiteConnector;
import org.junit.Test; import org.junit.Test;
/** /**
@@ -33,13 +32,13 @@ public class ContextTest {
} }
@Test @Test
public void testFileContext(){ public void testFileContext() {
FileInstanceContext context = new FileInstanceContext(); FileInstanceContext context = new FileInstanceContext();
context.getSortedListableInstanceFactories().forEach(System.out::println); context.getSortedListableInstanceFactories().forEach(System.out::println);
} }
@Test @Test
public void testEmptyContext(){ public void testEmptyContext() {
GenericInstanceContext instanceContext = new GenericInstanceContext(false); GenericInstanceContext instanceContext = new GenericInstanceContext(false);
instanceContext.addListableInstanceFactory(new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR)); instanceContext.addListableInstanceFactory(new YamlFileInstanceFactory(SystemConstants.USER_INSTANCE_DIR));
@@ -52,4 +51,14 @@ public class ContextTest {
instanceContext.getInstances().forEach(System.out::println); instanceContext.getInstances().forEach(System.out::println);
} }
@Test
public void testGic1() {
MultipleSourceInstanceContext context = new GenericInstanceContext(true);
ListableInstanceFactory factory = new DatabaseInstanceFactory(SQLiteConnector.getInstance());
context.addListableInstanceFactory(factory);
context.refresh();
}
} }

View File

@@ -1,5 +1,6 @@
package com.serliunx.ddns.test.support; package com.serliunx.ddns.test.support;
import com.serliunx.ddns.support.ipprovider.IcanhazipProvider;
import com.serliunx.ddns.support.ipprovider.IpApiProvider; import com.serliunx.ddns.support.ipprovider.IpApiProvider;
import com.serliunx.ddns.support.ipprovider.Provider; import com.serliunx.ddns.support.ipprovider.Provider;
import com.serliunx.ddns.support.ipprovider.ScheduledProvider; import com.serliunx.ddns.support.ipprovider.ScheduledProvider;
@@ -26,4 +27,10 @@ public class ProviderTest {
String ip = provider.get(); String ip = provider.get();
System.out.println(ip); System.out.println(ip);
} }
@Test
public void testIcanhazipProvider() {
Provider provider = new IcanhazipProvider();
System.out.println(provider.get());
}
} }