From 3b5ee464a7655d506c5447d65030df22de444c0b Mon Sep 17 00:00:00 2001
From: Darc Z <53445798+DarcJC@users.noreply.github.com>
Date: Sat, 24 Feb 2024 21:10:27 +0800
Subject: [PATCH] Add DDNS support (#324)
* feat: add ddns updater framework
Note: no functionality implemented yet
* feat: add webhook ddns provider
* feat: update dashboard template
* fix: check nil and cron task string
* fix: webhook string formated with unexcepted param
* fix: webhook header split error
* feat: cloudflare ddns provider
* refract: move ddns update trigger into ReportSystemInfo
* lang: update other languages text
* fix: clear codes and logics
* fix: move update ddns to goroutine to avoid blocking
* fix: clear unused codes
* fix: update timestamp to prevent cache
---
cmd/dashboard/controller/member_api.go | 4 +
model/config.go | 22 ++
model/server.go | 5 +-
resource/l10n/en-US.toml | 8 +-
resource/l10n/es-ES.toml | 8 +-
resource/l10n/zh-CN.toml | 6 +
resource/l10n/zh-TW.toml | 8 +-
resource/static/main.js | 6 +
resource/template/common/footer.html | 2 +-
resource/template/component/server.html | 10 +
.../template/dashboard-default/server.html | 4 +
.../template/theme-angel-kanade/footer.html | 2 +-
script/config.yaml | 10 +
service/rpc/nezha.go | 32 ++
service/singleton/ddns.go | 302 ++++++++++++++++++
service/singleton/singleton.go | 16 +
16 files changed, 439 insertions(+), 6 deletions(-)
create mode 100644 service/singleton/ddns.go
diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go
index 4514d84..f1b5969 100644
--- a/cmd/dashboard/controller/member_api.go
+++ b/cmd/dashboard/controller/member_api.go
@@ -300,6 +300,8 @@ type serverForm struct {
Tag string
Note string
HideForGuest string
+ EnableDDNS string
+ DDNSDomain string
}
func (ma *memberAPI) addOrEditServer(c *gin.Context) {
@@ -315,6 +317,8 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
s.Tag = sf.Tag
s.Note = sf.Note
s.HideForGuest = sf.HideForGuest == "on"
+ s.EnableDDNS = sf.EnableDDNS == "on"
+ s.DDNSDomain = sf.DDNSDomain
if s.ID == 0 {
s.Secret, err = utils.GenerateRandomString(18)
if err == nil {
diff --git a/model/config.go b/model/config.go
index c18bb3f..341597b 100644
--- a/model/config.go
+++ b/model/config.go
@@ -112,6 +112,19 @@ type Config struct {
IgnoredIPNotificationServerIDs map[uint64]bool // [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内)
MaxTCPPingValue int32
AvgPingCount int
+
+ // 动态域名解析更新
+ DDNS struct {
+ Enable bool
+ Provider string
+ AccessID string
+ AccessSecret string
+ WebhookURL string
+ WebhookMethod string
+ WebhookRequestBody string
+ WebhookHeaders string
+ MaxRetries uint32
+ }
}
// Read 读取配置文件并应用
@@ -152,6 +165,15 @@ func (c *Config) Read(path string) error {
if c.AvgPingCount == 0 {
c.AvgPingCount = 2
}
+ if c.DDNS.Provider == "" {
+ c.DDNS.Provider = "webhook"
+ }
+ if c.DDNS.WebhookMethod == "" {
+ c.DDNS.WebhookMethod = "POST"
+ }
+ if c.DDNS.MaxRetries == 0 {
+ c.DDNS.MaxRetries = 3
+ }
c.updateIgnoredIPNotificationID()
return nil
diff --git a/model/server.go b/model/server.go
index 95e798d..3077265 100644
--- a/model/server.go
+++ b/model/server.go
@@ -17,6 +17,8 @@ type Server struct {
Note string `json:"-"` // 管理员可见备注
DisplayIndex int // 展示排序,越大越靠前
HideForGuest bool // 对游客隐藏
+ EnableDDNS bool // 是否启用DDNS 未在配置文件中启用DDNS 或 DDNS检查时间为0时此项无效
+ DDNSDomain string // DDNS中的前缀 如基础域名为abc.oracle DDNSName为mjj 就会把mjj.abc.oracle解析服务器IP 为空则停用
Host *Host `gorm:"-"`
State *HostState `gorm:"-"`
@@ -51,5 +53,6 @@ func (s Server) Marshal() template.JS {
tag, _ := utils.Json.Marshal(s.Tag)
note, _ := utils.Json.Marshal(s.Note)
secret, _ := utils.Json.Marshal(s.Secret)
- return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s,"HideForGuest": %s}`, s.ID, name, secret, s.DisplayIndex, tag, note, boolToString(s.HideForGuest))) // #nosec
+ ddnsDomain, _ := utils.Json.Marshal(s.DDNSDomain)
+ return template.JS(fmt.Sprintf(`{"ID":%d,"Name":%s,"Secret":%s,"DisplayIndex":%d,"Tag":%s,"Note":%s,"HideForGuest": %s,"EnableDDNS": %s,"DDNSDomain": %s}`, s.ID, name, secret, s.DisplayIndex, tag, note, boolToString(s.HideForGuest), boolToString(s.EnableDDNS), ddnsDomain)) // #nosec
}
diff --git a/resource/l10n/en-US.toml b/resource/l10n/en-US.toml
index 79e3f37..749d1c2 100644
--- a/resource/l10n/en-US.toml
+++ b/resource/l10n/en-US.toml
@@ -614,4 +614,10 @@ other = "Menu"
other = "Network"
[EnableShowInService]
-other = "Enable Show in Service"
\ No newline at end of file
+other = "Enable Show in Service"
+
+[EnableDDNS]
+other = "Enable DDNS"
+
+[DDNSDomain]
+other = "DDNS Domain"
diff --git a/resource/l10n/es-ES.toml b/resource/l10n/es-ES.toml
index adee1d5..993ae36 100644
--- a/resource/l10n/es-ES.toml
+++ b/resource/l10n/es-ES.toml
@@ -614,4 +614,10 @@ other = "Menú"
other = "Red"
[EnableShowInService]
-other = "Mostrar en servicio"
\ No newline at end of file
+other = "Mostrar en servicio"
+
+[EnableDDNS]
+other = "Habilitar DDNS"
+
+[DDNSDomain]
+other = "Dominio DDNS"
diff --git a/resource/l10n/zh-CN.toml b/resource/l10n/zh-CN.toml
index 598f306..240a946 100644
--- a/resource/l10n/zh-CN.toml
+++ b/resource/l10n/zh-CN.toml
@@ -615,3 +615,9 @@ other = "网络"
[EnableShowInService]
other = "在服务中显示"
+
+[EnableDDNS]
+other = "启用DDNS"
+
+[DDNSDomain]
+other = "DDNS域名"
diff --git a/resource/l10n/zh-TW.toml b/resource/l10n/zh-TW.toml
index 6d49408..246e461 100644
--- a/resource/l10n/zh-TW.toml
+++ b/resource/l10n/zh-TW.toml
@@ -614,4 +614,10 @@ other = "菜單"
other = "網絡"
[EnableShowInService]
-other = "在服務中顯示"
\ No newline at end of file
+other = "在服務中顯示"
+
+[EnableDDNS]
+other = "啟用DDNS"
+
+[DDNSDomain]
+other = "DDNS網域"
diff --git a/resource/static/main.js b/resource/static/main.js
index a38b5a0..f3b8c74 100644
--- a/resource/static/main.js
+++ b/resource/static/main.js
@@ -302,6 +302,7 @@ function addOrEditServer(server, conf) {
modal.find("input[name=id]").val(server ? server.ID : null);
modal.find("input[name=name]").val(server ? server.Name : null);
modal.find("input[name=Tag]").val(server ? server.Tag : null);
+ modal.find("input[name=DDNSDomain]").val(server ? server.DDNSDomain : null);
modal
.find("input[name=DisplayIndex]")
.val(server ? server.DisplayIndex : null);
@@ -321,6 +322,11 @@ function addOrEditServer(server, conf) {
} else {
modal.find(".ui.hideforguest.checkbox").checkbox("set unchecked");
}
+ if (server && server.EnableDDNS) {
+ modal.find(".ui.enableddns.checkbox").checkbox("set checked");
+ } else {
+ modal.find(".ui.enableddns.checkbox").checkbox("set unchecked");
+ }
showFormModal(".server.modal", "#serverForm", "/api/server");
}
diff --git a/resource/template/common/footer.html b/resource/template/common/footer.html
index 051bda8..f243702 100644
--- a/resource/template/common/footer.html
+++ b/resource/template/common/footer.html
@@ -10,7 +10,7 @@
-
+
-
+