From 853897a6f8cb35cab868485c000f81029e7e9ae8 Mon Sep 17 00:00:00 2001 From: robin Date: Mon, 2 Mar 2026 23:42:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8A=82=E7=82=B9=E8=87=AA=E5=8A=A8=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=8A=9F=E8=83=BD=E4=B9=8B=E5=89=8D=E7=9A=84=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/db/models/httpdns_cluster_dao.go | 8 +- .../db/models/httpdns_cluster_model.go | 4 + EdgeAPI/internal/installers/deploy_manager.go | 62 +++- .../rpc/services/httpdns/converters.go | 2 + .../httpdns/service_httpdns_cluster.go | 4 +- .../services/httpdns/service_httpdns_node.go | 58 +++ .../services/users/service_user_ext_plus.go | 4 - .../httpdns/apps/customRecordsCreatePopup.go | 2 +- .../httpdns/clusters/clusterSettings.go | 6 + .../default/httpdns/clusters/rpc_helpers.go | 2 + .../web/actions/default/users/createPopup.go | 4 - .../web/actions/default/users/update.go | 18 +- .../httpdns/apps/customRecordsCreatePopup.js | 2 +- .../clusters/cluster/node/install.html | 8 +- .../httpdns/clusters/clusterSettings.html | 34 +- .../pkg/rpc/pb/model_httpdns_cluster.pb.go | 16 + .../pkg/rpc/pb/service_httpdns_cluster.pb.go | 32 ++ .../pkg/rpc/pb/service_httpdns_node.pb.go | 337 ++++++++++++++++-- .../rpc/pb/service_httpdns_node_grpc.pb.go | 94 ++++- .../protos/models/model_httpdns_cluster.proto | 2 + .../rpc/protos/service_httpdns_cluster.proto | 4 + .../pkg/rpc/protos/service_httpdns_node.proto | 33 ++ EdgeCommon/pkg/userconfigs/user_features.go | 7 +- ...档.md => HTTPDNS SDK 集成文档(Android).md} | 2 +- EdgeHttpDNS/internal/apps/app_cmd.go | 6 +- EdgeHttpDNS/internal/nodes/httpdns_node.go | 13 +- EdgeHttpDNS/internal/nodes/upgrade_manager.go | 280 +++++++++++++++ EdgeHttpDNS/internal/utils/unzip.go | 98 +++++ .../internal/web/helpers/user_must_auth.go | 2 +- 29 files changed, 1063 insertions(+), 81 deletions(-) rename EdgeHttpDNS/{Android SDK集成文档.md => HTTPDNS SDK 集成文档(Android).md} (98%) create mode 100644 EdgeHttpDNS/internal/nodes/upgrade_manager.go create mode 100644 EdgeHttpDNS/internal/utils/unzip.go diff --git a/EdgeAPI/internal/db/models/httpdns_cluster_dao.go b/EdgeAPI/internal/db/models/httpdns_cluster_dao.go index 087d36b..a184b36 100644 --- a/EdgeAPI/internal/db/models/httpdns_cluster_dao.go +++ b/EdgeAPI/internal/db/models/httpdns_cluster_dao.go @@ -34,7 +34,7 @@ func init() { }) } -func (this *HTTPDNSClusterDAO) CreateCluster(tx *dbs.Tx, name string, serviceDomain string, defaultTTL int32, fallbackTimeoutMs int32, installDir string, tlsPolicyJSON []byte, isOn bool, isDefault bool) (int64, error) { +func (this *HTTPDNSClusterDAO) CreateCluster(tx *dbs.Tx, name string, serviceDomain string, defaultTTL int32, fallbackTimeoutMs int32, installDir string, tlsPolicyJSON []byte, isOn bool, isDefault bool, autoRemoteStart bool, accessLogIsOn bool) (int64, error) { if isDefault { err := this.Query(tx). State(HTTPDNSClusterStateEnabled). @@ -53,6 +53,8 @@ func (this *HTTPDNSClusterDAO) CreateCluster(tx *dbs.Tx, name string, serviceDom op.InstallDir = installDir op.IsOn = isOn op.IsDefault = isDefault + op.AutoRemoteStart = autoRemoteStart + op.AccessLogIsOn = accessLogIsOn op.CreatedAt = time.Now().Unix() op.UpdatedAt = time.Now().Unix() op.State = HTTPDNSClusterStateEnabled @@ -66,7 +68,7 @@ func (this *HTTPDNSClusterDAO) CreateCluster(tx *dbs.Tx, name string, serviceDom return types.Int64(op.Id), nil } -func (this *HTTPDNSClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, serviceDomain string, defaultTTL int32, fallbackTimeoutMs int32, installDir string, tlsPolicyJSON []byte, isOn bool, isDefault bool) error { +func (this *HTTPDNSClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name string, serviceDomain string, defaultTTL int32, fallbackTimeoutMs int32, installDir string, tlsPolicyJSON []byte, isOn bool, isDefault bool, autoRemoteStart bool, accessLogIsOn bool) error { if isDefault { err := this.Query(tx). State(HTTPDNSClusterStateEnabled). @@ -87,6 +89,8 @@ func (this *HTTPDNSClusterDAO) UpdateCluster(tx *dbs.Tx, clusterId int64, name s op.InstallDir = installDir op.IsOn = isOn op.IsDefault = isDefault + op.AutoRemoteStart = autoRemoteStart + op.AccessLogIsOn = accessLogIsOn op.UpdatedAt = time.Now().Unix() if len(tlsPolicyJSON) > 0 { op.TLSPolicy = tlsPolicyJSON diff --git a/EdgeAPI/internal/db/models/httpdns_cluster_model.go b/EdgeAPI/internal/db/models/httpdns_cluster_model.go index 00aeaf1..1fc8517 100644 --- a/EdgeAPI/internal/db/models/httpdns_cluster_model.go +++ b/EdgeAPI/internal/db/models/httpdns_cluster_model.go @@ -13,6 +13,8 @@ type HTTPDNSCluster struct { FallbackTimeoutMs int32 `field:"fallbackTimeoutMs"` // 降级超时 InstallDir string `field:"installDir"` // 安装目录 TLSPolicy dbs.JSON `field:"tlsPolicy"` // TLS策略 + AutoRemoteStart bool `field:"autoRemoteStart"` // 自动远程启动 + AccessLogIsOn bool `field:"accessLogIsOn"` // 访问日志是否开启 CreatedAt uint64 `field:"createdAt"` // 创建时间 UpdatedAt uint64 `field:"updatedAt"` // 修改时间 State uint8 `field:"state"` // 记录状态 @@ -28,6 +30,8 @@ type HTTPDNSClusterOperator struct { FallbackTimeoutMs any // 降级超时 InstallDir any // 安装目录 TLSPolicy any // TLS策略 + AutoRemoteStart any // 自动远程启动 + AccessLogIsOn any // 访问日志是否开启 CreatedAt any // 创建时间 UpdatedAt any // 修改时间 State any // 记录状态 diff --git a/EdgeAPI/internal/installers/deploy_manager.go b/EdgeAPI/internal/installers/deploy_manager.go index 90a5cce..3ea01f2 100644 --- a/EdgeAPI/internal/installers/deploy_manager.go +++ b/EdgeAPI/internal/installers/deploy_manager.go @@ -15,8 +15,9 @@ var SharedDeployManager = NewDeployManager() type DeployManager struct { dir string - nodeFiles []*DeployFile - nsNodeFiles []*DeployFile + nodeFiles []*DeployFile + nsNodeFiles []*DeployFile + httpdnsNodeFiles []*DeployFile locker sync.Mutex } @@ -28,6 +29,7 @@ func NewDeployManager() *DeployManager { } manager.LoadNodeFiles() manager.LoadNSNodeFiles() + manager.LoadHTTPDNSNodeFiles() return manager } @@ -141,6 +143,61 @@ func (this *DeployManager) FindNSNodeFile(os string, arch string) *DeployFile { return nil } +// LoadHTTPDNSNodeFiles 加载所有HTTPDNS节点安装文件 +func (this *DeployManager) LoadHTTPDNSNodeFiles() []*DeployFile { + this.locker.Lock() + defer this.locker.Unlock() + + if len(this.httpdnsNodeFiles) > 0 { + return this.httpdnsNodeFiles + } + + var keyMap = map[string]*DeployFile{} // key => File + + var reg = regexp.MustCompile(`^edge-httpdns-(\w+)-(\w+)-v([0-9.]+)\.zip$`) + for _, file := range files.NewFile(this.dir).List() { + var name = file.Name() + if !reg.MatchString(name) { + continue + } + var matches = reg.FindStringSubmatch(name) + var osName = matches[1] + var arch = matches[2] + var version = matches[3] + + var key = osName + "_" + arch + oldFile, ok := keyMap[key] + if ok && stringutil.VersionCompare(oldFile.Version, version) > 0 { + continue + } + keyMap[key] = &DeployFile{ + OS: osName, + Arch: arch, + Version: version, + Path: file.Path(), + } + } + + var result = []*DeployFile{} + for _, v := range keyMap { + result = append(result, v) + } + + this.httpdnsNodeFiles = result + + return result +} + +// FindHTTPDNSNodeFile 查找特定平台的HTTPDNS节点安装文件 +func (this *DeployManager) FindHTTPDNSNodeFile(os string, arch string) *DeployFile { + for _, file := range this.LoadHTTPDNSNodeFiles() { + if file.OS == os && file.Arch == arch { + return file + } + } + return nil +} + // Reload 重置缓存 func (this *DeployManager) Reload() { this.locker.Lock() @@ -148,4 +205,5 @@ func (this *DeployManager) Reload() { this.nodeFiles = nil this.nsNodeFiles = nil + this.httpdnsNodeFiles = nil } diff --git a/EdgeAPI/internal/rpc/services/httpdns/converters.go b/EdgeAPI/internal/rpc/services/httpdns/converters.go index 98d2b4d..d1e82fc 100644 --- a/EdgeAPI/internal/rpc/services/httpdns/converters.go +++ b/EdgeAPI/internal/rpc/services/httpdns/converters.go @@ -23,6 +23,8 @@ func toPBCluster(cluster *models.HTTPDNSCluster) *pb.HTTPDNSCluster { TlsPolicyJSON: cluster.TLSPolicy, CreatedAt: int64(cluster.CreatedAt), UpdatedAt: int64(cluster.UpdatedAt), + AutoRemoteStart: cluster.AutoRemoteStart, + AccessLogIsOn: cluster.AccessLogIsOn, } } diff --git a/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_cluster.go b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_cluster.go index fda859d..dcab940 100644 --- a/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_cluster.go +++ b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_cluster.go @@ -25,7 +25,7 @@ func (this *HTTPDNSClusterService) CreateHTTPDNSCluster(ctx context.Context, req } var clusterId int64 err = this.RunTx(func(tx *dbs.Tx) error { - clusterId, err = models.SharedHTTPDNSClusterDAO.CreateCluster(tx, req.Name, req.ServiceDomain, req.DefaultTTL, req.FallbackTimeoutMs, req.InstallDir, req.TlsPolicyJSON, req.IsOn, req.IsDefault) + clusterId, err = models.SharedHTTPDNSClusterDAO.CreateCluster(tx, req.Name, req.ServiceDomain, req.DefaultTTL, req.FallbackTimeoutMs, req.InstallDir, req.TlsPolicyJSON, req.IsOn, req.IsDefault, req.AutoRemoteStart, req.AccessLogIsOn) if err != nil { return err } @@ -43,7 +43,7 @@ func (this *HTTPDNSClusterService) UpdateHTTPDNSCluster(ctx context.Context, req return nil, err } err = this.RunTx(func(tx *dbs.Tx) error { - err = models.SharedHTTPDNSClusterDAO.UpdateCluster(tx, req.ClusterId, req.Name, req.ServiceDomain, req.DefaultTTL, req.FallbackTimeoutMs, req.InstallDir, req.TlsPolicyJSON, req.IsOn, req.IsDefault) + err = models.SharedHTTPDNSClusterDAO.UpdateCluster(tx, req.ClusterId, req.Name, req.ServiceDomain, req.DefaultTTL, req.FallbackTimeoutMs, req.InstallDir, req.TlsPolicyJSON, req.IsOn, req.IsDefault, req.AutoRemoteStart, req.AccessLogIsOn) if err != nil { return err } diff --git a/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_node.go b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_node.go index 5c7eb06..d1ea6a0 100644 --- a/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_node.go +++ b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_node.go @@ -4,14 +4,19 @@ import ( "context" "encoding/json" "errors" + "io" + "path/filepath" + "github.com/TeaOSLab/EdgeAPI/internal/db/models" "github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/installers" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services" + rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/logs" + stringutil "github.com/iwind/TeaGo/utils/string" ) // HTTPDNSNodeService HTTPDNS节点服务 @@ -216,6 +221,59 @@ func (this *HTTPDNSNodeService) UpdateHTTPDNSNodeLogin(ctx context.Context, req return this.Success() } +// CheckHTTPDNSNodeLatestVersion 检查HTTPDNS节点新版本 +func (this *HTTPDNSNodeService) CheckHTTPDNSNodeLatestVersion(ctx context.Context, req *pb.CheckHTTPDNSNodeLatestVersionRequest) (*pb.CheckHTTPDNSNodeLatestVersionResponse, error) { + _, _, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeHTTPDNS) + if err != nil { + return nil, err + } + + deployFiles := installers.SharedDeployManager.LoadHTTPDNSNodeFiles() + for _, file := range deployFiles { + if file.OS == req.Os && file.Arch == req.Arch && stringutil.VersionCompare(file.Version, req.CurrentVersion) > 0 { + return &pb.CheckHTTPDNSNodeLatestVersionResponse{ + HasNewVersion: true, + NewVersion: file.Version, + }, nil + } + } + return &pb.CheckHTTPDNSNodeLatestVersionResponse{HasNewVersion: false}, nil +} + +// DownloadHTTPDNSNodeInstallationFile 下载最新HTTPDNS节点安装文件 +func (this *HTTPDNSNodeService) DownloadHTTPDNSNodeInstallationFile(ctx context.Context, req *pb.DownloadHTTPDNSNodeInstallationFileRequest) (*pb.DownloadHTTPDNSNodeInstallationFileResponse, error) { + nodeId, err := this.ValidateHTTPDNSNode(ctx) + if err != nil { + return nil, err + } + + var file = installers.SharedDeployManager.FindHTTPDNSNodeFile(req.Os, req.Arch) + if file == nil { + return &pb.DownloadHTTPDNSNodeInstallationFileResponse{}, nil + } + + sum, err := file.Sum() + if err != nil { + return nil, err + } + + data, offset, err := file.Read(req.ChunkOffset) + if err != nil && err != io.EOF { + return nil, err + } + + // 增加下载速度监控 + installers.SharedUpgradeLimiter.UpdateNodeBytes(nodeconfigs.NodeRoleHTTPDNS, nodeId, int64(len(data))) + + return &pb.DownloadHTTPDNSNodeInstallationFileResponse{ + Sum: sum, + Offset: offset, + ChunkData: data, + Version: file.Version, + Filename: filepath.Base(file.Path), + }, nil +} + func shouldTriggerHTTPDNSInstall(installStatusJSON []byte) bool { if len(installStatusJSON) == 0 { return false diff --git a/EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go b/EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go index 41f91de..2038d6f 100644 --- a/EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go +++ b/EdgeAPI/internal/rpc/services/users/service_user_ext_plus.go @@ -11,7 +11,6 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/iwind/TeaGo/dbs" - "github.com/iwind/TeaGo/lists" ) // FindUserPriceInfo 读取用户计费信息 @@ -145,9 +144,6 @@ func (this *UserService) RegisterUser(ctx context.Context, req *pb.RegisterUserR } features := registerConfig.Features - if registerConfig.HTTPDNSIsOn && !lists.ContainsString(features, userconfigs.UserFeatureCodeHTTPDNS) { - features = append(features, userconfigs.UserFeatureCodeHTTPDNS) - } // 创建用户 userId, err := models.SharedUserDAO.CreateUser(tx, req.Username, req.Password, req.Fullname, req.Mobile, "", req.Email, "", req.Source, registerConfig.ClusterId, features, req.Ip, !registerConfig.RequireVerification) diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/apps/customRecordsCreatePopup.go b/EdgeAdmin/internal/web/actions/default/httpdns/apps/customRecordsCreatePopup.go index 93c1638..567751b 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/apps/customRecordsCreatePopup.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/apps/customRecordsCreatePopup.go @@ -48,7 +48,7 @@ func (this *CustomRecordsCreatePopupAction) RunGet(params struct { "lineCountry": "默认", "ruleName": "", "weightEnabled": false, - "ttl": 30, + "ttl": 60, "isOn": true, "recordItemsJson": `[{"type":"A","value":"","weight":100}]`, } diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go index 71768d1..f8737ed 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go @@ -47,6 +47,8 @@ func (this *ClusterSettingsAction) RunGet(params struct { "fallbackTimeout": cluster.GetInt("fallbackTimeout"), "installDir": cluster.GetString("installDir"), "isOn": cluster.GetBool("isOn"), + "autoRemoteStart": cluster.GetBool("autoRemoteStart"), + "accessLogIsOn": cluster.GetBool("accessLogIsOn"), } if settings.GetInt("cacheTtl") <= 0 { settings["cacheTtl"] = 60 @@ -110,6 +112,8 @@ func (this *ClusterSettingsAction) RunPost(params struct { FallbackTimeout int32 InstallDir string IsOn bool + AutoRemoteStart bool + AccessLogIsOn bool Addresses []byte SslPolicyJSON []byte @@ -183,6 +187,8 @@ func (this *ClusterSettingsAction) RunPost(params struct { TlsPolicyJSON: tlsPolicyJSON, IsOn: params.IsOn, IsDefault: false, + AutoRemoteStart: params.AutoRemoteStart, + AccessLogIsOn: params.AccessLogIsOn, }) if err != nil { this.ErrorPage(err) diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/rpc_helpers.go b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/rpc_helpers.go index 36cdbd3..3090532 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/rpc_helpers.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/rpc_helpers.go @@ -92,6 +92,8 @@ func findClusterMap(parent *actionutils.ParentAction, clusterID int64) (maps.Map "isOn": cluster.GetIsOn(), "isDefault": cluster.GetIsDefault(), "tlsPolicyJSON": cluster.GetTlsPolicyJSON(), + "autoRemoteStart": cluster.GetAutoRemoteStart(), + "accessLogIsOn": cluster.GetAccessLogIsOn(), }, nil } } diff --git a/EdgeAdmin/internal/web/actions/default/users/createPopup.go b/EdgeAdmin/internal/web/actions/default/users/createPopup.go index 8fc14c6..40da64f 100644 --- a/EdgeAdmin/internal/web/actions/default/users/createPopup.go +++ b/EdgeAdmin/internal/web/actions/default/users/createPopup.go @@ -10,7 +10,6 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/iwind/TeaGo/actions" - "github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/maps" "github.com/xlzd/gotp" ) @@ -184,9 +183,6 @@ func (this *CreatePopupAction) RunPost(params struct { return } var featureCodes = config.Features - if config.HTTPDNSIsOn && !lists.ContainsString(featureCodes, userconfigs.UserFeatureCodeHTTPDNS) { - featureCodes = append(featureCodes, userconfigs.UserFeatureCodeHTTPDNS) - } _, err = this.RPC().UserRPC().UpdateUserFeatures(this.AdminContext(), &pb.UpdateUserFeaturesRequest{ UserId: userId, diff --git a/EdgeAdmin/internal/web/actions/default/users/update.go b/EdgeAdmin/internal/web/actions/default/users/update.go index d67631b..2347ef7 100644 --- a/EdgeAdmin/internal/web/actions/default/users/update.go +++ b/EdgeAdmin/internal/web/actions/default/users/update.go @@ -7,6 +7,8 @@ import ( "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils" "github.com/TeaOSLab/EdgeCommon/pkg/langs/codes" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" "github.com/xlzd/gotp" @@ -87,17 +89,13 @@ func (this *UpdateAction) RunGet(params struct { this.Data["clusterId"] = user.NodeCluster.Id } - // 检查用户是否开通了 HTTPDNS 功能 + // 检查全局是否启用了 HTTPDNS 功能 var hasHTTPDNSFeature = false - userFeaturesResp, err := this.RPC().UserRPC().FindUserFeatures(this.AdminContext(), &pb.FindUserFeaturesRequest{UserId: params.UserId}) - if err != nil { - this.ErrorPage(err) - return - } - for _, f := range userFeaturesResp.Features { - if f.Code == "httpdns" { - hasHTTPDNSFeature = true - break + sysResp, sysErr := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeUserRegisterConfig}) + if sysErr == nil && len(sysResp.ValueJSON) > 0 { + var regConfig = userconfigs.DefaultUserRegisterConfig() + if json.Unmarshal(sysResp.ValueJSON, regConfig) == nil { + hasHTTPDNSFeature = regConfig.HTTPDNSIsOn } } this.Data["hasHTTPDNSFeature"] = hasHTTPDNSFeature diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.js b/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.js index e8bc6a0..e148e5d 100644 --- a/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.js +++ b/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.js @@ -74,7 +74,7 @@ vm.record.lineContinent = vm.record.lineContinent || "默认"; vm.record.lineCountry = vm.record.lineCountry || "默认"; vm.record.ruleName = vm.record.ruleName || ""; - vm.record.ttl = vm.record.ttl || 30; + vm.record.ttl = vm.record.ttl || 60; vm.record.weightEnabled = vm.normalizeBoolean(vm.record.weightEnabled, false); vm.record.isOn = vm.normalizeBoolean(vm.record.isOn, true); diff --git a/EdgeAdmin/web/views/@default/httpdns/clusters/cluster/node/install.html b/EdgeAdmin/web/views/@default/httpdns/clusters/cluster/node/install.html index 6129a00..421f9a0 100644 --- a/EdgeAdmin/web/views/@default/httpdns/clusters/cluster/node/install.html +++ b/EdgeAdmin/web/views/@default/httpdns/clusters/cluster/node/install.html @@ -20,8 +20,8 @@ 配置内容 rpc.endpoints: [ {{apiEndpoints}} ] - nodeId: "{{node.uniqueId}}" - secret: "{{node.secret}}" +nodeId: "{{node.uniqueId}}" +secret: "{{node.secret}}"

每个节点的配置文件内容均不相同,不能混用。

@@ -81,8 +81,8 @@ 配置内容 rpc.endpoints: [ {{apiEndpoints}} ] - nodeId: "{{node.uniqueId}}" - secret: "{{node.secret}}" +nodeId: "{{node.uniqueId}}" +secret: "{{node.secret}}"

每个节点的配置文件内容均不相同,不能混用。

diff --git a/EdgeAdmin/web/views/@default/httpdns/clusters/clusterSettings.html b/EdgeAdmin/web/views/@default/httpdns/clusters/clusterSettings.html index 8389623..809eb1d 100644 --- a/EdgeAdmin/web/views/@default/httpdns/clusters/clusterSettings.html +++ b/EdgeAdmin/web/views/@default/httpdns/clusters/clusterSettings.html @@ -45,7 +45,8 @@ 默认解析 TTL
- +

SDK 通过 HTTPDNS 解析域名时返回的默认 TTL。

@@ -55,12 +56,33 @@ 降级超时容忍度
- + 毫秒

节点回源查询上游 DNS 时的最大等待时间。

+ + 自动远程启动 + +
+ + +
+

当检测到节点离线时,自动尝试远程启动(前提是节点已经设置了SSH登录认证)。

+ + + + 访问日志 + +
+ + +
+

启用后,HTTPDNS 节点将会记录客户端的请求访问日志。

+ + 启用当前集群 @@ -77,13 +99,15 @@ 绑定端口 * - + - + - + \ No newline at end of file diff --git a/EdgeCommon/pkg/rpc/pb/model_httpdns_cluster.pb.go b/EdgeCommon/pkg/rpc/pb/model_httpdns_cluster.pb.go index 754260d..55e3ef1 100644 --- a/EdgeCommon/pkg/rpc/pb/model_httpdns_cluster.pb.go +++ b/EdgeCommon/pkg/rpc/pb/model_httpdns_cluster.pb.go @@ -36,6 +36,8 @@ type HTTPDNSCluster struct { TlsPolicyJSON []byte `protobuf:"bytes,9,opt,name=tlsPolicyJSON,proto3" json:"tlsPolicyJSON,omitempty"` CreatedAt int64 `protobuf:"varint,10,opt,name=createdAt,proto3" json:"createdAt,omitempty"` UpdatedAt int64 `protobuf:"varint,11,opt,name=updatedAt,proto3" json:"updatedAt,omitempty"` + AutoRemoteStart bool `protobuf:"varint,12,opt,name=autoRemoteStart,proto3" json:"autoRemoteStart,omitempty"` + AccessLogIsOn bool `protobuf:"varint,13,opt,name=accessLogIsOn,proto3" json:"accessLogIsOn,omitempty"` } func (x *HTTPDNSCluster) Reset() { @@ -145,6 +147,20 @@ func (x *HTTPDNSCluster) GetUpdatedAt() int64 { return 0 } +func (x *HTTPDNSCluster) GetAutoRemoteStart() bool { + if x != nil { + return x.AutoRemoteStart + } + return false +} + +func (x *HTTPDNSCluster) GetAccessLogIsOn() bool { + if x != nil { + return x.AccessLogIsOn + } + return false +} + var File_models_model_httpdns_cluster_proto protoreflect.FileDescriptor var file_models_model_httpdns_cluster_proto_rawDesc = []byte{ diff --git a/EdgeCommon/pkg/rpc/pb/service_httpdns_cluster.pb.go b/EdgeCommon/pkg/rpc/pb/service_httpdns_cluster.pb.go index 885607e..970c13c 100644 --- a/EdgeCommon/pkg/rpc/pb/service_httpdns_cluster.pb.go +++ b/EdgeCommon/pkg/rpc/pb/service_httpdns_cluster.pb.go @@ -33,6 +33,8 @@ type CreateHTTPDNSClusterRequest struct { TlsPolicyJSON []byte `protobuf:"bytes,6,opt,name=tlsPolicyJSON,proto3" json:"tlsPolicyJSON,omitempty"` IsOn bool `protobuf:"varint,7,opt,name=isOn,proto3" json:"isOn,omitempty"` IsDefault bool `protobuf:"varint,8,opt,name=isDefault,proto3" json:"isDefault,omitempty"` + AutoRemoteStart bool `protobuf:"varint,9,opt,name=autoRemoteStart,proto3" json:"autoRemoteStart,omitempty"` + AccessLogIsOn bool `protobuf:"varint,10,opt,name=accessLogIsOn,proto3" json:"accessLogIsOn,omitempty"` } func (x *CreateHTTPDNSClusterRequest) Reset() { @@ -121,6 +123,20 @@ func (x *CreateHTTPDNSClusterRequest) GetIsDefault() bool { return false } +func (x *CreateHTTPDNSClusterRequest) GetAutoRemoteStart() bool { + if x != nil { + return x.AutoRemoteStart + } + return false +} + +func (x *CreateHTTPDNSClusterRequest) GetAccessLogIsOn() bool { + if x != nil { + return x.AccessLogIsOn + } + return false +} + type CreateHTTPDNSClusterResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -180,6 +196,8 @@ type UpdateHTTPDNSClusterRequest struct { TlsPolicyJSON []byte `protobuf:"bytes,7,opt,name=tlsPolicyJSON,proto3" json:"tlsPolicyJSON,omitempty"` IsOn bool `protobuf:"varint,8,opt,name=isOn,proto3" json:"isOn,omitempty"` IsDefault bool `protobuf:"varint,9,opt,name=isDefault,proto3" json:"isDefault,omitempty"` + AutoRemoteStart bool `protobuf:"varint,10,opt,name=autoRemoteStart,proto3" json:"autoRemoteStart,omitempty"` + AccessLogIsOn bool `protobuf:"varint,11,opt,name=accessLogIsOn,proto3" json:"accessLogIsOn,omitempty"` } func (x *UpdateHTTPDNSClusterRequest) Reset() { @@ -275,6 +293,20 @@ func (x *UpdateHTTPDNSClusterRequest) GetIsDefault() bool { return false } +func (x *UpdateHTTPDNSClusterRequest) GetAutoRemoteStart() bool { + if x != nil { + return x.AutoRemoteStart + } + return false +} + +func (x *UpdateHTTPDNSClusterRequest) GetAccessLogIsOn() bool { + if x != nil { + return x.AccessLogIsOn + } + return false +} + type DeleteHTTPDNSClusterRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/EdgeCommon/pkg/rpc/pb/service_httpdns_node.pb.go b/EdgeCommon/pkg/rpc/pb/service_httpdns_node.pb.go index a89dbef..9e684be 100644 --- a/EdgeCommon/pkg/rpc/pb/service_httpdns_node.pb.go +++ b/EdgeCommon/pkg/rpc/pb/service_httpdns_node.pb.go @@ -558,6 +558,256 @@ func (x *UpdateHTTPDNSNodeLoginRequest) GetNodeLogin() *NodeLogin { return nil } +// 检查HTTPDNS节点新版本 +type CheckHTTPDNSNodeLatestVersionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Os string `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"` + Arch string `protobuf:"bytes,2,opt,name=arch,proto3" json:"arch,omitempty"` + CurrentVersion string `protobuf:"bytes,3,opt,name=currentVersion,proto3" json:"currentVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) Reset() { + *x = CheckHTTPDNSNodeLatestVersionRequest{} + mi := &file_service_httpdns_node_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckHTTPDNSNodeLatestVersionRequest) ProtoMessage() {} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_node_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckHTTPDNSNodeLatestVersionRequest.ProtoReflect.Descriptor instead. +func (*CheckHTTPDNSNodeLatestVersionRequest) Descriptor() ([]byte, []int) { + return file_service_httpdns_node_proto_rawDescGZIP(), []int{10} +} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) GetOs() string { + if x != nil { + return x.Os + } + return "" +} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +func (x *CheckHTTPDNSNodeLatestVersionRequest) GetCurrentVersion() string { + if x != nil { + return x.CurrentVersion + } + return "" +} + +type CheckHTTPDNSNodeLatestVersionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + HasNewVersion bool `protobuf:"varint,1,opt,name=hasNewVersion,proto3" json:"hasNewVersion,omitempty"` + NewVersion string `protobuf:"bytes,2,opt,name=newVersion,proto3" json:"newVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckHTTPDNSNodeLatestVersionResponse) Reset() { + *x = CheckHTTPDNSNodeLatestVersionResponse{} + mi := &file_service_httpdns_node_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckHTTPDNSNodeLatestVersionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckHTTPDNSNodeLatestVersionResponse) ProtoMessage() {} + +func (x *CheckHTTPDNSNodeLatestVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_node_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckHTTPDNSNodeLatestVersionResponse.ProtoReflect.Descriptor instead. +func (*CheckHTTPDNSNodeLatestVersionResponse) Descriptor() ([]byte, []int) { + return file_service_httpdns_node_proto_rawDescGZIP(), []int{11} +} + +func (x *CheckHTTPDNSNodeLatestVersionResponse) GetHasNewVersion() bool { + if x != nil { + return x.HasNewVersion + } + return false +} + +func (x *CheckHTTPDNSNodeLatestVersionResponse) GetNewVersion() string { + if x != nil { + return x.NewVersion + } + return "" +} + +// 下载最新HTTPDNS节点安装文件 +type DownloadHTTPDNSNodeInstallationFileRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Os string `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"` + Arch string `protobuf:"bytes,2,opt,name=arch,proto3" json:"arch,omitempty"` + ChunkOffset int64 `protobuf:"varint,3,opt,name=chunkOffset,proto3" json:"chunkOffset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) Reset() { + *x = DownloadHTTPDNSNodeInstallationFileRequest{} + mi := &file_service_httpdns_node_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownloadHTTPDNSNodeInstallationFileRequest) ProtoMessage() {} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_node_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DownloadHTTPDNSNodeInstallationFileRequest.ProtoReflect.Descriptor instead. +func (*DownloadHTTPDNSNodeInstallationFileRequest) Descriptor() ([]byte, []int) { + return file_service_httpdns_node_proto_rawDescGZIP(), []int{12} +} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) GetOs() string { + if x != nil { + return x.Os + } + return "" +} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +func (x *DownloadHTTPDNSNodeInstallationFileRequest) GetChunkOffset() int64 { + if x != nil { + return x.ChunkOffset + } + return 0 +} + +type DownloadHTTPDNSNodeInstallationFileResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ChunkData []byte `protobuf:"bytes,1,opt,name=chunkData,proto3" json:"chunkData,omitempty"` + Sum string `protobuf:"bytes,2,opt,name=sum,proto3" json:"sum,omitempty"` + Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + Filename string `protobuf:"bytes,5,opt,name=filename,proto3" json:"filename,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) Reset() { + *x = DownloadHTTPDNSNodeInstallationFileResponse{} + mi := &file_service_httpdns_node_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownloadHTTPDNSNodeInstallationFileResponse) ProtoMessage() {} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_node_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DownloadHTTPDNSNodeInstallationFileResponse.ProtoReflect.Descriptor instead. +func (*DownloadHTTPDNSNodeInstallationFileResponse) Descriptor() ([]byte, []int) { + return file_service_httpdns_node_proto_rawDescGZIP(), []int{13} +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) GetChunkData() []byte { + if x != nil { + return x.ChunkData + } + return nil +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) GetSum() string { + if x != nil { + return x.Sum + } + return "" +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *DownloadHTTPDNSNodeInstallationFileResponse) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + var File_service_httpdns_node_proto protoreflect.FileDescriptor const file_service_httpdns_node_proto_rawDesc = "" + @@ -600,7 +850,26 @@ const file_service_httpdns_node_proto_rawDesc = "" + "\x11installStatusJSON\x18\x06 \x01(\fR\x11installStatusJSON\"d\n" + "\x1dUpdateHTTPDNSNodeLoginRequest\x12\x16\n" + "\x06nodeId\x18\x01 \x01(\x03R\x06nodeId\x12+\n" + - "\tnodeLogin\x18\x02 \x01(\v2\r.pb.NodeLoginR\tnodeLogin2\xa3\x04\n" + + "\tnodeLogin\x18\x02 \x01(\v2\r.pb.NodeLoginR\tnodeLogin\"r\n" + + "$CheckHTTPDNSNodeLatestVersionRequest\x12\x0e\n" + + "\x02os\x18\x01 \x01(\tR\x02os\x12\x12\n" + + "\x04arch\x18\x02 \x01(\tR\x04arch\x12&\n" + + "\x0ecurrentVersion\x18\x03 \x01(\tR\x0ecurrentVersion\"m\n" + + "%CheckHTTPDNSNodeLatestVersionResponse\x12$\n" + + "\rhasNewVersion\x18\x01 \x01(\bR\rhasNewVersion\x12\x1e\n" + + "\n" + + "newVersion\x18\x02 \x01(\tR\n" + + "newVersion\"r\n" + + "*DownloadHTTPDNSNodeInstallationFileRequest\x12\x0e\n" + + "\x02os\x18\x01 \x01(\tR\x02os\x12\x12\n" + + "\x04arch\x18\x02 \x01(\tR\x04arch\x12 \n" + + "\vchunkOffset\x18\x03 \x01(\x03R\vchunkOffset\"\xab\x01\n" + + "+DownloadHTTPDNSNodeInstallationFileResponse\x12\x1c\n" + + "\tchunkData\x18\x01 \x01(\fR\tchunkData\x12\x10\n" + + "\x03sum\x18\x02 \x01(\tR\x03sum\x12\x16\n" + + "\x06offset\x18\x03 \x01(\x03R\x06offset\x12\x18\n" + + "\aversion\x18\x04 \x01(\tR\aversion\x12\x1a\n" + + "\bfilename\x18\x05 \x01(\tR\bfilename2\xa2\x06\n" + "\x12HTTPDNSNodeService\x12P\n" + "\x11createHTTPDNSNode\x12\x1c.pb.CreateHTTPDNSNodeRequest\x1a\x1d.pb.CreateHTTPDNSNodeResponse\x12A\n" + "\x11updateHTTPDNSNode\x12\x1c.pb.UpdateHTTPDNSNodeRequest\x1a\x0e.pb.RPCSuccess\x12A\n" + @@ -608,7 +877,9 @@ const file_service_httpdns_node_proto_rawDesc = "" + "\x0ffindHTTPDNSNode\x12\x1a.pb.FindHTTPDNSNodeRequest\x1a\x1b.pb.FindHTTPDNSNodeResponse\x12M\n" + "\x10listHTTPDNSNodes\x12\x1b.pb.ListHTTPDNSNodesRequest\x1a\x1c.pb.ListHTTPDNSNodesResponse\x12M\n" + "\x17updateHTTPDNSNodeStatus\x12\".pb.UpdateHTTPDNSNodeStatusRequest\x1a\x0e.pb.RPCSuccess\x12K\n" + - "\x16updateHTTPDNSNodeLogin\x12!.pb.UpdateHTTPDNSNodeLoginRequest\x1a\x0e.pb.RPCSuccessB\x06Z\x04./pbb\x06proto3" + "\x16updateHTTPDNSNodeLogin\x12!.pb.UpdateHTTPDNSNodeLoginRequest\x1a\x0e.pb.RPCSuccess\x12t\n" + + "\x1dcheckHTTPDNSNodeLatestVersion\x12(.pb.CheckHTTPDNSNodeLatestVersionRequest\x1a).pb.CheckHTTPDNSNodeLatestVersionResponse\x12\x86\x01\n" + + "#downloadHTTPDNSNodeInstallationFile\x12..pb.DownloadHTTPDNSNodeInstallationFileRequest\x1a/.pb.DownloadHTTPDNSNodeInstallationFileResponseB\x06Z\x04./pbb\x06proto3" var ( file_service_httpdns_node_proto_rawDescOnce sync.Once @@ -622,26 +893,30 @@ func file_service_httpdns_node_proto_rawDescGZIP() []byte { return file_service_httpdns_node_proto_rawDescData } -var file_service_httpdns_node_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_service_httpdns_node_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_service_httpdns_node_proto_goTypes = []any{ - (*CreateHTTPDNSNodeRequest)(nil), // 0: pb.CreateHTTPDNSNodeRequest - (*CreateHTTPDNSNodeResponse)(nil), // 1: pb.CreateHTTPDNSNodeResponse - (*UpdateHTTPDNSNodeRequest)(nil), // 2: pb.UpdateHTTPDNSNodeRequest - (*DeleteHTTPDNSNodeRequest)(nil), // 3: pb.DeleteHTTPDNSNodeRequest - (*FindHTTPDNSNodeRequest)(nil), // 4: pb.FindHTTPDNSNodeRequest - (*FindHTTPDNSNodeResponse)(nil), // 5: pb.FindHTTPDNSNodeResponse - (*ListHTTPDNSNodesRequest)(nil), // 6: pb.ListHTTPDNSNodesRequest - (*ListHTTPDNSNodesResponse)(nil), // 7: pb.ListHTTPDNSNodesResponse - (*UpdateHTTPDNSNodeStatusRequest)(nil), // 8: pb.UpdateHTTPDNSNodeStatusRequest - (*UpdateHTTPDNSNodeLoginRequest)(nil), // 9: pb.UpdateHTTPDNSNodeLoginRequest - (*HTTPDNSNode)(nil), // 10: pb.HTTPDNSNode - (*NodeLogin)(nil), // 11: pb.NodeLogin - (*RPCSuccess)(nil), // 12: pb.RPCSuccess + (*CreateHTTPDNSNodeRequest)(nil), // 0: pb.CreateHTTPDNSNodeRequest + (*CreateHTTPDNSNodeResponse)(nil), // 1: pb.CreateHTTPDNSNodeResponse + (*UpdateHTTPDNSNodeRequest)(nil), // 2: pb.UpdateHTTPDNSNodeRequest + (*DeleteHTTPDNSNodeRequest)(nil), // 3: pb.DeleteHTTPDNSNodeRequest + (*FindHTTPDNSNodeRequest)(nil), // 4: pb.FindHTTPDNSNodeRequest + (*FindHTTPDNSNodeResponse)(nil), // 5: pb.FindHTTPDNSNodeResponse + (*ListHTTPDNSNodesRequest)(nil), // 6: pb.ListHTTPDNSNodesRequest + (*ListHTTPDNSNodesResponse)(nil), // 7: pb.ListHTTPDNSNodesResponse + (*UpdateHTTPDNSNodeStatusRequest)(nil), // 8: pb.UpdateHTTPDNSNodeStatusRequest + (*UpdateHTTPDNSNodeLoginRequest)(nil), // 9: pb.UpdateHTTPDNSNodeLoginRequest + (*CheckHTTPDNSNodeLatestVersionRequest)(nil), // 10: pb.CheckHTTPDNSNodeLatestVersionRequest + (*CheckHTTPDNSNodeLatestVersionResponse)(nil), // 11: pb.CheckHTTPDNSNodeLatestVersionResponse + (*DownloadHTTPDNSNodeInstallationFileRequest)(nil), // 12: pb.DownloadHTTPDNSNodeInstallationFileRequest + (*DownloadHTTPDNSNodeInstallationFileResponse)(nil), // 13: pb.DownloadHTTPDNSNodeInstallationFileResponse + (*HTTPDNSNode)(nil), // 14: pb.HTTPDNSNode + (*NodeLogin)(nil), // 15: pb.NodeLogin + (*RPCSuccess)(nil), // 16: pb.RPCSuccess } var file_service_httpdns_node_proto_depIdxs = []int32{ - 10, // 0: pb.FindHTTPDNSNodeResponse.node:type_name -> pb.HTTPDNSNode - 10, // 1: pb.ListHTTPDNSNodesResponse.nodes:type_name -> pb.HTTPDNSNode - 11, // 2: pb.UpdateHTTPDNSNodeLoginRequest.nodeLogin:type_name -> pb.NodeLogin + 14, // 0: pb.FindHTTPDNSNodeResponse.node:type_name -> pb.HTTPDNSNode + 14, // 1: pb.ListHTTPDNSNodesResponse.nodes:type_name -> pb.HTTPDNSNode + 15, // 2: pb.UpdateHTTPDNSNodeLoginRequest.nodeLogin:type_name -> pb.NodeLogin 0, // 3: pb.HTTPDNSNodeService.createHTTPDNSNode:input_type -> pb.CreateHTTPDNSNodeRequest 2, // 4: pb.HTTPDNSNodeService.updateHTTPDNSNode:input_type -> pb.UpdateHTTPDNSNodeRequest 3, // 5: pb.HTTPDNSNodeService.deleteHTTPDNSNode:input_type -> pb.DeleteHTTPDNSNodeRequest @@ -649,15 +924,19 @@ var file_service_httpdns_node_proto_depIdxs = []int32{ 6, // 7: pb.HTTPDNSNodeService.listHTTPDNSNodes:input_type -> pb.ListHTTPDNSNodesRequest 8, // 8: pb.HTTPDNSNodeService.updateHTTPDNSNodeStatus:input_type -> pb.UpdateHTTPDNSNodeStatusRequest 9, // 9: pb.HTTPDNSNodeService.updateHTTPDNSNodeLogin:input_type -> pb.UpdateHTTPDNSNodeLoginRequest - 1, // 10: pb.HTTPDNSNodeService.createHTTPDNSNode:output_type -> pb.CreateHTTPDNSNodeResponse - 12, // 11: pb.HTTPDNSNodeService.updateHTTPDNSNode:output_type -> pb.RPCSuccess - 12, // 12: pb.HTTPDNSNodeService.deleteHTTPDNSNode:output_type -> pb.RPCSuccess - 5, // 13: pb.HTTPDNSNodeService.findHTTPDNSNode:output_type -> pb.FindHTTPDNSNodeResponse - 7, // 14: pb.HTTPDNSNodeService.listHTTPDNSNodes:output_type -> pb.ListHTTPDNSNodesResponse - 12, // 15: pb.HTTPDNSNodeService.updateHTTPDNSNodeStatus:output_type -> pb.RPCSuccess - 12, // 16: pb.HTTPDNSNodeService.updateHTTPDNSNodeLogin:output_type -> pb.RPCSuccess - 10, // [10:17] is the sub-list for method output_type - 3, // [3:10] is the sub-list for method input_type + 10, // 10: pb.HTTPDNSNodeService.checkHTTPDNSNodeLatestVersion:input_type -> pb.CheckHTTPDNSNodeLatestVersionRequest + 12, // 11: pb.HTTPDNSNodeService.downloadHTTPDNSNodeInstallationFile:input_type -> pb.DownloadHTTPDNSNodeInstallationFileRequest + 1, // 12: pb.HTTPDNSNodeService.createHTTPDNSNode:output_type -> pb.CreateHTTPDNSNodeResponse + 16, // 13: pb.HTTPDNSNodeService.updateHTTPDNSNode:output_type -> pb.RPCSuccess + 16, // 14: pb.HTTPDNSNodeService.deleteHTTPDNSNode:output_type -> pb.RPCSuccess + 5, // 15: pb.HTTPDNSNodeService.findHTTPDNSNode:output_type -> pb.FindHTTPDNSNodeResponse + 7, // 16: pb.HTTPDNSNodeService.listHTTPDNSNodes:output_type -> pb.ListHTTPDNSNodesResponse + 16, // 17: pb.HTTPDNSNodeService.updateHTTPDNSNodeStatus:output_type -> pb.RPCSuccess + 16, // 18: pb.HTTPDNSNodeService.updateHTTPDNSNodeLogin:output_type -> pb.RPCSuccess + 11, // 19: pb.HTTPDNSNodeService.checkHTTPDNSNodeLatestVersion:output_type -> pb.CheckHTTPDNSNodeLatestVersionResponse + 13, // 20: pb.HTTPDNSNodeService.downloadHTTPDNSNodeInstallationFile:output_type -> pb.DownloadHTTPDNSNodeInstallationFileResponse + 12, // [12:21] is the sub-list for method output_type + 3, // [3:12] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name 3, // [3:3] is the sub-list for extension extendee 0, // [0:3] is the sub-list for field type_name @@ -677,7 +956,7 @@ func file_service_httpdns_node_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_service_httpdns_node_proto_rawDesc), len(file_service_httpdns_node_proto_rawDesc)), NumEnums: 0, - NumMessages: 10, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/EdgeCommon/pkg/rpc/pb/service_httpdns_node_grpc.pb.go b/EdgeCommon/pkg/rpc/pb/service_httpdns_node_grpc.pb.go index 0d8f9e8..31b3576 100644 --- a/EdgeCommon/pkg/rpc/pb/service_httpdns_node_grpc.pb.go +++ b/EdgeCommon/pkg/rpc/pb/service_httpdns_node_grpc.pb.go @@ -19,13 +19,15 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - HTTPDNSNodeService_CreateHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/createHTTPDNSNode" - HTTPDNSNodeService_UpdateHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNode" - HTTPDNSNodeService_DeleteHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/deleteHTTPDNSNode" - HTTPDNSNodeService_FindHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/findHTTPDNSNode" - HTTPDNSNodeService_ListHTTPDNSNodes_FullMethodName = "/pb.HTTPDNSNodeService/listHTTPDNSNodes" - HTTPDNSNodeService_UpdateHTTPDNSNodeStatus_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNodeStatus" - HTTPDNSNodeService_UpdateHTTPDNSNodeLogin_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNodeLogin" + HTTPDNSNodeService_CreateHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/createHTTPDNSNode" + HTTPDNSNodeService_UpdateHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNode" + HTTPDNSNodeService_DeleteHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/deleteHTTPDNSNode" + HTTPDNSNodeService_FindHTTPDNSNode_FullMethodName = "/pb.HTTPDNSNodeService/findHTTPDNSNode" + HTTPDNSNodeService_ListHTTPDNSNodes_FullMethodName = "/pb.HTTPDNSNodeService/listHTTPDNSNodes" + HTTPDNSNodeService_UpdateHTTPDNSNodeStatus_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNodeStatus" + HTTPDNSNodeService_UpdateHTTPDNSNodeLogin_FullMethodName = "/pb.HTTPDNSNodeService/updateHTTPDNSNodeLogin" + HTTPDNSNodeService_CheckHTTPDNSNodeLatestVersion_FullMethodName = "/pb.HTTPDNSNodeService/checkHTTPDNSNodeLatestVersion" + HTTPDNSNodeService_DownloadHTTPDNSNodeInstallationFile_FullMethodName = "/pb.HTTPDNSNodeService/downloadHTTPDNSNodeInstallationFile" ) // HTTPDNSNodeServiceClient is the client API for HTTPDNSNodeService service. @@ -40,6 +42,10 @@ type HTTPDNSNodeServiceClient interface { UpdateHTTPDNSNodeStatus(ctx context.Context, in *UpdateHTTPDNSNodeStatusRequest, opts ...grpc.CallOption) (*RPCSuccess, error) // 修改HTTPDNS节点登录信息 UpdateHTTPDNSNodeLogin(ctx context.Context, in *UpdateHTTPDNSNodeLoginRequest, opts ...grpc.CallOption) (*RPCSuccess, error) + // 检查HTTPDNS节点新版本 + CheckHTTPDNSNodeLatestVersion(ctx context.Context, in *CheckHTTPDNSNodeLatestVersionRequest, opts ...grpc.CallOption) (*CheckHTTPDNSNodeLatestVersionResponse, error) + // 下载最新HTTPDNS节点安装文件 + DownloadHTTPDNSNodeInstallationFile(ctx context.Context, in *DownloadHTTPDNSNodeInstallationFileRequest, opts ...grpc.CallOption) (*DownloadHTTPDNSNodeInstallationFileResponse, error) } type hTTPDNSNodeServiceClient struct { @@ -120,6 +126,26 @@ func (c *hTTPDNSNodeServiceClient) UpdateHTTPDNSNodeLogin(ctx context.Context, i return out, nil } +func (c *hTTPDNSNodeServiceClient) CheckHTTPDNSNodeLatestVersion(ctx context.Context, in *CheckHTTPDNSNodeLatestVersionRequest, opts ...grpc.CallOption) (*CheckHTTPDNSNodeLatestVersionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CheckHTTPDNSNodeLatestVersionResponse) + err := c.cc.Invoke(ctx, HTTPDNSNodeService_CheckHTTPDNSNodeLatestVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *hTTPDNSNodeServiceClient) DownloadHTTPDNSNodeInstallationFile(ctx context.Context, in *DownloadHTTPDNSNodeInstallationFileRequest, opts ...grpc.CallOption) (*DownloadHTTPDNSNodeInstallationFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DownloadHTTPDNSNodeInstallationFileResponse) + err := c.cc.Invoke(ctx, HTTPDNSNodeService_DownloadHTTPDNSNodeInstallationFile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // HTTPDNSNodeServiceServer is the server API for HTTPDNSNodeService service. // All implementations must embed UnimplementedHTTPDNSNodeServiceServer // for forward compatibility. @@ -132,6 +158,10 @@ type HTTPDNSNodeServiceServer interface { UpdateHTTPDNSNodeStatus(context.Context, *UpdateHTTPDNSNodeStatusRequest) (*RPCSuccess, error) // 修改HTTPDNS节点登录信息 UpdateHTTPDNSNodeLogin(context.Context, *UpdateHTTPDNSNodeLoginRequest) (*RPCSuccess, error) + // 检查HTTPDNS节点新版本 + CheckHTTPDNSNodeLatestVersion(context.Context, *CheckHTTPDNSNodeLatestVersionRequest) (*CheckHTTPDNSNodeLatestVersionResponse, error) + // 下载最新HTTPDNS节点安装文件 + DownloadHTTPDNSNodeInstallationFile(context.Context, *DownloadHTTPDNSNodeInstallationFileRequest) (*DownloadHTTPDNSNodeInstallationFileResponse, error) mustEmbedUnimplementedHTTPDNSNodeServiceServer() } @@ -163,6 +193,12 @@ func (UnimplementedHTTPDNSNodeServiceServer) UpdateHTTPDNSNodeStatus(context.Con func (UnimplementedHTTPDNSNodeServiceServer) UpdateHTTPDNSNodeLogin(context.Context, *UpdateHTTPDNSNodeLoginRequest) (*RPCSuccess, error) { return nil, status.Error(codes.Unimplemented, "method UpdateHTTPDNSNodeLogin not implemented") } +func (UnimplementedHTTPDNSNodeServiceServer) CheckHTTPDNSNodeLatestVersion(context.Context, *CheckHTTPDNSNodeLatestVersionRequest) (*CheckHTTPDNSNodeLatestVersionResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CheckHTTPDNSNodeLatestVersion not implemented") +} +func (UnimplementedHTTPDNSNodeServiceServer) DownloadHTTPDNSNodeInstallationFile(context.Context, *DownloadHTTPDNSNodeInstallationFileRequest) (*DownloadHTTPDNSNodeInstallationFileResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DownloadHTTPDNSNodeInstallationFile not implemented") +} func (UnimplementedHTTPDNSNodeServiceServer) mustEmbedUnimplementedHTTPDNSNodeServiceServer() {} func (UnimplementedHTTPDNSNodeServiceServer) testEmbeddedByValue() {} @@ -310,6 +346,42 @@ func _HTTPDNSNodeService_UpdateHTTPDNSNodeLogin_Handler(srv interface{}, ctx con return interceptor(ctx, in, info, handler) } +func _HTTPDNSNodeService_CheckHTTPDNSNodeLatestVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckHTTPDNSNodeLatestVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HTTPDNSNodeServiceServer).CheckHTTPDNSNodeLatestVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HTTPDNSNodeService_CheckHTTPDNSNodeLatestVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HTTPDNSNodeServiceServer).CheckHTTPDNSNodeLatestVersion(ctx, req.(*CheckHTTPDNSNodeLatestVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _HTTPDNSNodeService_DownloadHTTPDNSNodeInstallationFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DownloadHTTPDNSNodeInstallationFileRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HTTPDNSNodeServiceServer).DownloadHTTPDNSNodeInstallationFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HTTPDNSNodeService_DownloadHTTPDNSNodeInstallationFile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HTTPDNSNodeServiceServer).DownloadHTTPDNSNodeInstallationFile(ctx, req.(*DownloadHTTPDNSNodeInstallationFileRequest)) + } + return interceptor(ctx, in, info, handler) +} + // HTTPDNSNodeService_ServiceDesc is the grpc.ServiceDesc for HTTPDNSNodeService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -345,6 +417,14 @@ var HTTPDNSNodeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "updateHTTPDNSNodeLogin", Handler: _HTTPDNSNodeService_UpdateHTTPDNSNodeLogin_Handler, }, + { + MethodName: "checkHTTPDNSNodeLatestVersion", + Handler: _HTTPDNSNodeService_CheckHTTPDNSNodeLatestVersion_Handler, + }, + { + MethodName: "downloadHTTPDNSNodeInstallationFile", + Handler: _HTTPDNSNodeService_DownloadHTTPDNSNodeInstallationFile_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "service_httpdns_node.proto", diff --git a/EdgeCommon/pkg/rpc/protos/models/model_httpdns_cluster.proto b/EdgeCommon/pkg/rpc/protos/models/model_httpdns_cluster.proto index f9e25aa..a32dcc5 100644 --- a/EdgeCommon/pkg/rpc/protos/models/model_httpdns_cluster.proto +++ b/EdgeCommon/pkg/rpc/protos/models/model_httpdns_cluster.proto @@ -15,4 +15,6 @@ message HTTPDNSCluster { bytes tlsPolicyJSON = 9; int64 createdAt = 10; int64 updatedAt = 11; + bool autoRemoteStart = 12; + bool accessLogIsOn = 13; } diff --git a/EdgeCommon/pkg/rpc/protos/service_httpdns_cluster.proto b/EdgeCommon/pkg/rpc/protos/service_httpdns_cluster.proto index f9ea0a6..8aae475 100644 --- a/EdgeCommon/pkg/rpc/protos/service_httpdns_cluster.proto +++ b/EdgeCommon/pkg/rpc/protos/service_httpdns_cluster.proto @@ -27,6 +27,8 @@ message CreateHTTPDNSClusterRequest { bytes tlsPolicyJSON = 6; bool isOn = 7; bool isDefault = 8; + bool autoRemoteStart = 9; + bool accessLogIsOn = 10; } message CreateHTTPDNSClusterResponse { @@ -43,6 +45,8 @@ message UpdateHTTPDNSClusterRequest { bytes tlsPolicyJSON = 7; bool isOn = 8; bool isDefault = 9; + bool autoRemoteStart = 10; + bool accessLogIsOn = 11; } message DeleteHTTPDNSClusterRequest { diff --git a/EdgeCommon/pkg/rpc/protos/service_httpdns_node.proto b/EdgeCommon/pkg/rpc/protos/service_httpdns_node.proto index 97227df..53b8b4c 100644 --- a/EdgeCommon/pkg/rpc/protos/service_httpdns_node.proto +++ b/EdgeCommon/pkg/rpc/protos/service_httpdns_node.proto @@ -16,6 +16,12 @@ service HTTPDNSNodeService { rpc updateHTTPDNSNodeStatus (UpdateHTTPDNSNodeStatusRequest) returns (RPCSuccess); // 修改HTTPDNS节点登录信息 rpc updateHTTPDNSNodeLogin (UpdateHTTPDNSNodeLoginRequest) returns (RPCSuccess); + + // 检查HTTPDNS节点新版本 + rpc checkHTTPDNSNodeLatestVersion (CheckHTTPDNSNodeLatestVersionRequest) returns (CheckHTTPDNSNodeLatestVersionResponse); + + // 下载最新HTTPDNS节点安装文件 + rpc downloadHTTPDNSNodeInstallationFile (DownloadHTTPDNSNodeInstallationFileRequest) returns (DownloadHTTPDNSNodeInstallationFileResponse); } message CreateHTTPDNSNodeRequest { @@ -70,3 +76,30 @@ message UpdateHTTPDNSNodeLoginRequest { int64 nodeId = 1; NodeLogin nodeLogin = 2; } + +// 检查HTTPDNS节点新版本 +message CheckHTTPDNSNodeLatestVersionRequest { + string os = 1; + string arch = 2; + string currentVersion = 3; +} + +message CheckHTTPDNSNodeLatestVersionResponse { + bool hasNewVersion = 1; + string newVersion = 2; +} + +// 下载最新HTTPDNS节点安装文件 +message DownloadHTTPDNSNodeInstallationFileRequest { + string os = 1; + string arch = 2; + int64 chunkOffset = 3; +} + +message DownloadHTTPDNSNodeInstallationFileResponse { + bytes chunkData = 1; + string sum = 2; + int64 offset = 3; + string version = 4; + string filename = 5; +} diff --git a/EdgeCommon/pkg/userconfigs/user_features.go b/EdgeCommon/pkg/userconfigs/user_features.go index a881206..9afcde0 100644 --- a/EdgeCommon/pkg/userconfigs/user_features.go +++ b/EdgeCommon/pkg/userconfigs/user_features.go @@ -213,12 +213,7 @@ func FindAllUserFeatures() []*UserFeature { Description: "用户可以购买和管理套餐。", SupportPlan: false, }, - { - Name: "HTTPDNS", - Code: UserFeatureCodeHTTPDNS, - Description: "用户可以使用 HTTPDNS 应用管理、访问日志和解析测试。", - SupportPlan: false, - }, + // HTTPDNS 功能已改为通过用户设置页面全局开关控制,不再作为单独的功能选项 } } diff --git a/EdgeHttpDNS/Android SDK集成文档.md b/EdgeHttpDNS/HTTPDNS SDK 集成文档(Android).md similarity index 98% rename from EdgeHttpDNS/Android SDK集成文档.md rename to EdgeHttpDNS/HTTPDNS SDK 集成文档(Android).md index 9dfca0d..5da43a4 100644 --- a/EdgeHttpDNS/Android SDK集成文档.md +++ b/EdgeHttpDNS/HTTPDNS SDK 集成文档(Android).md @@ -1,4 +1,4 @@ -# Android SDK 集成文档(Edge HTTPDNS) +# HTTPDNS SDK 集成文档(Android) ## 1. 版本与依赖 diff --git a/EdgeHttpDNS/internal/apps/app_cmd.go b/EdgeHttpDNS/internal/apps/app_cmd.go index 208fd9e..d7db2f8 100644 --- a/EdgeHttpDNS/internal/apps/app_cmd.go +++ b/EdgeHttpDNS/internal/apps/app_cmd.go @@ -94,7 +94,11 @@ func (a *AppCmd) runStart() { return } - cmd := exec.Command(os.Args[0]) + exe, _ := os.Executable() + if len(exe) == 0 { + exe = os.Args[0] + } + cmd := exec.Command(exe) cmd.Env = append(os.Environ(), "EdgeBackground=on") err := cmd.Start() if err != nil { diff --git a/EdgeHttpDNS/internal/nodes/httpdns_node.go b/EdgeHttpDNS/internal/nodes/httpdns_node.go index e799f05..322da60 100644 --- a/EdgeHttpDNS/internal/nodes/httpdns_node.go +++ b/EdgeHttpDNS/internal/nodes/httpdns_node.go @@ -16,6 +16,9 @@ import ( "github.com/iwind/gosock/pkg/gosock" ) +var DaemonIsOn = false +var DaemonPid = 0 + type HTTPDNSNode struct { sock *gosock.Sock @@ -31,6 +34,12 @@ func NewHTTPDNSNode() *HTTPDNSNode { } func (n *HTTPDNSNode) Run() { + _, ok := os.LookupEnv("EdgeDaemon") + if ok { + DaemonIsOn = true + DaemonPid = os.Getppid() + } + err := n.listenSock() if err != nil { log.Println("[HTTPDNS_NODE]" + err.Error()) @@ -54,7 +63,7 @@ func (n *HTTPDNSNode) Daemon() { } cmd := exec.Command(exe) - cmd.Env = append(os.Environ(), "EdgeBackground=on") + cmd.Env = append(os.Environ(), "EdgeBackground=on", "EdgeDaemon=on") if runtime.GOOS != "windows" { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -147,6 +156,8 @@ func (n *HTTPDNSNode) start() { go statusManager.Start() go taskManager.Start() go resolveServer.Start() + + go NewUpgradeManager().Loop() } func (n *HTTPDNSNode) stop() { diff --git a/EdgeHttpDNS/internal/nodes/upgrade_manager.go b/EdgeHttpDNS/internal/nodes/upgrade_manager.go new file mode 100644 index 0000000..291ac2f --- /dev/null +++ b/EdgeHttpDNS/internal/nodes/upgrade_manager.go @@ -0,0 +1,280 @@ +package nodes + +import ( + "crypto/md5" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "time" + + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + teaconst "github.com/TeaOSLab/EdgeHttpDNS/internal/const" + "github.com/TeaOSLab/EdgeHttpDNS/internal/rpc" + "github.com/TeaOSLab/EdgeHttpDNS/internal/utils" + "github.com/iwind/TeaGo/Tea" + stringutil "github.com/iwind/TeaGo/utils/string" + "github.com/iwind/gosock/pkg/gosock" +) + +// UpgradeManager 节点升级管理器 +type UpgradeManager struct { + isInstalling bool + lastFile string + exe string +} + +// NewUpgradeManager 获取新对象 +func NewUpgradeManager() *UpgradeManager { + return &UpgradeManager{} +} + +// Loop 启动升级检查循环(每1分钟) +func (this *UpgradeManager) Loop() { + rpcClient, err := rpc.SharedRPC() + if err != nil { + log.Println("[UPGRADE_MANAGER]" + err.Error()) + return + } + + var ticker = time.NewTicker(1 * time.Minute) + for range ticker.C { + resp, err := rpcClient.HTTPDNSNodeRPC.CheckHTTPDNSNodeLatestVersion(rpcClient.Context(), &pb.CheckHTTPDNSNodeLatestVersionRequest{ + Os: runtime.GOOS, + Arch: runtime.GOARCH, + CurrentVersion: teaconst.Version, + }) + if err != nil { + log.Println("[UPGRADE_MANAGER]check version failed: " + err.Error()) + continue + } + if resp.HasNewVersion { + this.Start() + } + } +} + +// Start 启动升级 +func (this *UpgradeManager) Start() { + // 必须放在文件解压之前读取可执行文件路径,防止解压之后,当前的可执行文件路径发生改变 + exe, err := os.Executable() + if err != nil { + log.Println("[UPGRADE_MANAGER]can not find current executable file name") + return + } + this.exe = exe + + // 测试环境下不更新 + if Tea.IsTesting() { + return + } + + if this.isInstalling { + return + } + this.isInstalling = true + + // 还原安装状态 + defer func() { + this.isInstalling = false + }() + + log.Println("[UPGRADE_MANAGER]upgrading httpdns node ...") + err = this.install() + if err != nil { + log.Println("[UPGRADE_MANAGER]download failed: " + err.Error()) + return + } + + log.Println("[UPGRADE_MANAGER]upgrade successfully") + + go func() { + err = this.restart() + if err != nil { + log.Println("[UPGRADE_MANAGER]" + err.Error()) + } + }() +} + +func (this *UpgradeManager) install() error { + // 检查是否有已下载但未安装成功的 + if len(this.lastFile) > 0 { + _, err := os.Stat(this.lastFile) + if err == nil { + err = this.unzip(this.lastFile) + if err != nil { + return err + } + this.lastFile = "" + return nil + } + } + + // 创建临时文件 + dir := Tea.Root + "/tmp" + _, err := os.Stat(dir) + if err != nil { + if os.IsNotExist(err) { + err = os.Mkdir(dir, 0777) + if err != nil { + return err + } + } else { + return err + } + } + + log.Println("[UPGRADE_MANAGER]downloading new node ...") + + path := dir + "/" + teaconst.ProcessName + ".tmp" + fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777) + if err != nil { + return err + } + isClosed := false + defer func() { + if !isClosed { + _ = fp.Close() + } + }() + + client, err := rpc.SharedRPC() + if err != nil { + return err + } + + var offset int64 + var h = md5.New() + var sum = "" + var filename = "" + for { + resp, err := client.HTTPDNSNodeRPC.DownloadHTTPDNSNodeInstallationFile(client.Context(), &pb.DownloadHTTPDNSNodeInstallationFileRequest{ + Os: runtime.GOOS, + Arch: runtime.GOARCH, + ChunkOffset: offset, + }) + if err != nil { + return err + } + if len(resp.Sum) == 0 { + return nil + } + sum = resp.Sum + filename = resp.Filename + if stringutil.VersionCompare(resp.Version, teaconst.Version) <= 0 { + return nil + } + if len(resp.ChunkData) == 0 { + break + } + + // 写入文件 + _, err = fp.Write(resp.ChunkData) + if err != nil { + return err + } + _, err = h.Write(resp.ChunkData) + if err != nil { + return err + } + + offset = resp.Offset + } + + if len(filename) == 0 { + return nil + } + + isClosed = true + err = fp.Close() + if err != nil { + return err + } + + if fmt.Sprintf("%x", h.Sum(nil)) != sum { + _ = os.Remove(path) + return nil + } + + // 改成zip + zipPath := dir + "/" + filename + err = os.Rename(path, zipPath) + if err != nil { + return err + } + this.lastFile = zipPath + + // 解压 + err = this.unzip(zipPath) + if err != nil { + return err + } + + return nil +} + +// 解压 +func (this *UpgradeManager) unzip(zipPath string) error { + var isOk = false + defer func() { + if isOk { + // 只有解压并覆盖成功后才会删除 + _ = os.Remove(zipPath) + } + }() + + // 解压 + var target = Tea.Root + if Tea.IsTesting() { + // 测试环境下只解压在tmp目录 + target = Tea.Root + "/tmp" + } + + // 先改先前的可执行文件 + err := os.Rename(target+"/bin/"+teaconst.ProcessName, target+"/bin/."+teaconst.ProcessName+".dist") + hasBackup := err == nil + defer func() { + if !isOk && hasBackup { + // 失败时还原 + _ = os.Rename(target+"/bin/."+teaconst.ProcessName+".dist", target+"/bin/"+teaconst.ProcessName) + } + }() + + unzip := utils.NewUnzip(zipPath, target, teaconst.ProcessName+"/") + err = unzip.Run() + if err != nil { + return err + } + + isOk = true + + return nil +} + +// 重启 +func (this *UpgradeManager) restart() error { + // 关闭当前sock,防止无法重启 + _ = gosock.NewTmpSock(teaconst.ProcessName).Close() + + // 重新启动 + if DaemonIsOn && DaemonPid == os.Getppid() { + os.Exit(0) + } else { + // 启动 + var exe = filepath.Dir(this.exe) + "/" + teaconst.ProcessName + + log.Println("[UPGRADE_MANAGER]restarting ...", exe) + cmd := exec.Command(exe, "start") + err := cmd.Start() + if err != nil { + return err + } + + // 退出当前进程 + time.Sleep(1 * time.Second) + os.Exit(0) + } + return nil +} diff --git a/EdgeHttpDNS/internal/utils/unzip.go b/EdgeHttpDNS/internal/utils/unzip.go new file mode 100644 index 0000000..95e4bdb --- /dev/null +++ b/EdgeHttpDNS/internal/utils/unzip.go @@ -0,0 +1,98 @@ +package utils + +import ( + "archive/zip" + "errors" + "io" + "os" + "strings" +) + +type Unzip struct { + zipFile string + targetDir string + stripPrefix string +} + +func NewUnzip(zipFile string, targetDir string, stripPrefix string) *Unzip { + return &Unzip{ + zipFile: zipFile, + targetDir: targetDir, + stripPrefix: stripPrefix, + } +} + +func (this *Unzip) Run() error { + if len(this.zipFile) == 0 { + return errors.New("zip file should not be empty") + } + if len(this.targetDir) == 0 { + return errors.New("target dir should not be empty") + } + + reader, err := zip.OpenReader(this.zipFile) + if err != nil { + return err + } + + defer func() { + _ = reader.Close() + }() + + for _, file := range reader.File { + info := file.FileInfo() + filename := file.Name + if len(this.stripPrefix) > 0 { + filename = strings.TrimPrefix(filename, this.stripPrefix) + } + target := this.targetDir + "/" + filename + + // 目录 + if info.IsDir() { + stat, err := os.Stat(target) + if err != nil { + if !os.IsNotExist(err) { + return err + } else { + err = os.MkdirAll(target, info.Mode()) + if err != nil { + return err + } + } + } else if !stat.IsDir() { + err = os.MkdirAll(target, info.Mode()) + if err != nil { + return err + } + } + continue + } + + // 文件 + err := func(file *zip.File, target string) error { + fileReader, err := file.Open() + if err != nil { + return err + } + defer func() { + _ = fileReader.Close() + }() + + fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode()) + if err != nil { + return err + } + defer func() { + _ = fileWriter.Close() + }() + + _, err = io.Copy(fileWriter, fileReader) + return err + }(file, target) + if err != nil { + return err + } + } + + return nil +} diff --git a/EdgeUser/internal/web/helpers/user_must_auth.go b/EdgeUser/internal/web/helpers/user_must_auth.go index 7efd70d..b9563f3 100644 --- a/EdgeUser/internal/web/helpers/user_must_auth.go +++ b/EdgeUser/internal/web/helpers/user_must_auth.go @@ -430,7 +430,7 @@ func (this *userMustAuth) modules(userId int64, isVerified bool, isIdentified bo "code": "httpdns", "name": "HTTPDNS", "icon": "shield alternate", - "isOn": lists.ContainsString(featureCodes, userconfigs.UserFeatureCodeHTTPDNS), + "isOn": registerConfig != nil && registerConfig.HTTPDNSIsOn, "subItems": []maps.Map{ { "name": "应用管理",