From 320603f754b9d6e7dbb9386f08271965544ce3cb Mon Sep 17 00:00:00 2001 From: carm Date: Sat, 17 Sep 2022 01:18:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(all):=20=E9=A1=B9=E7=9B=AE=E5=A4=A7?= =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=8C=E4=BC=98=E5=8C=96=E5=A4=A7=E9=87=8F?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .doc/REQUEST.md | 18 ++ .github/workflows/deploy.yml | 18 +- .gitignore | 40 +++- README.md | 60 +++--- pom.xml | 119 +++++----- src/main/java/cc/carm/app/aliddns/Main.java | 84 +++++--- .../cc/carm/app/aliddns/conf/AppConfig.java | 37 ++++ .../cc/carm/app/aliddns/conf/QueryConfig.java | 16 ++ .../carm/app/aliddns/conf/ServiceConfig.java | 17 ++ .../app/aliddns/manager/ConfigManager.java | 204 ------------------ .../app/aliddns/manager/RequestManager.java | 58 ++--- .../app/aliddns/model/RequestRegistry.java | 77 +++++++ .../carm/app/aliddns/model/UpdateRequest.java | 49 ++--- .../cc/carm/app/aliddns/utils/FileUtils.java | 34 +++ .../carm/app/aliddns/utils/TimeDateUtils.java | 29 +++ .../carm/app/aliddns/utils/VersionReader.java | 41 ++++ src/main/resources/config.yml | 27 --- src/main/resources/version.properties | 1 + src/test/java/ConfigTest.java | 20 ++ 19 files changed, 540 insertions(+), 409 deletions(-) create mode 100644 .doc/REQUEST.md create mode 100644 src/main/java/cc/carm/app/aliddns/conf/AppConfig.java create mode 100644 src/main/java/cc/carm/app/aliddns/conf/QueryConfig.java create mode 100644 src/main/java/cc/carm/app/aliddns/conf/ServiceConfig.java delete mode 100644 src/main/java/cc/carm/app/aliddns/manager/ConfigManager.java create mode 100644 src/main/java/cc/carm/app/aliddns/model/RequestRegistry.java create mode 100644 src/main/java/cc/carm/app/aliddns/utils/FileUtils.java create mode 100644 src/main/java/cc/carm/app/aliddns/utils/TimeDateUtils.java create mode 100644 src/main/java/cc/carm/app/aliddns/utils/VersionReader.java delete mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/version.properties create mode 100644 src/test/java/ConfigTest.java diff --git a/.doc/REQUEST.md b/.doc/REQUEST.md new file mode 100644 index 0000000..9c485c6 --- /dev/null +++ b/.doc/REQUEST.md @@ -0,0 +1,18 @@ +# 配置文件参数 + +### `主域名` domain + +如 `www.baidu.com` 中的 _baidu.com_ 就是主域名。 + +### 主机记录 `record` + +如 `www.baidu.com` 中的 _www_ 就是主机记录; +而 `@` 符号代表通过直接通过主域名直通访问。 + +### ipv6 (IPv6记录) + +该记录是否为IPv6 *(AAAA)* 记录,默认为 `false` 。 + +### access-key (访问密键) & access-secret (访问密钥) + +用于验证更改域名内容,在阿里云的个人控制台中获取。 \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 95322a9..4201dcb 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,8 +26,22 @@ jobs: server-id: github server-username: MAVEN_USERNAME server-password: MAVEN_TOKEN + - name: "Deploy" - run: mvn -B deploy -DskipTests --file pom.xml + run: mvn -B deploy --file pom.xml env: MAVEN_USERNAME: ${{ github.repository_owner }} - MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file + MAVEN_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: "Copy example configuration" + run: cp target/example.yml .asset/ + + - name: "Release Asset Upload" + id: upload-release-asset + uses: shogo82148/actions-upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: .asset/*.jar + asset_content_type: application/java-archive \ No newline at end of file diff --git a/.gitignore b/.gitignore index 445f9d3..4b0d7d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,36 @@ -/.idea/ -/target/ -./*.iml -*.iml +.asset/ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/ +**.iws +**.iml +**.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index b33fd81..d0f4c83 100644 --- a/README.md +++ b/README.md @@ -16,34 +16,40 @@ java -jar aliddns-updater-.jar ## 配置文件示例 +关于请求的具体配置内容请参考 [请求配置](.doc/REQUEST.md) 。 + ```yaml -version: 1.7 +# 配置文件版本,请不要修改。 +version: 2.0 -#输出域名记录查询返回信息 +# 是否输出域名记录查询返回信息。(用于调试) debug: false -Service: - #更新间隔(毫秒) - period: 900000 - # 阿里云地域ID,可以不改动 +service: + # 更新间隔,单位为秒。 + period: 900 + # 阿里云接口地域ID,可以不改动。 # 请参考 https://help.aliyun.com/knowledge_detail/40654.html - region-id: "cn-hangzhou" - # IP地址查询相关设定 - # 用于获取对应的IP地址,以更新到域名 + region-id: cn-hangzhou + +# 本机IP查询接口配置。 +# 用于获取对应的IP地址,以更新到域名记录。 +query: + # IPv4地址获取链接 + v4: http://ifconfig.me/ip + # IPv6地址获取链接 (可选) # 如不需要IPV6,则可以直接将地址留空。 - ipQuery: - IPv4: "http://ifconfig.me/ip" - IPv6: "https://v6.ip.zxinc.org/getip" - - -#更新任务列表 -UpdateRequests: - test: - domain: "test.cn" # 域名,如 www.baidu.com 中的 baidu.com - AccessKey: "xx" # 访问密钥 (在个人控制台中获取) - AccessSecret: "xx" # 访问密码 (在个人控制台中获取) - record: "www" #主机记录 - ipv6: false # 该记录是否为IPv6[AAAA]记录 (默认为false) + v6: https://v6.ip.zxinc.org/getip + +# 更新任务配置。 +# 具体配置请参考 https://github.com/CarmJos/AliDDNS-Updater/blob/master/.doc/REQUEST.md +requests: + demo: + domain: example.com + record: '@' + ipv6: false + access-key: YOUR-ACCESS-KEY + access-secret: YOUR-ACCESS-SECRET ``` ## 守护进程示例 @@ -56,6 +62,10 @@ UpdateRequests: 请参考 [windows环境下批处理实现守护进程](https://blog.csdn.net/qin9r3y/article/details/22805095) +## 视频教程 + +您可以 [点击这里](https://www.bilibili.com/video/BV1t54y147aQ) 查看由开发者本人制作的简易视频讲解。 + ## 支持与捐赠 若您觉得本软件做的不错,您可以捐赠支持我! @@ -77,8 +87,10 @@ UpdateRequests: > #### 可以用来盈利 > 你可以在分发软件的时候收费,但你必须在收费前向你的客户提供该软件的 GNU GPL 许可协议,以便让他们知道,他们可以从别的渠道免费得到这份软件,以及你收费的理由。 > #### 可自由修改 -> 如果你想添加或删除某个功能,没问题,如果你想在别的项目中使用部分代码,也没问题,唯一的要求是,使用了这段代码的项目也必须使用 GPL 协议。 +> 如果你想添加或删除某个功能,没问题,如果你想在别的项目中使用部分代码,也没问题,唯一的要求是,使用了这段代码的项目也必须使用 +> GPL 协议。 > -> 需要注意的是,分发的时候,需要明确提供源代码和二进制文件,另外,用于某些程序的某些协议有一些问题和限制,你可以看一下 @PierreJoye 写的 Practical Guide to GPL Compliance 一文。使用 GPL 协议,你必须在源代码代码中包含相应信息,以及协议本身。 +> 需要注意的是,分发的时候,需要明确提供源代码和二进制文件,另外,用于某些程序的某些协议有一些问题和限制,你可以看一下 +> @PierreJoye 写的 Practical Guide to GPL Compliance 一文。使用 GPL 协议,你必须在源代码代码中包含相应信息,以及协议本身。 > > *以上文字来自 [五种开源协议GPL,LGPL,BSD,MIT,Apache](https://www.oschina.net/question/54100_9455) 。* diff --git a/pom.xml b/pom.xml index e5b964a..81e27a8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,14 +6,16 @@ cc.carm.app aliddns-updater - 2.0.3 + 3.0.0 jar - 8 - 8 + 8 + ${project.jdk.version} + ${project.jdk.version} UTF-8 UTF-8 + cc.carm.app.aliddns.Main @@ -24,12 +26,12 @@ GitHub Issues - ${project.url}/issues + https://github.com/CarmJos/AliDDNS-Updater/issues GitHub Actions - ${project.url}/actions/workflows/maven.yml + https://github.com/CarmJos/AliDDNS-Updater/actions/workflows/maven.yml @@ -57,7 +59,7 @@ GitHub Packages https://maven.pkg.github.com/CarmJos/${project.name} - ${project.url}/releases + https://github.com/CarmJos/AliDDNS-Updater/releases @@ -94,15 +96,16 @@ com.aliyun aliyun-java-sdk-alidns - 2.6.19 + 3.0.0 compile + com.aliyun aliyun-java-sdk-core - 4.5.17 + 4.6.1 compile @@ -110,28 +113,35 @@ com.alibaba fastjson - 1.2.73 + 1.2.83 compile - cc.bukkit - BukkitConfiguration - 1.16.1-R0.1-SNAPSHOT + cc.carm.lib + easyconfiguration-yaml + 3.2.0 + compile + + + + cc.carm.lib + githubreleases4j + 1.3.1 compile org.jetbrains annotations - 22.0.0 + 23.0.0 compile junit junit - 4.13.1 + 4.13.2 test @@ -142,19 +152,43 @@ org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 + maven-clean-plugin + 2.5 - 1.8 - 1.8 - UTF-8 - -parameters + + + ${project.basedir}/.asset/ + true + + **/* + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false org.apache.maven.plugins maven-jar-plugin - 3.2.0 + 3.2.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + -parameters + org.apache.maven.plugins @@ -182,46 +216,27 @@ + ${project.name}-${project.version} + ${project.basedir}/.asset + *:* META-INF/MANIFEST.MF + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA - - true - - - - maven-assembly-plugin - - - jar-with-dependencies - - - + + ${mainClass} - - - - - - make-assembly - package - - assembly - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - false + + + true diff --git a/src/main/java/cc/carm/app/aliddns/Main.java b/src/main/java/cc/carm/app/aliddns/Main.java index c903d8c..56585d0 100644 --- a/src/main/java/cc/carm/app/aliddns/Main.java +++ b/src/main/java/cc/carm/app/aliddns/Main.java @@ -1,44 +1,59 @@ package cc.carm.app.aliddns; -import cc.carm.app.aliddns.manager.ConfigManager; +import cc.carm.app.aliddns.conf.AppConfig; +import cc.carm.app.aliddns.conf.ServiceConfig; import cc.carm.app.aliddns.manager.RequestManager; +import cc.carm.app.aliddns.utils.FileUtils; +import cc.carm.app.aliddns.utils.TimeDateUtils; +import cc.carm.app.aliddns.utils.VersionReader; +import cc.carm.lib.configuration.EasyConfiguration; +import cc.carm.lib.configuration.yaml.YAMLConfigProvider; +import cc.carm.lib.githubreleases4j.GithubReleases4J; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; public class Main { - private static ConfigManager configManager; private static RequestManager requestManager; - private static TimerTask updateTimerTask; - public static void main(String[] args) throws InterruptedException { print("-------------------------------------------"); - print("阿里云服务 DDNS更新器"); + print("阿里云服务 DDNS更新器 (v" + getCurrentVersion() + ")"); print("项目地址 https://git.carm.cc/AliDDNS-Updater"); print("-------------------------------------------"); Thread.sleep(1000L); - print("初始化配置文件管理..."); - configManager = new ConfigManager(); - getConfigManager().initConfig(); - - if (getConfigManager().getConfig().getDouble("version", 1.0) < getConfigManager().getConfigVersion()) { + print("初始化配置文件管理..."); + YAMLConfigProvider configuration = EasyConfiguration.from("config.yml"); + double configVersion = configuration.getConfiguration().getDouble("version", 1.0); + if (configVersion < AppConfig.CURRENT_VERSION) { print(" 配置文件过时,正在尝试重新创建..."); - getConfigManager().backupConfig(); - getConfigManager().createConfig(); + try { + FileUtils.copy(configuration.getFile(), "config-v" + configVersion + ".bak.yml"); + if (configuration.getFile().delete()) { + configuration = EasyConfiguration.from("config.yml"); + } + } catch (IOException e) { + e.printStackTrace(); + } } - - print(" 完成加载配置文件 v" + getConfigManager().getConfig().getDouble("version", 1.0)); - + configuration.initialize(AppConfig.class); + print(" 完成加载配置文件 v" + AppConfig.CURRENT_VERSION); print(); + if (AppConfig.CHECK_UPDATE.getNotNull()) { + info("正在检查更新(可以在配置文件中关闭此功能)... "); + checkUpdate(); + print(); + } + print("初始化记录请求管理器..."); requestManager = new RequestManager(); - int loaded = requestManager.loadRequests(); + int loaded = requestManager.getRequests().size(); if (loaded < 1) { print(" 您没有配置任何记录,请检查配置文件!"); @@ -48,16 +63,16 @@ public static void main(String[] args) throws InterruptedException { } print(); - print("所有任务已设定为每 " + ConfigManager.getPeriod() + " 毫秒进行一次更新。"); + print("所有任务已设定为每 " + TimeDateUtils.toDHMSStyle(ServiceConfig.PERIOD.getNotNull()) + " 进行一次更新。"); print("-------------------------------------------"); Timer timer = new Timer(); - timer.schedule(updateTimerTask = new TimerTask() { + timer.schedule(new TimerTask() { @Override public void run() { getRequestManager().doUpdate(); } - }, 500, ConfigManager.getPeriod()); + }, 500, ServiceConfig.PERIOD.getNotNull() * 1000L); } @@ -83,23 +98,38 @@ public static void info(String... messages) { } public static void debug(String... messages) { - printWithPrefix("[DEBUG] ", messages); + if (AppConfig.DEBUG.getNotNull()) printWithPrefix("[DEBUG] ", messages); } - public static void error(String... messages) { + public static void severe(String... messages) { printWithPrefix("[ERROR] ", messages); } - public static ConfigManager getConfigManager() { - return configManager; - } - public static RequestManager getRequestManager() { return requestManager; } - public static TimerTask getUpdateTimerTask() { - return updateTimerTask; + protected static void checkUpdate() { + String currentVersion = getCurrentVersion(); + Integer behindVersions = GithubReleases4J.getVersionBehind("CarmJos", "AliDDNS-Updater", currentVersion); + String downloadURL = GithubReleases4J.getReleasesURL("CarmJos", "AliDDNS-Updater"); + + if (behindVersions == null) { + severe(" 检查更新失败,请您定期查看插件是否更新,避免安全问题。"); + severe(" 下载地址 " + downloadURL); + } else if (behindVersions == 0) { + info(" 检查完成,当前已是最新版本。"); + } else if (behindVersions > 0) { + info(" 发现新版本! 目前已落后 " + behindVersions + " 个版本。"); + info(" 最新版下载地址 " + downloadURL); + } else { + severe(" 检查更新失败! 当前版本未知,请您使用原生版本以避免安全问题。"); + severe(" 最新版下载地址 " + downloadURL); + } + } + + protected static String getCurrentVersion() { + return new VersionReader("version.properties").get("version"); } } diff --git a/src/main/java/cc/carm/app/aliddns/conf/AppConfig.java b/src/main/java/cc/carm/app/aliddns/conf/AppConfig.java new file mode 100644 index 0000000..c318cf8 --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/conf/AppConfig.java @@ -0,0 +1,37 @@ +package cc.carm.app.aliddns.conf; + +import cc.carm.app.aliddns.model.RequestRegistry; +import cc.carm.lib.configuration.core.ConfigurationRoot; +import cc.carm.lib.configuration.core.annotation.HeaderComment; +import cc.carm.lib.configuration.core.value.ConfigValue; +import cc.carm.lib.configuration.core.value.type.ConfiguredSection; +import cc.carm.lib.configuration.core.value.type.ConfiguredValue; + +@SuppressWarnings("unused") +public class AppConfig extends ConfigurationRoot { + + public static final double CURRENT_VERSION = 2.0; + + @HeaderComment("配置文件版本,请不要修改。") + public static final ConfigValue VERSION = ConfiguredValue.of(Double.class, 2.0D); + + @HeaderComment("是否输出域名记录查询返回信息。(用于调试)") + public static final ConfigValue DEBUG = ConfiguredValue.of(Boolean.class, false); + + @HeaderComment("是否检查本程序更新。(默认开启)") + public static final ConfigValue CHECK_UPDATE = ConfiguredValue.of(Boolean.class, true); + + public static final Class SERVICE = ServiceConfig.class; + @HeaderComment({"", "本机IP查询接口配置。", "用于获取对应的IP地址,以更新到域名记录。"}) + public static final Class QUERY = QueryConfig.class; + + @HeaderComment({ + "", "更新任务配置。", + "具体配置请参考 https://github.com/CarmJos/AliDDNS-Updater/blob/master/.doc/REQUEST.md", + }) + public static final ConfigValue REQUESTS = ConfiguredSection.builder(RequestRegistry.class) + .parseValue((w, d) -> RequestRegistry.loadFrom(w)) + .serializeValue(RequestRegistry::serialize) + .defaults(RequestRegistry.defaults()) + .build(); +} diff --git a/src/main/java/cc/carm/app/aliddns/conf/QueryConfig.java b/src/main/java/cc/carm/app/aliddns/conf/QueryConfig.java new file mode 100644 index 0000000..3b3edb1 --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/conf/QueryConfig.java @@ -0,0 +1,16 @@ +package cc.carm.app.aliddns.conf; + +import cc.carm.lib.configuration.core.ConfigurationRoot; +import cc.carm.lib.configuration.core.annotation.HeaderComment; +import cc.carm.lib.configuration.core.value.ConfigValue; +import cc.carm.lib.configuration.core.value.type.ConfiguredValue; + +public class QueryConfig extends ConfigurationRoot { + + @HeaderComment({"IPv4地址获取链接"}) + public static final ConfigValue V4 = ConfiguredValue.of(String.class, "http://ifconfig.me/ip"); + + @HeaderComment({"IPv6地址获取链接 (可选)", "如不需要IPV6,则可以直接将地址留空。"}) + public static final ConfigValue V6 = ConfiguredValue.of(String.class, "https://v6.ip.zxinc.org/getip"); + +} diff --git a/src/main/java/cc/carm/app/aliddns/conf/ServiceConfig.java b/src/main/java/cc/carm/app/aliddns/conf/ServiceConfig.java new file mode 100644 index 0000000..dd2c473 --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/conf/ServiceConfig.java @@ -0,0 +1,17 @@ +package cc.carm.app.aliddns.conf; + +import cc.carm.lib.configuration.core.ConfigurationRoot; +import cc.carm.lib.configuration.core.annotation.HeaderComment; +import cc.carm.lib.configuration.core.value.ConfigValue; +import cc.carm.lib.configuration.core.value.type.ConfiguredValue; + +public class ServiceConfig extends ConfigurationRoot { + + @HeaderComment("更新间隔,单位为秒。") + public static final ConfigValue PERIOD = ConfiguredValue.of(Integer.class, 900); + + @HeaderComment({"阿里云接口地域ID,可以不改动。", "请参考 https://help.aliyun.com/knowledge_detail/40654.html"}) + public static final ConfigValue REGION_ID = ConfiguredValue.of(String.class, "cn-hangzhou"); + + +} diff --git a/src/main/java/cc/carm/app/aliddns/manager/ConfigManager.java b/src/main/java/cc/carm/app/aliddns/manager/ConfigManager.java deleted file mode 100644 index 00bd2bd..0000000 --- a/src/main/java/cc/carm/app/aliddns/manager/ConfigManager.java +++ /dev/null @@ -1,204 +0,0 @@ -package cc.carm.app.aliddns.manager; - -import cc.carm.app.aliddns.Main; -import com.google.common.base.Charsets; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.net.URL; -import java.net.URLConnection; - -public class ConfigManager { - - private static ConfigManager instance; - - private final double CONFIG_VERSION = 1.7; - - private File sourceFile; - private File dataFolder; - private File configFile; - - private FileConfiguration newConfig = null; - - - public ConfigManager() { - instance = this; - - String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); - this.sourceFile = new File(path); - this.dataFolder = sourceFile.getParentFile(); - this.configFile = new File(dataFolder, "config.yml"); - - } - - public static boolean isDebugMode() { - return getInstance().getConfig().getBoolean("debug", false); - } - - public static String getRegionID() { - return getInstance().getConfig().getString("Service.region-id", "cn-hangzhou"); - } - - public static long getPeriod() { - return getInstance().getConfig().getLong("Service.period", 900000L); - } - - public static String getIPv4QueryURL() { - return getInstance().getConfig().getString("Service.ipQuery.IPv4", "http://ifconfig.me/ip"); - } - - @Nullable - public static String getIPv6QueryURL() { - return getInstance().getConfig().getString("Service.ipQuery.IPv6", "https://v6.ip.zxinc.org/getip"); - } - - public static boolean isIPV6Enabled() { - return getIPv6QueryURL() != null && getIPv6QueryURL().length() > 0; - } - - public static ConfigManager getInstance() { - return instance; - } - - public FileConfiguration getConfig() { - if (newConfig == null) { - reloadConfig(); - } - return newConfig; - } - - public void reloadConfig() { - newConfig = YamlConfiguration.loadConfiguration(configFile); - - final InputStream defConfigStream = getResource("config.yml"); - if (defConfigStream == null) { - return; - } - - final YamlConfiguration defConfig; - defConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(defConfigStream, Charsets.UTF_8)); - newConfig.setDefaults(defConfig); - } - - public void saveConfig() { - try { - getConfig().save(configFile); - } catch (IOException ex) { - Main.error("Could not save config to " + configFile); - } - } - - public void initConfig() { - if (!configFile.exists()) { - createConfig(); - } else { - Main.print(" 配置文件加载于 " + configFile.getAbsolutePath()); - } - } - - public void backupConfig() { - try { - copy(configFile, "config.yml.bak"); - Main.print(" 旧的配置文件已备份与 " + configFile.getAbsolutePath() + ".bak"); - this.configFile = new File(dataFolder, "config.yml"); - } catch (Exception ignore) { - - } - } - - - public void createConfig() { - saveResource("config.yml", true); - Main.print(" 配置文件创建于 " + configFile.getAbsolutePath()); - } - - public void saveResource(String resourcePath, boolean replace) { - if (resourcePath == null || resourcePath.equals("")) { - throw new IllegalArgumentException("ResourcePath cannot be null or empty"); - } - - resourcePath = resourcePath.replace('\\', '/'); - InputStream in = getResource(resourcePath); - if (in == null) { - throw new IllegalArgumentException("The embedded resource '" + resourcePath + "' cannot be found in " + sourceFile); - } - - File outFile = new File(dataFolder, resourcePath); - int lastIndex = resourcePath.lastIndexOf('/'); - File outDir = new File(dataFolder, resourcePath.substring(0, lastIndex >= 0 ? lastIndex : 0)); - - if (!outDir.exists()) { - outDir.mkdirs(); - } - - try { - if (!outFile.exists() || replace) { - OutputStream out = new FileOutputStream(outFile); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - out.close(); - in.close(); - } else { - Main.error("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); - } - } catch (IOException ex) { - Main.error("Could not save " + outFile.getName() + " to " + outFile); - } - } - - public InputStream getResource(String filename) { - if (filename == null) { - throw new IllegalArgumentException("Filename cannot be null"); - } - - try { - URL url = this.getClass().getClassLoader().getResource(filename); - - if (url == null) { - return null; - } - - URLConnection connection = url.openConnection(); - connection.setUseCaches(false); - return connection.getInputStream(); - } catch (IOException ex) { - return null; - } - } - - - /** - * Rename the file. - */ - public static void copy(final File file, final String newName) throws IOException { - // file is null then return false - if (file == null) return; - // file doesn't exist then return false - if (!file.exists()) return; - // the new name equals old name then return true - if (newName.equals(file.getName())) return; - File newFile = new File(file.getParent() + File.separator + newName); - // the new name of file exists then return false - if (newFile.exists()) { - newFile.delete(); - } - try (InputStream input = new FileInputStream(file); OutputStream output = new FileOutputStream(newFile)) { - byte[] buf = new byte[1024]; - int bytesRead; - while ((bytesRead = input.read(buf)) > 0) { - output.write(buf, 0, bytesRead); - } - } - } - - public double getConfigVersion() { - return CONFIG_VERSION; - } - - -} diff --git a/src/main/java/cc/carm/app/aliddns/manager/RequestManager.java b/src/main/java/cc/carm/app/aliddns/manager/RequestManager.java index cf22000..f74eaf5 100644 --- a/src/main/java/cc/carm/app/aliddns/manager/RequestManager.java +++ b/src/main/java/cc/carm/app/aliddns/manager/RequestManager.java @@ -1,9 +1,10 @@ package cc.carm.app.aliddns.manager; import cc.carm.app.aliddns.Main; +import cc.carm.app.aliddns.conf.AppConfig; +import cc.carm.app.aliddns.conf.QueryConfig; +import cc.carm.app.aliddns.model.RequestRegistry; import cc.carm.app.aliddns.model.UpdateRequest; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -16,13 +17,7 @@ public class RequestManager { - public final String SECTION = "UpdateRequests"; - - private int updatedTimes = 1; - private boolean hasIPv6 = false; - private final SimpleDateFormat format; - public final HashMap requests; public RequestManager() { @@ -31,43 +26,26 @@ public RequestManager() { } - public int loadRequests() { - requests.clear(); - - FileConfiguration config = Main.getConfigManager().getConfig(); - ConfigurationSection rootSection = config.getConfigurationSection(SECTION); - if (rootSection != null) { - - for (String taskName : rootSection.getKeys(false)) { - ConfigurationSection requestSection = rootSection.getConfigurationSection(taskName); - if (requestSection == null) continue; - UpdateRequest request = UpdateRequest.readConfiguration(requestSection); - if (request.isIpv6() && !ConfigManager.isIPV6Enabled()) { - Main.info("记录 [" + taskName + "] 为IPv6任务,但本实例未启用IPv6,跳过加载。"); - continue; - } - requests.put(taskName, request); - } - } - - this.hasIPv6 = getRequests().values().stream().anyMatch(UpdateRequest::isIpv6); - this.updatedTimes = 1; - - return getRequests().size(); + public static boolean isIPV6Enabled() { + String v6URL = QueryConfig.V6.get(); + return v6URL != null && v6URL.length() > 0; } + public RequestRegistry getRegistry() { + return AppConfig.REQUESTS.getNotNull(); + } public void doUpdate() { - Main.info("[" + this.format.format(new Date()) + "]" + " 开始执行第" + updatedTimes + "次更新..."); + Main.info("[" + this.format.format(new Date()) + "]" + " 开始执行第" + getRegistry().getUpdateCount() + "次更新..."); - Main.info("从 " + ConfigManager.getIPv4QueryURL() + " 获取IPv4地址..."); + Main.info("从 " + QueryConfig.V4.getNotNull() + " 获取IPv4地址..."); String IPv4 = getCurrentHostIP(false); Main.info(" 获取完成,当前IPv4地址为 " + IPv4); String IPv6 = null; - if (ConfigManager.isIPV6Enabled() && this.hasIPv6) { - Main.info("从 " + ConfigManager.getIPv6QueryURL() + " 获取IPv6地址..."); + if (isIPV6Enabled() && getRegistry().hasV6Request()) { + Main.info("从 " + QueryConfig.V6.getNotNull() + " 获取IPv6地址..."); IPv6 = getCurrentHostIP(true); Main.info(" 获取完成,当前IPv6地址为 " + IPv6); } @@ -82,21 +60,21 @@ public void doUpdate() { try { currentRequest.doUpdate(currentRequest.isIpv6() ? IPv6 : IPv4); } catch (Exception exception) { - Main.error("在更新请求 [" + entry.getKey() + "] 时发生问题,请检查配置。"); + Main.severe("在更新请求 [" + entry.getKey() + "] 时发生问题,请检查配置。"); exception.printStackTrace(); } } - updatedTimes++; + getRegistry().countUpdate(); } public HashMap getRequests() { - return new HashMap<>(this.requests); + return new HashMap<>(getRegistry().listRequests()); } public static String getCurrentHostIP(boolean isIPV6) { StringBuilder result = new StringBuilder(); - String requestURL = isIPV6 ? ConfigManager.getIPv6QueryURL() : ConfigManager.getIPv4QueryURL(); + String requestURL = isIPV6 ? QueryConfig.V6.getNotNull() : QueryConfig.V4.getNotNull(); try { // 使用HttpURLConnection网络请求第三方接口 @@ -114,7 +92,7 @@ public static String getCurrentHostIP(boolean isIPV6) { } in.close(); } catch (Exception e) { - Main.error("获取" + (isIPV6 ? "IPV6" : "IPV4") + "地址失败,请检查配置的请求连接和当前网络!"); + Main.severe("获取" + (isIPV6 ? "IPV6" : "IPV4") + "地址失败,请检查配置的请求连接和当前网络!"); e.printStackTrace(); } return result.toString(); diff --git a/src/main/java/cc/carm/app/aliddns/model/RequestRegistry.java b/src/main/java/cc/carm/app/aliddns/model/RequestRegistry.java new file mode 100644 index 0000000..d392e62 --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/model/RequestRegistry.java @@ -0,0 +1,77 @@ +package cc.carm.app.aliddns.model; + +import cc.carm.app.aliddns.Main; +import cc.carm.app.aliddns.manager.RequestManager; +import cc.carm.lib.configuration.core.source.ConfigurationWrapper; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class RequestRegistry { + + protected final LinkedHashMap requests; + protected int updateCount; + protected boolean hasV6Request; + + public RequestRegistry(LinkedHashMap requests) { + this.requests = requests; + this.updateCount = 1; + this.hasV6Request = requests.values().stream().anyMatch(UpdateRequest::isIpv6); + } + + public LinkedHashMap listRequests() { + return requests; + } + + public int getUpdateCount() { + return updateCount; + } + + public void countUpdate() { + this.updateCount++; + } + + public boolean hasV6Request() { + return hasV6Request; + } + + public @NotNull Map serialize() { + Map data = new LinkedHashMap<>(); + listRequests().forEach((k, r) -> data.put(k, r.serialize())); + return data; + } + + public static RequestRegistry loadFrom(ConfigurationWrapper section) { + LinkedHashMap data = new LinkedHashMap<>(); + if (section == null) return new RequestRegistry(data); + for (String taskName : section.getKeys(false)) { + ConfigurationWrapper requestSection = section.getConfigurationSection(taskName); + if (requestSection == null) continue; + + UpdateRequest request = new UpdateRequest( + requestSection.getString("access-key", "xx"), + requestSection.getString("access-secret", "xx"), + requestSection.getString("domain", "xx"), + requestSection.getString("record", "xx"), + requestSection.getBoolean("ipv6", false) + ); + + if (request.isIpv6() && !RequestManager.isIPV6Enabled()) { + Main.info("记录 [" + taskName + "] 为IPv6任务,但本实例未启用IPv6,跳过加载。"); + continue; + } + + data.put(taskName, request); + } + return new RequestRegistry(data); + } + + public static RequestRegistry defaults() { + LinkedHashMap data = new LinkedHashMap<>(); + data.put("demo", new UpdateRequest("YOUR-ACCESS-KEY", "YOUR-ACCESS-SECRET", "example.com", "@", false)); + return new RequestRegistry(data); + } + + +} diff --git a/src/main/java/cc/carm/app/aliddns/model/UpdateRequest.java b/src/main/java/cc/carm/app/aliddns/model/UpdateRequest.java index 606de3f..91110fc 100644 --- a/src/main/java/cc/carm/app/aliddns/model/UpdateRequest.java +++ b/src/main/java/cc/carm/app/aliddns/model/UpdateRequest.java @@ -1,20 +1,20 @@ package cc.carm.app.aliddns.model; import cc.carm.app.aliddns.Main; -import cc.carm.app.aliddns.manager.ConfigManager; +import cc.carm.app.aliddns.conf.ServiceConfig; import com.alibaba.fastjson.JSON; import com.aliyuncs.DefaultAcsClient; -import com.aliyuncs.IAcsClient; import com.aliyuncs.alidns.model.v20150109.DescribeDomainRecordsRequest; import com.aliyuncs.alidns.model.v20150109.DescribeDomainRecordsResponse; import com.aliyuncs.alidns.model.v20150109.UpdateDomainRecordRequest; import com.aliyuncs.alidns.model.v20150109.UpdateDomainRecordResponse; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.profile.DefaultProfile; -import org.bukkit.configuration.ConfigurationSection; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class UpdateRequest { @@ -24,10 +24,6 @@ public class UpdateRequest { @NotNull private final String accessKeySecret; - private final DefaultProfile profile; - private final IAcsClient client; - - private final String domain; private final String record; @@ -39,10 +35,18 @@ public UpdateRequest(@NotNull String accessKey, @NotNull String accessKeySecret, this.domain = domain; this.record = record; this.ipv6 = ipv6; + } - this.profile = DefaultProfile.getProfile(ConfigManager.getRegionID(), getAccessKey(), getAccessKeySecret()); - this.client = new DefaultAcsClient(profile); + public Map serialize() { + Map data = new LinkedHashMap<>(); + data.put("domain", getDomain()); + data.put("record", getRecord()); + data.put("ipv6", isIpv6()); + + data.put("access-key", getAccessKey()); + data.put("access-secret", getAccessKeySecret()); + return data; } @NotNull @@ -79,17 +83,6 @@ public String getRecordType() { return isIpv6() ? "AAAA" : "A"; } - @NotNull - public static UpdateRequest readConfiguration(@NotNull ConfigurationSection section) { - return new UpdateRequest( - section.getString("AccessKey", "xx"), - section.getString("AccessSecret", "xx"), - section.getString("domain", "xx"), - section.getString("record", "xx"), - section.getBoolean("ipv6", false) - ); - } - /** * 进行更新操作 * @@ -97,6 +90,8 @@ public static UpdateRequest readConfiguration(@NotNull ConfigurationSection sect */ public void doUpdate(String currentValue) throws ClientException { + DefaultProfile profile = DefaultProfile.getProfile(ServiceConfig.REGION_ID.getNotNull(), getAccessKey(), getAccessKeySecret()); + DefaultAcsClient client = new DefaultAcsClient(profile); DescribeDomainRecordsRequest describeDomainRecordsRequest = new DescribeDomainRecordsRequest(); describeDomainRecordsRequest.setDomainName(getDomain()); // 主域名 @@ -105,14 +100,13 @@ public void doUpdate(String currentValue) throws ClientException { // 获取主域名的所有解析记录列表 DescribeDomainRecordsResponse describeDomainRecordsResponse = client.getAcsResponse(describeDomainRecordsRequest); - if (ConfigManager.isDebugMode()) { - Main.debug(" \n" + JSON.toJSONString(describeDomainRecordsResponse, true)); - } + Main.debug(" \n" + JSON.toJSONString(describeDomainRecordsResponse, true)); + // 最新的一条解析记录 List domainRecords = describeDomainRecordsResponse.getDomainRecords(); if (domainRecords == null || domainRecords.size() == 0) { - Main.error(" 域名“" + getDomain() + "”下无" + getRecordType() + "记录 “" + getRecord() + "” ,请检查阿里云控制台。"); + Main.severe(" 域名“" + getDomain() + "”下无" + getRecordType() + "记录 “" + getRecord() + "” ,请检查阿里云控制台。"); return; } @@ -130,15 +124,12 @@ public void doUpdate(String currentValue) throws ClientException { //发出请求,收到回复 UpdateDomainRecordResponse updateDomainRecordResponse = client.getAcsResponse(updateDomainRecordRequest); - - if (ConfigManager.isDebugMode()) { - Main.debug(" \n" + JSON.toJSONString(updateDomainRecordResponse, true)); - } + Main.debug(" \n" + JSON.toJSONString(updateDomainRecordResponse, true)); if (recordID.equals(updateDomainRecordResponse.getRecordId())) { Main.info(" 记录 “" + getFullDomain() + "” 成功更新为 " + currentValue + " 。"); } else { - Main.error(" 记录 “" + getFullDomain() + "” 更新失败,请检查网络与配置。"); + Main.severe(" 记录 “" + getFullDomain() + "” 更新失败,请检查网络与配置。"); } } else { Main.info(" 记录 “" + getFullDomain() + "” 无需更新,跳过。"); diff --git a/src/main/java/cc/carm/app/aliddns/utils/FileUtils.java b/src/main/java/cc/carm/app/aliddns/utils/FileUtils.java new file mode 100644 index 0000000..d7f10a9 --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/utils/FileUtils.java @@ -0,0 +1,34 @@ +package cc.carm.app.aliddns.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; + +public class FileUtils { + + /** + * Rename the file. + */ + public static void copy(final File file, final String newName) throws IOException { + // file is null then return false + if (file == null) return; + // file doesn't exist then return false + if (!file.exists()) return; + // the new name equals old name then return true + if (newName.equals(file.getName())) return; + File newFile = new File(file.getParent(), newName); + // the new name of file exists then return false + if (newFile.exists()) newFile.delete(); + + try (InputStream input = Files.newInputStream(file.toPath()); + OutputStream output = Files.newOutputStream(newFile.toPath())) { + byte[] buf = new byte[1024]; + int bytesRead; + while ((bytesRead = input.read(buf)) > 0) { + output.write(buf, 0, bytesRead); + } + } + } +} diff --git a/src/main/java/cc/carm/app/aliddns/utils/TimeDateUtils.java b/src/main/java/cc/carm/app/aliddns/utils/TimeDateUtils.java new file mode 100644 index 0000000..74d958e --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/utils/TimeDateUtils.java @@ -0,0 +1,29 @@ +package cc.carm.app.aliddns.utils; + +public class TimeDateUtils { + + /** + * 将秒数转化为 DD:hh:mm:ss 格式 + * + * @param allSeconds 秒数 + * @return DD:hh:mm:ss格式文本 + */ + public static String toDHMSStyle(long allSeconds) { + long days = allSeconds / 86400L; + long hours = allSeconds % 86400L / 3600L; + long minutes = allSeconds % 3600L / 60L; + long seconds = allSeconds % 60L; + String DateTimes; + if (days > 0L) { + DateTimes = days + "天" + (hours > 0L ? hours + "小时" : "") + (minutes > 0L ? minutes + "分钟" : "") + (seconds > 0L ? seconds + "秒" : ""); + } else if (hours > 0L) { + DateTimes = hours + "小时" + (minutes > 0L ? minutes + "分钟" : "") + (seconds > 0L ? seconds + "秒" : ""); + } else if (minutes > 0L) { + DateTimes = minutes + "分钟" + (seconds > 0L ? seconds + "秒" : ""); + } else { + DateTimes = seconds + "秒"; + } + + return DateTimes; + } +} diff --git a/src/main/java/cc/carm/app/aliddns/utils/VersionReader.java b/src/main/java/cc/carm/app/aliddns/utils/VersionReader.java new file mode 100644 index 0000000..acfad0a --- /dev/null +++ b/src/main/java/cc/carm/app/aliddns/utils/VersionReader.java @@ -0,0 +1,41 @@ +package cc.carm.app.aliddns.utils; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; + +public class VersionReader { + + protected final @NotNull String versionsFileName; + protected final @NotNull Properties properties; + + public VersionReader(@NotNull String versionsFileName) { + this.versionsFileName = versionsFileName; + this.properties = Optional.ofNullable(getProperties(versionsFileName)).orElse(new Properties()); + } + + public synchronized @NotNull String get(@NotNull String artifactID) { + return get(artifactID, "UNKNOWN"); + } + + @Contract("_,!null->!null") + public synchronized @Nullable String get(@NotNull String artifactID, + @Nullable String defaultValue) { + return this.properties.getProperty(artifactID, defaultValue); + } + + protected Properties getProperties(@NotNull String versionsFileName) { + try (InputStream is = this.getClass().getResourceAsStream("/" + versionsFileName)) { + Properties p = new Properties(); + p.load(is); + return p; + } catch (Exception ignore) { + } + return null; + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml deleted file mode 100644 index 23aa173..0000000 --- a/src/main/resources/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: 1.7 - -#输出域名记录查询返回信息 -debug: false - -Service: - #更新间隔(毫秒) - period: 900000 - # 阿里云地域ID,可以不改动 - # 请参考 https://help.aliyun.com/knowledge_detail/40654.html - region-id: "cn-hangzhou" - # IP地址查询相关设定 - # 用于获取对应的IP地址,以更新到域名 - # 如不需要IPV6,则可以直接将地址留空。 - ipQuery: - IPv4: "http://ifconfig.me/ip" - IPv6: "https://v6.ip.zxinc.org/getip" - - -#更新任务列表 -UpdateRequests: - test: - domain: "test.cn" # 域名,如 www.baidu.com 中的 baidu.com - AccessKey: "xx" # 访问密钥 (在个人控制台中获取) - AccessSecret: "xx" # 访问密码 (在个人控制台中获取) - record: "www" #主机记录 - ipv6: false # 该记录是否为IPv6[AAAA]记录 (默认为false) diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties new file mode 100644 index 0000000..e5683df --- /dev/null +++ b/src/main/resources/version.properties @@ -0,0 +1 @@ +version=${project.version} \ No newline at end of file diff --git a/src/test/java/ConfigTest.java b/src/test/java/ConfigTest.java new file mode 100644 index 0000000..af4603f --- /dev/null +++ b/src/test/java/ConfigTest.java @@ -0,0 +1,20 @@ +import cc.carm.app.aliddns.conf.AppConfig; +import cc.carm.lib.configuration.EasyConfiguration; +import cc.carm.lib.configuration.core.source.ConfigurationProvider; +import org.junit.Test; + +public class ConfigTest { + + @Test + public void onTest() { + + ConfigurationProvider configuration = EasyConfiguration.from("target/example.yml"); + configuration.initialize(AppConfig.class); + try { + configuration.save(); + } catch (Exception e) { + e.printStackTrace(); + } + + } +}