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 @@ - + - +