diff --git a/EdgeAPI/build/build.sh b/EdgeAPI/build/build.sh index 9c58075..57f19b2 100644 --- a/EdgeAPI/build/build.sh +++ b/EdgeAPI/build/build.sh @@ -128,13 +128,11 @@ function build() { # copy files echo "copying ..." - if [ ! -d "$DIST" ]; then - mkdir "$DIST" - mkdir "$DIST"/bin - mkdir "$DIST"/configs - mkdir "$DIST"/logs - mkdir "$DIST"/data - fi + rm -rf "$DIST" + mkdir -p "$DIST"/bin + mkdir -p "$DIST"/configs + mkdir -p "$DIST"/logs + mkdir -p "$DIST"/data cp "$ROOT"/configs/api.template.yaml "$DIST"/configs/ cp "$ROOT"/configs/db.template.yaml "$DIST"/configs/ # 复制 EdgeCommon 的配置文件(如果存在) @@ -148,42 +146,6 @@ function build() { rm -f "$DIST"/deploy/.gitignore cp -R "$ROOT"/installers "$DIST"/ - # copy fluent-bit templates and local packages from repo root - FLUENT_ROOT="$ROOT/../../deploy/fluent-bit" - FLUENT_DIST="$DIST/deploy/fluent-bit" - if [ -d "$FLUENT_ROOT" ]; then - rm -rf "$FLUENT_DIST" - mkdir -p "$FLUENT_DIST" - - FLUENT_FILES=( - "fluent-bit.conf" - "fluent-bit-dns.conf" - "fluent-bit-https.conf" - "fluent-bit-dns-https.conf" - "fluent-bit-windows.conf" - "fluent-bit-windows-https.conf" - "parsers.conf" - "clickhouse-upstream.conf" - "clickhouse-upstream-windows.conf" - "logrotate.conf" - "README.md" - ) - for file in "${FLUENT_FILES[@]}"; do - if [ -f "$FLUENT_ROOT/$file" ]; then - cp "$FLUENT_ROOT/$file" "$FLUENT_DIST/" - fi - done - - if [ -d "$FLUENT_ROOT/packages" ]; then - cp -R "$FLUENT_ROOT/packages" "$FLUENT_DIST/" - fi - - # remove local runtime artifacts if present - rm -f "$FLUENT_DIST/.gitignore" - rm -f "$FLUENT_DIST"/logs.db* - rm -rf "$FLUENT_DIST/storage" - fi - # building edge installer echo "building node installer ..." architects=("amd64") diff --git a/EdgeAPI/internal/clickhouse/httpdns_access_logs_store.go b/EdgeAPI/internal/clickhouse/httpdns_access_logs_store.go index a794c5c..3e73d61 100644 --- a/EdgeAPI/internal/clickhouse/httpdns_access_logs_store.go +++ b/EdgeAPI/internal/clickhouse/httpdns_access_logs_store.go @@ -47,6 +47,33 @@ type HTTPDNSAccessLogListFilter struct { Size int64 } +type HTTPDNSAccessLogHourlyStat struct { + Hour string + CountRequests int64 +} + +type HTTPDNSAccessLogDailyStat struct { + Day string + CountRequests int64 +} + +type HTTPDNSAccessLogTopAppStat struct { + AppId string + AppName string + CountRequests int64 +} + +type HTTPDNSAccessLogTopDomainStat struct { + Domain string + CountRequests int64 +} + +type HTTPDNSAccessLogTopNodeStat struct { + ClusterId uint32 + NodeId uint32 + CountRequests int64 +} + type HTTPDNSAccessLogsStore struct { client *Client } @@ -176,6 +203,155 @@ func (s *HTTPDNSAccessLogsStore) List(ctx context.Context, f HTTPDNSAccessLogLis return result, nil } +func (s *HTTPDNSAccessLogsStore) FindHourlyStats(ctx context.Context, hourFrom string, hourTo string) ([]*HTTPDNSAccessLogHourlyStat, error) { + if !s.client.IsConfigured() { + return nil, fmt.Errorf("clickhouse: not configured") + } + + query := fmt.Sprintf( + "SELECT formatDateTime(toDateTime(created_at), '%%Y%%m%%d%%H') AS hour, count() AS count_requests FROM %s WHERE formatDateTime(toDateTime(created_at), '%%Y%%m%%d%%H') BETWEEN '%s' AND '%s' GROUP BY hour ORDER BY hour ASC", + s.tableName(), + escapeString(hourFrom), + escapeString(hourTo), + ) + + rows := []map[string]interface{}{} + if err := s.client.Query(ctx, query, &rows); err != nil { + return nil, err + } + + result := make([]*HTTPDNSAccessLogHourlyStat, 0, len(rows)) + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogHourlyStat{ + Hour: toString(row["hour"]), + CountRequests: toInt64(row["count_requests"]), + }) + } + return result, nil +} + +func (s *HTTPDNSAccessLogsStore) FindDailyStats(ctx context.Context, dayFrom string, dayTo string) ([]*HTTPDNSAccessLogDailyStat, error) { + if !s.client.IsConfigured() { + return nil, fmt.Errorf("clickhouse: not configured") + } + + query := fmt.Sprintf( + "SELECT day, count() AS count_requests FROM %s WHERE day BETWEEN '%s' AND '%s' GROUP BY day ORDER BY day ASC", + s.tableName(), + escapeString(dayFrom), + escapeString(dayTo), + ) + + rows := []map[string]interface{}{} + if err := s.client.Query(ctx, query, &rows); err != nil { + return nil, err + } + + result := make([]*HTTPDNSAccessLogDailyStat, 0, len(rows)) + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogDailyStat{ + Day: toString(row["day"]), + CountRequests: toInt64(row["count_requests"]), + }) + } + return result, nil +} + +func (s *HTTPDNSAccessLogsStore) ListTopApps(ctx context.Context, dayFrom string, dayTo string, limit int64) ([]*HTTPDNSAccessLogTopAppStat, error) { + if !s.client.IsConfigured() { + return nil, fmt.Errorf("clickhouse: not configured") + } + if limit <= 0 { + limit = 10 + } + + query := fmt.Sprintf( + "SELECT app_id, max(app_name) AS app_name, count() AS count_requests FROM %s WHERE day BETWEEN '%s' AND '%s' GROUP BY app_id ORDER BY count_requests DESC LIMIT %d", + s.tableName(), + escapeString(dayFrom), + escapeString(dayTo), + limit, + ) + + rows := []map[string]interface{}{} + if err := s.client.Query(ctx, query, &rows); err != nil { + return nil, err + } + + result := make([]*HTTPDNSAccessLogTopAppStat, 0, len(rows)) + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopAppStat{ + AppId: toString(row["app_id"]), + AppName: toString(row["app_name"]), + CountRequests: toInt64(row["count_requests"]), + }) + } + return result, nil +} + +func (s *HTTPDNSAccessLogsStore) ListTopDomains(ctx context.Context, dayFrom string, dayTo string, limit int64) ([]*HTTPDNSAccessLogTopDomainStat, error) { + if !s.client.IsConfigured() { + return nil, fmt.Errorf("clickhouse: not configured") + } + if limit <= 0 { + limit = 10 + } + + query := fmt.Sprintf( + "SELECT domain, count() AS count_requests FROM %s WHERE day BETWEEN '%s' AND '%s' AND domain != '' GROUP BY domain ORDER BY count_requests DESC LIMIT %d", + s.tableName(), + escapeString(dayFrom), + escapeString(dayTo), + limit, + ) + + rows := []map[string]interface{}{} + if err := s.client.Query(ctx, query, &rows); err != nil { + return nil, err + } + + result := make([]*HTTPDNSAccessLogTopDomainStat, 0, len(rows)) + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopDomainStat{ + Domain: toString(row["domain"]), + CountRequests: toInt64(row["count_requests"]), + }) + } + return result, nil +} + +func (s *HTTPDNSAccessLogsStore) ListTopNodes(ctx context.Context, dayFrom string, dayTo string, limit int64) ([]*HTTPDNSAccessLogTopNodeStat, error) { + if !s.client.IsConfigured() { + return nil, fmt.Errorf("clickhouse: not configured") + } + if limit <= 0 { + limit = 10 + } + + query := fmt.Sprintf( + "SELECT min(cluster_id) AS cluster_id, node_id, count() AS count_requests FROM %s WHERE day BETWEEN '%s' AND '%s' GROUP BY node_id ORDER BY count_requests DESC LIMIT %d", + s.tableName(), + escapeString(dayFrom), + escapeString(dayTo), + limit, + ) + + rows := []map[string]interface{}{} + if err := s.client.Query(ctx, query, &rows); err != nil { + return nil, err + } + + result := make([]*HTTPDNSAccessLogTopNodeStat, 0, len(rows)) + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopNodeStat{ + ClusterId: uint32(toInt64(row["cluster_id"])), + NodeId: uint32(toInt64(row["node_id"])), + CountRequests: toInt64(row["count_requests"]), + }) + } + return result, nil +} + func HTTPDNSRowToPB(row *HTTPDNSAccessLogRow) *pb.HTTPDNSAccessLog { if row == nil { return nil diff --git a/EdgeAPI/internal/const/const.go b/EdgeAPI/internal/const/const.go index c3b3d66..daab8e9 100644 --- a/EdgeAPI/internal/const/const.go +++ b/EdgeAPI/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "1.4.9" //1.3.9 + Version = "1.5.0" //1.3.9 ProductName = "Edge API" ProcessName = "edge-api" @@ -17,6 +17,6 @@ const ( // 其他节点版本号,用来检测是否有需要升级的节点 - NodeVersion = "1.4.9" //1.3.8.2 + NodeVersion = "1.5.0" //1.3.8.2 ) diff --git a/EdgeAPI/internal/const/const_plus.go b/EdgeAPI/internal/const/const_plus.go index 5b679bd..2bb0568 100644 --- a/EdgeAPI/internal/const/const_plus.go +++ b/EdgeAPI/internal/const/const_plus.go @@ -4,9 +4,9 @@ package teaconst const ( - DNSNodeVersion = "1.4.9" //1.3.8.2 - UserNodeVersion = "1.4.9" //1.3.8.2 - ReportNodeVersion = "0.1.5" + DNSNodeVersion = "1.5.0" //1.3.8.2 + UserNodeVersion = "1.5.0" //1.3.8.2 + ReportNodeVersion = "1.5.0" DefaultMaxNodes int32 = 50 ) diff --git a/EdgeAPI/internal/db/models/httpdns_access_log_dao_stat.go b/EdgeAPI/internal/db/models/httpdns_access_log_dao_stat.go new file mode 100644 index 0000000..fc17dcc --- /dev/null +++ b/EdgeAPI/internal/db/models/httpdns_access_log_dao_stat.go @@ -0,0 +1,138 @@ +package models + +import ( + "github.com/iwind/TeaGo/dbs" +) + +type HTTPDNSAccessLogHourlyStat struct { + Hour string `field:"hour"` + CountRequests int64 `field:"countRequests"` +} + +type HTTPDNSAccessLogDailyStat struct { + Day string `field:"day"` + CountRequests int64 `field:"countRequests"` +} + +type HTTPDNSAccessLogTopAppStat struct { + AppId string `field:"appId"` + AppName string `field:"appName"` + CountRequests int64 `field:"countRequests"` +} + +type HTTPDNSAccessLogTopDomainStat struct { + Domain string `field:"domain"` + CountRequests int64 `field:"countRequests"` +} + +type HTTPDNSAccessLogTopNodeStat struct { + ClusterId uint32 `field:"clusterId"` + NodeId uint32 `field:"nodeId"` + CountRequests int64 `field:"countRequests"` +} + +func (this *HTTPDNSAccessLogDAO) FindHourlyStats(tx *dbs.Tx, hourFrom string, hourTo string) (result []*HTTPDNSAccessLogHourlyStat, err error) { + rows, _, err := this.Query(tx). + Result("CONCAT(day, LPAD(HOUR(FROM_UNIXTIME(createdAt)),2,'0')) AS hour", "COUNT(*) AS countRequests"). + Where("CONCAT(day, LPAD(HOUR(FROM_UNIXTIME(createdAt)),2,'0')) BETWEEN :hourFrom AND :hourTo"). + Param("hourFrom", hourFrom). + Param("hourTo", hourTo). + Group("hour"). + FindOnes() + if err != nil { + return nil, err + } + + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogHourlyStat{ + Hour: row.GetString("hour"), + CountRequests: row.GetInt64("countRequests"), + }) + } + return +} + +func (this *HTTPDNSAccessLogDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*HTTPDNSAccessLogDailyStat, err error) { + rows, _, err := this.Query(tx). + Result("day", "COUNT(*) AS countRequests"). + Between("day", dayFrom, dayTo). + Group("day"). + FindOnes() + if err != nil { + return nil, err + } + + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogDailyStat{ + Day: row.GetString("day"), + CountRequests: row.GetInt64("countRequests"), + }) + } + return +} + +func (this *HTTPDNSAccessLogDAO) ListTopApps(tx *dbs.Tx, dayFrom string, dayTo string, limit int64) (result []*HTTPDNSAccessLogTopAppStat, err error) { + rows, _, err := this.Query(tx). + Result("appId", "MAX(appName) AS appName", "COUNT(*) AS countRequests"). + Between("day", dayFrom, dayTo). + Group("appId"). + Desc("countRequests"). + Limit(limit). + FindOnes() + if err != nil { + return nil, err + } + + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopAppStat{ + AppId: row.GetString("appId"), + AppName: row.GetString("appName"), + CountRequests: row.GetInt64("countRequests"), + }) + } + return +} + +func (this *HTTPDNSAccessLogDAO) ListTopDomains(tx *dbs.Tx, dayFrom string, dayTo string, limit int64) (result []*HTTPDNSAccessLogTopDomainStat, err error) { + rows, _, err := this.Query(tx). + Result("domain", "COUNT(*) AS countRequests"). + Between("day", dayFrom, dayTo). + Where("domain != ''"). + Group("domain"). + Desc("countRequests"). + Limit(limit). + FindOnes() + if err != nil { + return nil, err + } + + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopDomainStat{ + Domain: row.GetString("domain"), + CountRequests: row.GetInt64("countRequests"), + }) + } + return +} + +func (this *HTTPDNSAccessLogDAO) ListTopNodes(tx *dbs.Tx, dayFrom string, dayTo string, limit int64) (result []*HTTPDNSAccessLogTopNodeStat, err error) { + rows, _, err := this.Query(tx). + Result("MIN(clusterId) AS clusterId", "nodeId", "COUNT(*) AS countRequests"). + Between("day", dayFrom, dayTo). + Group("nodeId"). + Desc("countRequests"). + Limit(limit). + FindOnes() + if err != nil { + return nil, err + } + + for _, row := range rows { + result = append(result, &HTTPDNSAccessLogTopNodeStat{ + ClusterId: row.GetUint32("clusterId"), + NodeId: row.GetUint32("nodeId"), + CountRequests: row.GetInt64("countRequests"), + }) + } + return +} diff --git a/EdgeAPI/internal/db/models/httpdns_domain_dao.go b/EdgeAPI/internal/db/models/httpdns_domain_dao.go index 2330869..b4133ea 100644 --- a/EdgeAPI/internal/db/models/httpdns_domain_dao.go +++ b/EdgeAPI/internal/db/models/httpdns_domain_dao.go @@ -113,3 +113,11 @@ func (this *HTTPDNSDomainDAO) ListEnabledDomainsWithAppId(tx *dbs.Tx, appDbId in _, err = query.Slice(&result).FindAll() return } + +func (this *HTTPDNSDomainDAO) CountEnabledDomains(tx *dbs.Tx, appDbId int64) (int64, error) { + query := this.Query(tx).State(HTTPDNSDomainStateEnabled) + if appDbId > 0 { + query = query.Attr("appId", appDbId) + } + return query.Count() +} diff --git a/EdgeAPI/internal/db/models/node_value_dao.go b/EdgeAPI/internal/db/models/node_value_dao.go index c9f523d..7422376 100644 --- a/EdgeAPI/internal/db/models/node_value_dao.go +++ b/EdgeAPI/internal/db/models/node_value_dao.go @@ -221,6 +221,41 @@ func (this *NodeValueDAO) ListValuesForNSNodes(tx *dbs.Tx, item string, key stri return } +// ListValuesForHTTPDNSNodes 列出HTTPDNS节点相关的平均数据 +func (this *NodeValueDAO) ListValuesForHTTPDNSNodes(tx *dbs.Tx, item string, key string, timeRange nodeconfigs.NodeValueRange) (result []*NodeValue, err error) { + query := this.Query(tx). + Attr("role", "httpdns"). + Attr("item", item). + Result("AVG(JSON_EXTRACT(value, '$." + key + "')) AS value, MIN(createdAt) AS createdAt") + + switch timeRange { + // TODO 支持更多的时间范围 + case nodeconfigs.NodeValueRangeMinute: + fromMinute := timeutil.FormatTime("YmdHi", time.Now().Unix()-3600) // 一个小时之前的 + query.Gte("minute", fromMinute) + query.Result("minute") + query.Group("minute") + default: + err = errors.New("invalid 'range' value: '" + timeRange + "'") + return + } + + _, err = query.Slice(&result). + FindAll() + + if err != nil { + return nil, err + } + + for _, nodeValue := range result { + nodeValue.Value, _ = json.Marshal(maps.Map{ + key: types.Float32(string(nodeValue.Value)), + }) + } + + return +} + // SumAllNodeValues 计算所有节点的某项参数值 func (this *NodeValueDAO) SumAllNodeValues(tx *dbs.Tx, role string, item nodeconfigs.NodeValueItem, param string, duration int32, durationUnit nodeconfigs.NodeValueDurationUnit) (total float64, avg float64, max float64, err error) { if duration <= 0 { diff --git a/EdgeAPI/internal/installers/fluent_bit.go b/EdgeAPI/internal/installers/fluent_bit.go deleted file mode 100644 index 9357b1d..0000000 --- a/EdgeAPI/internal/installers/fluent_bit.go +++ /dev/null @@ -1,889 +0,0 @@ -package installers - -import ( - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "net/url" - "os" - slashpath "path" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - - teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" - "github.com/TeaOSLab/EdgeAPI/internal/db/models" - "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - "github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs" - "github.com/iwind/TeaGo/Tea" -) - -const ( - fluentBitConfigDir = "/etc/fluent-bit" - fluentBitStorageDir = "/var/lib/fluent-bit/storage" - fluentBitMainConfigFile = "/etc/fluent-bit/fluent-bit.conf" - fluentBitParsersFile = "/etc/fluent-bit/parsers.conf" - fluentBitManagedMetaFile = "/etc/fluent-bit/.edge-managed.json" - fluentBitManagedEnvFile = "/etc/fluent-bit/.edge-managed.env" - fluentBitDropInDir = "/etc/systemd/system/fluent-bit.service.d" - fluentBitDropInFile = "/etc/systemd/system/fluent-bit.service.d/edge-managed.conf" - fluentBitServiceName = "fluent-bit" - fluentBitDefaultBinPath = "/opt/fluent-bit/bin/fluent-bit" - fluentBitLocalPackagesRoot = "packages" - fluentBitHTTPPathPattern = "/var/log/edge/edge-node/*.log" - fluentBitDNSPathPattern = "/var/log/edge/edge-dns/*.log" - fluentBitHTTPDNSPathPattern = "/var/log/edge/edge-httpdns/*.log" - fluentBitManagedMarker = "managed-by-edgeapi" - fluentBitRoleNode = "node" - fluentBitRoleDNS = "dns" - fluentBitRoleHTTPDNS = "httpdns" -) - -var errFluentBitLocalPackageNotFound = errors.New("fluent-bit local package not found") - -var fluentBitPackageFileMapping = map[string]string{ - "ubuntu22.04-amd64": "fluent-bit_4.2.2_amd64.deb", - "ubuntu22.04-arm64": "fluent-bit_4.2.2_arm64.deb", - "amzn2023-amd64": "fluent-bit-4.2.2-1.x86_64.rpm", - "amzn2023-arm64": "fluent-bit-4.2.2-1.aarch64.rpm", -} - -type fluentBitManagedMeta struct { - Roles []string `json:"roles"` - Hash string `json:"hash"` - UpdatedAt int64 `json:"updatedAt"` - SourceVersion string `json:"sourceVersion"` -} - -type fluentBitDesiredConfig struct { - Roles []string - ClickHouse *systemconfigs.ClickHouseSetting - HTTPPathPattern string - DNSPathPattern string - HTTPDNSPathPattern string -} - -// SetupFluentBit 安装并托管 Fluent Bit 配置(离线包 + 平台渲染配置)。 -func (this *BaseInstaller) SetupFluentBit(role nodeconfigs.NodeRole) error { - if this.client == nil { - return errors.New("ssh client is nil") - } - - uname := this.uname() - if !strings.Contains(uname, "Linux") { - return nil - } - - tempDir := strings.TrimRight(this.client.UserHome(), "/") + "/.edge-fluent-bit" - _, _, _ = this.client.Exec("mkdir -p " + shQuote(tempDir)) - defer func() { - _, _, _ = this.client.Exec("rm -rf " + shQuote(tempDir)) - }() - - if err := this.ensureFluentBitInstalled(tempDir); err != nil { - return err - } - - _, stderr, err := this.client.Exec("mkdir -p " + shQuote(fluentBitConfigDir) + " " + shQuote(fluentBitStorageDir)) - if err != nil { - return fmt.Errorf("prepare fluent-bit directories failed: %w, stderr: %s", err, stderr) - } - - parserContent, err := this.readLocalParsersContent() - if err != nil { - return err - } - - existingMeta, err := this.readManagedMeta() - if err != nil { - return err - } - - mergedRoles, err := mergeManagedRoles(existingMeta, role) - if err != nil { - return err - } - - desiredConfig, err := this.buildDesiredFluentBitConfig(mergedRoles) - if err != nil { - return err - } - - configChanged, err := this.applyManagedConfig(tempDir, desiredConfig, parserContent, existingMeta) - if err != nil { - return err - } - - binPath, err := this.lookupFluentBitBinPath() - if err != nil { - return err - } - - if err := this.ensureFluentBitService(tempDir, binPath, configChanged); err != nil { - return err - } - - return nil -} - -func (this *BaseInstaller) ensureFluentBitInstalled(tempDir string) error { - binPath, _ := this.lookupFluentBitBinPath() - if binPath != "" { - return nil - } - - platformKey, packageName, arch, err := this.detectRemotePlatformAndPackage() - if err != nil { - return fmt.Errorf("detect fluent-bit platform failed: %w", err) - } - - if err := this.installFluentBitFromLocalPackage(tempDir, arch, packageName); err != nil { - if errors.Is(err, errFluentBitLocalPackageNotFound) { - expectedPath := filepath.Join("deploy", "fluent-bit", fluentBitLocalPackagesRoot, "linux-"+arch, packageName) - return fmt.Errorf("install fluent-bit failed: local package missing for platform '%s', expected '%s'", platformKey, expectedPath) - } - return fmt.Errorf("install fluent-bit from local package failed: %w", err) - } - - binPath, err = this.lookupFluentBitBinPath() - if err != nil { - return err - } - if binPath == "" { - return errors.New("fluent-bit binary not found after local package install") - } - - _, stderr, err := this.client.Exec(binPath + " --version") - if err != nil { - return fmt.Errorf("verify fluent-bit version failed: %w, stderr: %s", err, stderr) - } - - return nil -} - -func (this *BaseInstaller) installFluentBitFromLocalPackage(tempDir string, arch string, packageName string) error { - packageDir := filepath.Join(Tea.Root, "deploy", "fluent-bit", fluentBitLocalPackagesRoot, "linux-"+arch) - localPackagePath := filepath.Join(packageDir, packageName) - if _, err := os.Stat(localPackagePath); err != nil { - if os.IsNotExist(err) { - return errFluentBitLocalPackageNotFound - } - return fmt.Errorf("check local package failed: %w", err) - } - - remotePackagePath := tempDir + "/" + filepath.Base(localPackagePath) - if err := this.client.Copy(localPackagePath, remotePackagePath, 0644); err != nil { - return fmt.Errorf("upload local package failed: %w", err) - } - - var installCmd string - lowerName := strings.ToLower(localPackagePath) - switch { - case strings.HasSuffix(lowerName, ".deb"): - installCmd = "dpkg -i " + shQuote(remotePackagePath) - case strings.HasSuffix(lowerName, ".rpm"): - installCmd = "rpm -Uvh --force " + shQuote(remotePackagePath) + " || rpm -ivh --force " + shQuote(remotePackagePath) - case strings.HasSuffix(lowerName, ".tar.gz") || strings.HasSuffix(lowerName, ".tgz"): - extractDir := tempDir + "/extract" - installCmd = "rm -rf " + shQuote(extractDir) + "; mkdir -p " + shQuote(extractDir) + "; tar -xzf " + shQuote(remotePackagePath) + " -C " + shQuote(extractDir) + "; " + - "bin=$(find " + shQuote(extractDir) + " -type f -name fluent-bit | head -n 1); " + - "if [ -z \"$bin\" ]; then exit 3; fi; " + - "mkdir -p /opt/fluent-bit/bin /usr/local/bin; " + - "install -m 0755 \"$bin\" /opt/fluent-bit/bin/fluent-bit; " + - "ln -sf /opt/fluent-bit/bin/fluent-bit /usr/local/bin/fluent-bit" - default: - return fmt.Errorf("unsupported local package format: %s", packageName) - } - - _, stderr, err := this.client.Exec(installCmd) - if err != nil { - return fmt.Errorf("install fluent-bit local package '%s' failed: %w, stderr: %s", filepath.Base(localPackagePath), err, stderr) - } - - return nil -} - -func (this *BaseInstaller) detectRemotePlatformAndPackage() (platformKey string, packageName string, arch string, err error) { - arch, err = this.detectRemoteLinuxArch() - if err != nil { - return "", "", "", err - } - - releaseData, stderr, err := this.client.Exec("cat /etc/os-release") - if err != nil { - return "", "", "", fmt.Errorf("read /etc/os-release failed: %w, stderr: %s", err, stderr) - } - if strings.TrimSpace(releaseData) == "" { - return "", "", "", errors.New("/etc/os-release is empty") - } - - releaseMap := parseOSRelease(releaseData) - id := strings.ToLower(strings.TrimSpace(releaseMap["ID"])) - versionID := strings.TrimSpace(releaseMap["VERSION_ID"]) - - var distro string - switch { - case id == "ubuntu" && strings.HasPrefix(versionID, "22.04"): - distro = "ubuntu22.04" - case id == "amzn" && strings.HasPrefix(versionID, "2023"): - distro = "amzn2023" - default: - return "", "", "", fmt.Errorf("unsupported linux platform id='%s' version='%s'", id, versionID) - } - - platformKey = distro + "-" + arch - packageName, ok := fluentBitPackageFileMapping[platformKey] - if !ok { - return "", "", "", fmt.Errorf("no local package mapping for platform '%s'", platformKey) - } - return platformKey, packageName, arch, nil -} - -func parseOSRelease(content string) map[string]string { - result := map[string]string{} - lines := strings.Split(content, "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") || !strings.Contains(line, "=") { - continue - } - parts := strings.SplitN(line, "=", 2) - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - value = strings.Trim(value, "\"") - result[key] = value - } - return result -} - -func (this *BaseInstaller) detectRemoteLinuxArch() (string, error) { - stdout, stderr, err := this.client.Exec("uname -m") - if err != nil { - return "", fmt.Errorf("detect remote arch failed: %w, stderr: %s", err, stderr) - } - - arch := strings.ToLower(strings.TrimSpace(stdout)) - switch arch { - case "x86_64", "amd64": - return "amd64", nil - case "aarch64", "arm64": - return "arm64", nil - default: - return arch, nil - } -} - -func (this *BaseInstaller) lookupFluentBitBinPath() (string, error) { - stdout, stderr, err := this.client.Exec("if command -v fluent-bit >/dev/null 2>&1; then command -v fluent-bit; elif [ -x " + fluentBitDefaultBinPath + " ]; then echo " + fluentBitDefaultBinPath + "; fi") - if err != nil { - return "", fmt.Errorf("lookup fluent-bit binary failed: %w, stderr: %s", err, stderr) - } - return strings.TrimSpace(stdout), nil -} - -func (this *BaseInstaller) readLocalParsersContent() (string, error) { - parsersPath := filepath.Join(Tea.Root, "deploy", "fluent-bit", "parsers.conf") - data, err := os.ReadFile(parsersPath) - if err != nil { - return "", fmt.Errorf("read local parsers config failed: %w", err) - } - return string(data), nil -} - -func (this *BaseInstaller) readManagedMeta() (*fluentBitManagedMeta, error) { - exists, err := this.remoteFileExists(fluentBitManagedMetaFile) - if err != nil { - return nil, err - } - if !exists { - return nil, nil - } - - content, stderr, err := this.client.Exec("cat " + shQuote(fluentBitManagedMetaFile)) - if err != nil { - return nil, fmt.Errorf("read fluent-bit managed metadata failed: %w, stderr: %s", err, stderr) - } - if strings.TrimSpace(content) == "" { - return nil, nil - } - - meta := &fluentBitManagedMeta{} - if err := json.Unmarshal([]byte(content), meta); err != nil { - return nil, fmt.Errorf("decode fluent-bit managed metadata failed: %w", err) - } - meta.Roles = normalizeRoles(meta.Roles) - return meta, nil -} - -func mergeManagedRoles(meta *fluentBitManagedMeta, role nodeconfigs.NodeRole) ([]string, error) { - roleName, err := mapNodeRole(role) - if err != nil { - return nil, err - } - - roleSet := map[string]struct{}{} - if meta != nil { - for _, r := range normalizeRoles(meta.Roles) { - roleSet[r] = struct{}{} - } - } - roleSet[roleName] = struct{}{} - - roles := make([]string, 0, len(roleSet)) - for r := range roleSet { - roles = append(roles, r) - } - sort.Strings(roles) - return roles, nil -} - -func mapNodeRole(role nodeconfigs.NodeRole) (string, error) { - switch role { - case nodeconfigs.NodeRoleNode: - return fluentBitRoleNode, nil - case nodeconfigs.NodeRoleDNS: - return fluentBitRoleDNS, nil - case nodeconfigs.NodeRoleHTTPDNS: - return fluentBitRoleHTTPDNS, nil - default: - return "", fmt.Errorf("unsupported fluent-bit role '%s'", role) - } -} - -func normalizeRoles(rawRoles []string) []string { - roleSet := map[string]struct{}{} - for _, role := range rawRoles { - role = strings.ToLower(strings.TrimSpace(role)) - if role != fluentBitRoleNode && role != fluentBitRoleDNS && role != fluentBitRoleHTTPDNS { - continue - } - roleSet[role] = struct{}{} - } - - roles := make([]string, 0, len(roleSet)) - for role := range roleSet { - roles = append(roles, role) - } - sort.Strings(roles) - return roles -} - -func hasRole(roles []string, role string) bool { - for _, one := range roles { - if one == role { - return true - } - } - return false -} - -func (this *BaseInstaller) buildDesiredFluentBitConfig(roles []string) (*fluentBitDesiredConfig, error) { - if len(roles) == 0 { - return nil, errors.New("fluent-bit roles should not be empty") - } - - ch, err := models.SharedSysSettingDAO.ReadClickHouseConfig(nil) - if err != nil { - return nil, fmt.Errorf("read clickhouse setting failed: %w", err) - } - if ch == nil { - ch = &systemconfigs.ClickHouseSetting{} - } - if strings.TrimSpace(ch.Host) == "" { - ch.Host = "127.0.0.1" - } - - ch.Scheme = strings.ToLower(strings.TrimSpace(ch.Scheme)) - if ch.Scheme == "" { - ch.Scheme = "https" - } - if ch.Scheme != "http" && ch.Scheme != "https" { - return nil, fmt.Errorf("unsupported clickhouse scheme '%s'", ch.Scheme) - } - - if ch.Port <= 0 { - if ch.Scheme == "https" { - ch.Port = 8443 - } else { - ch.Port = 8443 - } - } - if strings.TrimSpace(ch.Database) == "" { - ch.Database = "default" - } - if strings.TrimSpace(ch.User) == "" { - ch.User = "default" - } - // 当前平台策略:后台固定跳过 ClickHouse TLS 证书校验,不暴露 ServerName 配置。 - ch.TLSSkipVerify = true - ch.TLSServerName = "" - - httpPathPattern := fluentBitHTTPPathPattern - dnsPathPattern := fluentBitDNSPathPattern - httpdnsPathPattern := fluentBitHTTPDNSPathPattern - publicPolicyPath, err := this.readPublicAccessLogPolicyPath() - if err != nil { - return nil, err - } - policyDir := dirFromPolicyPath(publicPolicyPath) - if policyDir != "" { - pattern := strings.TrimRight(policyDir, "/") + "/*.log" - httpPathPattern = pattern - dnsPathPattern = pattern - httpdnsPathPattern = pattern - } - - return &fluentBitDesiredConfig{ - Roles: normalizeRoles(roles), - ClickHouse: ch, - HTTPPathPattern: httpPathPattern, - DNSPathPattern: dnsPathPattern, - HTTPDNSPathPattern: httpdnsPathPattern, - }, nil -} - -func (this *BaseInstaller) readPublicAccessLogPolicyPath() (string, error) { - policyId, err := models.SharedHTTPAccessLogPolicyDAO.FindCurrentPublicPolicyId(nil) - if err != nil { - return "", fmt.Errorf("find current public access log policy failed: %w", err) - } - if policyId <= 0 { - return "", nil - } - - policy, err := models.SharedHTTPAccessLogPolicyDAO.FindEnabledHTTPAccessLogPolicy(nil, policyId) - if err != nil { - return "", fmt.Errorf("read public access log policy failed: %w", err) - } - if policy == nil { - return "", nil - } - - return strings.TrimSpace(models.ParseHTTPAccessLogPolicyFilePath(policy)), nil -} - -func dirFromPolicyPath(policyPath string) string { - pathValue := strings.TrimSpace(policyPath) - if pathValue == "" { - return "" - } - pathValue = strings.ReplaceAll(pathValue, "\\", "/") - dir := slashpath.Dir(pathValue) - if dir == "." { - return "" - } - return strings.TrimRight(dir, "/") -} - -func (this *BaseInstaller) applyManagedConfig(tempDir string, desired *fluentBitDesiredConfig, parserContent string, existingMeta *fluentBitManagedMeta) (bool, error) { - mainExists, err := this.remoteFileExists(fluentBitMainConfigFile) - if err != nil { - return false, err - } - - if mainExists && existingMeta == nil { - containsMarker, err := this.remoteFileContains(fluentBitMainConfigFile, fluentBitManagedMarker) - if err != nil { - return false, err - } - if !containsMarker { - // Adopt unmanaged config by backing it up and replacing with managed config below. - } - } - - configContent, err := renderManagedConfig(desired) - if err != nil { - return false, err - } - envContent := renderManagedEnv(desired.ClickHouse) - metaContent, newMeta, err := renderManagedMeta(desired, configContent, parserContent, envContent) - if err != nil { - return false, err - } - - requiredFiles := []string{fluentBitMainConfigFile, fluentBitParsersFile, fluentBitManagedEnvFile, fluentBitManagedMetaFile} - if existingMeta != nil && existingMeta.Hash == newMeta.Hash { - allExists := true - for _, file := range requiredFiles { - exists, err := this.remoteFileExists(file) - if err != nil { - return false, err - } - if !exists { - allExists = false - break - } - } - if allExists { - return false, nil - } - } - - if mainExists { - backup := fluentBitMainConfigFile + ".bak." + strconv.FormatInt(time.Now().Unix(), 10) - _, stderr, err := this.client.Exec("cp -f " + shQuote(fluentBitMainConfigFile) + " " + shQuote(backup)) - if err != nil { - return false, fmt.Errorf("backup existing fluent-bit config failed: %w, stderr: %s", err, stderr) - } - } - - if err := this.writeRemoteFileByTemp(tempDir, fluentBitMainConfigFile, configContent, 0644); err != nil { - return false, err - } - if err := this.writeRemoteFileByTemp(tempDir, fluentBitParsersFile, parserContent, 0644); err != nil { - return false, err - } - if err := this.writeRemoteFileByTemp(tempDir, fluentBitManagedEnvFile, envContent, 0600); err != nil { - return false, err - } - if err := this.writeRemoteFileByTemp(tempDir, fluentBitManagedMetaFile, metaContent, 0644); err != nil { - return false, err - } - - return true, nil -} - -func renderManagedConfig(desired *fluentBitDesiredConfig) (string, error) { - if desired == nil || desired.ClickHouse == nil { - return "", errors.New("invalid fluent-bit desired config") - } - - scheme := strings.ToLower(strings.TrimSpace(desired.ClickHouse.Scheme)) - if scheme == "" { - scheme = "http" - } - if scheme != "http" && scheme != "https" { - return "", fmt.Errorf("unsupported clickhouse scheme '%s'", desired.ClickHouse.Scheme) - } - useTLS := scheme == "https" - - insertHTTP := url.QueryEscape(fmt.Sprintf("INSERT INTO %s.logs_ingest FORMAT JSONEachRow", desired.ClickHouse.Database)) - insertDNS := url.QueryEscape(fmt.Sprintf("INSERT INTO %s.dns_logs_ingest FORMAT JSONEachRow", desired.ClickHouse.Database)) - insertHTTPDNS := url.QueryEscape(fmt.Sprintf("INSERT INTO %s.httpdns_access_logs_ingest FORMAT JSONEachRow", desired.ClickHouse.Database)) - - lines := []string{ - "# " + fluentBitManagedMarker, - "[SERVICE]", - " Flush 1", - " Log_Level info", - " Parsers_File " + fluentBitParsersFile, - " storage.path " + fluentBitStorageDir, - " storage.sync normal", - " storage.checksum off", - " storage.backlog.mem_limit 512MB", - "", - } - - if hasRole(desired.Roles, fluentBitRoleNode) { - lines = append(lines, - "[INPUT]", - " Name tail", - " Path "+desired.HTTPPathPattern, - " Tag app.http.logs", - " Parser json", - " Refresh_Interval 2", - " Read_from_Head false", - " DB /var/lib/fluent-bit/http-logs.db", - " storage.type filesystem", - " Mem_Buf_Limit 256MB", - " Skip_Long_Lines On", - "", - ) - } - - if hasRole(desired.Roles, fluentBitRoleDNS) { - lines = append(lines, - "[INPUT]", - " Name tail", - " Path "+desired.DNSPathPattern, - " Tag app.dns.logs", - " Parser json", - " Refresh_Interval 2", - " Read_from_Head false", - " DB /var/lib/fluent-bit/dns-logs.db", - " storage.type filesystem", - " Mem_Buf_Limit 256MB", - " Skip_Long_Lines On", - "", - ) - } - - if hasRole(desired.Roles, fluentBitRoleHTTPDNS) { - lines = append(lines, - "[INPUT]", - " Name tail", - " Path "+desired.HTTPDNSPathPattern, - " Tag app.httpdns.logs", - " Parser json", - " Refresh_Interval 2", - " Read_from_Head false", - " DB /var/lib/fluent-bit/httpdns-logs.db", - " storage.type filesystem", - " Mem_Buf_Limit 256MB", - " Skip_Long_Lines On", - "", - ) - } - - if hasRole(desired.Roles, fluentBitRoleNode) { - lines = append(lines, - "[OUTPUT]", - " Name http", - " Match app.http.logs", - " Host "+desired.ClickHouse.Host, - " Port "+strconv.Itoa(desired.ClickHouse.Port), - " URI /?query="+insertHTTP, - " Format json_lines", - " http_user ${CH_USER}", - " http_passwd ${CH_PASSWORD}", - " json_date_key timestamp", - " json_date_format epoch", - " workers 2", - " net.keepalive On", - " Retry_Limit False", - ) - if useTLS { - lines = append(lines, " tls On") - if desired.ClickHouse.TLSSkipVerify { - lines = append(lines, " tls.verify Off") - } else { - lines = append(lines, " tls.verify On") - } - if strings.TrimSpace(desired.ClickHouse.TLSServerName) != "" { - lines = append(lines, " tls.vhost "+strings.TrimSpace(desired.ClickHouse.TLSServerName)) - } - } - lines = append(lines, "") - } - - if hasRole(desired.Roles, fluentBitRoleDNS) { - lines = append(lines, - "[OUTPUT]", - " Name http", - " Match app.dns.logs", - " Host "+desired.ClickHouse.Host, - " Port "+strconv.Itoa(desired.ClickHouse.Port), - " URI /?query="+insertDNS, - " Format json_lines", - " http_user ${CH_USER}", - " http_passwd ${CH_PASSWORD}", - " json_date_key timestamp", - " json_date_format epoch", - " workers 2", - " net.keepalive On", - " Retry_Limit False", - ) - if useTLS { - lines = append(lines, " tls On") - if desired.ClickHouse.TLSSkipVerify { - lines = append(lines, " tls.verify Off") - } else { - lines = append(lines, " tls.verify On") - } - if strings.TrimSpace(desired.ClickHouse.TLSServerName) != "" { - lines = append(lines, " tls.vhost "+strings.TrimSpace(desired.ClickHouse.TLSServerName)) - } - } - lines = append(lines, "") - } - - if hasRole(desired.Roles, fluentBitRoleHTTPDNS) { - lines = append(lines, - "[OUTPUT]", - " Name http", - " Match app.httpdns.logs", - " Host "+desired.ClickHouse.Host, - " Port "+strconv.Itoa(desired.ClickHouse.Port), - " URI /?query="+insertHTTPDNS, - " Format json_lines", - " http_user ${CH_USER}", - " http_passwd ${CH_PASSWORD}", - " json_date_key timestamp", - " json_date_format epoch", - " workers 2", - " net.keepalive On", - " Retry_Limit False", - ) - if useTLS { - lines = append(lines, " tls On") - if desired.ClickHouse.TLSSkipVerify { - lines = append(lines, " tls.verify Off") - } else { - lines = append(lines, " tls.verify On") - } - if strings.TrimSpace(desired.ClickHouse.TLSServerName) != "" { - lines = append(lines, " tls.vhost "+strings.TrimSpace(desired.ClickHouse.TLSServerName)) - } - } - lines = append(lines, "") - } - - return strings.Join(lines, "\n"), nil -} - -func renderManagedEnv(ch *systemconfigs.ClickHouseSetting) string { - user := "default" - password := "" - if ch != nil { - if strings.TrimSpace(ch.User) != "" { - user = strings.TrimSpace(ch.User) - } - password = ch.Password - } - return "CH_USER=" + strconv.Quote(user) + "\n" + - "CH_PASSWORD=" + strconv.Quote(password) + "\n" -} - -func renderManagedMeta(desired *fluentBitDesiredConfig, configContent string, parserContent string, envContent string) (string, *fluentBitManagedMeta, error) { - hashInput := configContent + "\n---\n" + parserContent + "\n---\n" + envContent + "\n---\n" + strings.Join(desired.Roles, ",") - hashBytes := sha256.Sum256([]byte(hashInput)) - hash := fmt.Sprintf("%x", hashBytes[:]) - - meta := &fluentBitManagedMeta{ - Roles: desired.Roles, - Hash: hash, - UpdatedAt: time.Now().Unix(), - SourceVersion: teaconst.Version, - } - data, err := json.MarshalIndent(meta, "", " ") - if err != nil { - return "", nil, fmt.Errorf("encode fluent-bit managed metadata failed: %w", err) - } - return string(data) + "\n", meta, nil -} - -func (this *BaseInstaller) copyLocalFileToRemote(tempDir string, localPath string, remotePath string, mode os.FileMode) error { - tempFile := tempDir + "/" + filepath.Base(remotePath) - if err := this.client.Copy(localPath, tempFile, mode); err != nil { - return fmt.Errorf("upload fluent-bit file '%s' failed: %w", localPath, err) - } - _, stderr, err := this.client.Exec("cp -f " + shQuote(tempFile) + " " + shQuote(remotePath) + " && chmod " + fmt.Sprintf("%04o", mode) + " " + shQuote(remotePath)) - if err != nil { - return fmt.Errorf("install remote fluent-bit file '%s' failed: %w, stderr: %s", remotePath, err, stderr) - } - return nil -} - -func (this *BaseInstaller) writeRemoteFileByTemp(tempDir string, remotePath string, content string, mode os.FileMode) error { - tempFile := tempDir + "/" + filepath.Base(remotePath) + ".tmp" - if _, err := this.client.WriteFile(tempFile, []byte(content)); err != nil { - return fmt.Errorf("write temp fluent-bit file '%s' failed: %w", tempFile, err) - } - - _, stderr, err := this.client.Exec("cp -f " + shQuote(tempFile) + " " + shQuote(remotePath) + " && chmod " + fmt.Sprintf("%04o", mode) + " " + shQuote(remotePath)) - if err != nil { - return fmt.Errorf("write managed fluent-bit file '%s' failed: %w, stderr: %s", remotePath, err, stderr) - } - return nil -} - -func (this *BaseInstaller) ensureFluentBitService(tempDir string, binPath string, configChanged bool) error { - _, _, _ = this.client.Exec("if command -v systemctl >/dev/null 2>&1 && [ ! -f /etc/systemd/system/" + fluentBitServiceName + ".service ] && [ ! -f /lib/systemd/system/" + fluentBitServiceName + ".service ]; then " + - "cat > /etc/systemd/system/" + fluentBitServiceName + ".service <<'EOF'\n" + - "[Unit]\n" + - "Description=Fluent Bit\n" + - "After=network.target\n" + - "\n" + - "[Service]\n" + - "ExecStart=" + binPath + " -c " + fluentBitMainConfigFile + "\n" + - "Restart=always\n" + - "RestartSec=5\n" + - "\n" + - "[Install]\n" + - "WantedBy=multi-user.target\n" + - "EOF\n" + - "fi") - - stdout, _, err := this.client.Exec("if command -v systemctl >/dev/null 2>&1; then echo 1; else echo 0; fi") - if err != nil { - return fmt.Errorf("check systemctl failed: %w", err) - } - - if strings.TrimSpace(stdout) == "1" { - dropInChanged, err := this.ensureServiceDropIn(tempDir, binPath) - if err != nil { - return err - } - - restartRequired := configChanged || dropInChanged - _, stderr, err := this.client.Exec("systemctl daemon-reload; systemctl enable " + fluentBitServiceName + " >/dev/null 2>&1 || true; " + - "if systemctl is-active " + fluentBitServiceName + " >/dev/null 2>&1; then " + - "if [ \"" + boolToString(restartRequired) + "\" = \"1\" ]; then systemctl restart " + fluentBitServiceName + "; fi; " + - "else systemctl start " + fluentBitServiceName + "; fi") - if err != nil { - return fmt.Errorf("ensure fluent-bit service failed: %w, stderr: %s", err, stderr) - } - return nil - } - - if configChanged { - _, _, _ = this.client.Exec("pkill -f \"fluent-bit.*fluent-bit.conf\" >/dev/null 2>&1 || true") - } - - _, _, runningErr := this.client.Exec("pgrep -f \"fluent-bit.*fluent-bit.conf\" >/dev/null 2>&1") - if runningErr != nil { - startCmd := "set -a; [ -f " + shQuote(fluentBitManagedEnvFile) + " ] && . " + shQuote(fluentBitManagedEnvFile) + "; set +a; " + - shQuote(binPath) + " -c " + shQuote(fluentBitMainConfigFile) + " >/dev/null 2>&1 &" - _, stderr, err := this.client.Exec(startCmd) - if err != nil { - return fmt.Errorf("start fluent-bit without systemd failed: %w, stderr: %s", err, stderr) - } - } - - return nil -} - -func (this *BaseInstaller) ensureServiceDropIn(tempDir string, binPath string) (bool, error) { - _, stderr, err := this.client.Exec("mkdir -p " + shQuote(fluentBitDropInDir)) - if err != nil { - return false, fmt.Errorf("prepare fluent-bit drop-in dir failed: %w, stderr: %s", err, stderr) - } - - content := "[Service]\n" + - "EnvironmentFile=-" + fluentBitManagedEnvFile + "\n" + - "ExecStart=\n" + - "ExecStart=" + binPath + " -c " + fluentBitMainConfigFile + "\n" - - existing, _, _ := this.client.Exec("if [ -f " + shQuote(fluentBitDropInFile) + " ]; then cat " + shQuote(fluentBitDropInFile) + "; fi") - if existing == content { - return false, nil - } - - if err := this.writeRemoteFileByTemp(tempDir, fluentBitDropInFile, content, 0644); err != nil { - return false, err - } - return true, nil -} - -func (this *BaseInstaller) remoteFileExists(path string) (bool, error) { - stdout, stderr, err := this.client.Exec("if [ -f " + shQuote(path) + " ]; then echo 1; else echo 0; fi") - if err != nil { - return false, fmt.Errorf("check remote file '%s' failed: %w, stderr: %s", path, err, stderr) - } - return strings.TrimSpace(stdout) == "1", nil -} - -func (this *BaseInstaller) remoteFileContains(path string, pattern string) (bool, error) { - stdout, stderr, err := this.client.Exec("if grep -F " + shQuote(pattern) + " " + shQuote(path) + " >/dev/null 2>&1; then echo 1; else echo 0; fi") - if err != nil { - return false, fmt.Errorf("check remote file content '%s' failed: %w, stderr: %s", path, err, stderr) - } - return strings.TrimSpace(stdout) == "1", nil -} - -func shQuote(value string) string { - if value == "" { - return "''" - } - return "'" + strings.ReplaceAll(value, "'", "'\"'\"'") + "'" -} - -func boolToString(v bool) string { - if v { - return "1" - } - return "0" -} diff --git a/EdgeAPI/internal/installers/installer_base.go b/EdgeAPI/internal/installers/installer_base.go index ca482b8..79f9f65 100644 --- a/EdgeAPI/internal/installers/installer_base.go +++ b/EdgeAPI/internal/installers/installer_base.go @@ -279,3 +279,27 @@ func (this *BaseInstaller) uname() (uname string) { return "x86_64 GNU/Linux" } + +func parseOSRelease(content string) map[string]string { + result := map[string]string{} + lines := strings.Split(content, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") || !strings.Contains(line, "=") { + continue + } + parts := strings.SplitN(line, "=", 2) + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + value = strings.Trim(value, "\"") + result[key] = value + } + return result +} + +func shQuote(s string) string { + if len(s) == 0 { + return "''" + } + return "'" + strings.ReplaceAll(s, "'", "'\"'\"'") + "'" +} diff --git a/EdgeAPI/internal/installers/installer_httpdns_node.go b/EdgeAPI/internal/installers/installer_httpdns_node.go index f93b600..638cab2 100644 --- a/EdgeAPI/internal/installers/installer_httpdns_node.go +++ b/EdgeAPI/internal/installers/installer_httpdns_node.go @@ -131,11 +131,6 @@ https.key: "${keyFile}"`) return fmt.Errorf("write '%s': %w", configFile, err) } - err = i.SetupFluentBit(nodeconfigs.NodeRoleHTTPDNS) - if err != nil { - installStatus.ErrorCode = "SETUP_FLUENT_BIT_FAILED" - return fmt.Errorf("setup fluent-bit failed: %w", err) - } startCmdPrefix := "cd " + shQuote(appDir+"/configs") + " && ../bin/edge-httpdns " diff --git a/EdgeAPI/internal/installers/installer_node.go b/EdgeAPI/internal/installers/installer_node.go index d0e6de3..e65829e 100644 --- a/EdgeAPI/internal/installers/installer_node.go +++ b/EdgeAPI/internal/installers/installer_node.go @@ -137,12 +137,6 @@ secret: "${nodeSecret}"`) } } - // 在线安装/更新 Fluent Bit(与边缘节点安装流程联动) - err = this.SetupFluentBit(nodeconfigs.NodeRoleNode) - if err != nil { - installStatus.ErrorCode = "SETUP_FLUENT_BIT_FAILED" - return fmt.Errorf("setup fluent-bit failed: %w", err) - } // 测试 _, stderr, err = this.client.Exec(dir + "/edge-node/bin/edge-node test") diff --git a/EdgeAPI/internal/installers/installer_ns_node_plus.go b/EdgeAPI/internal/installers/installer_ns_node_plus.go index cc23d56..39dadbb 100644 --- a/EdgeAPI/internal/installers/installer_ns_node_plus.go +++ b/EdgeAPI/internal/installers/installer_ns_node_plus.go @@ -139,12 +139,6 @@ secret: "${nodeSecret}"`) } } - // 在线安装/更新 Fluent Bit(与 DNS 节点安装流程联动) - err = this.SetupFluentBit(nodeconfigs.NodeRoleDNS) - if err != nil { - installStatus.ErrorCode = "SETUP_FLUENT_BIT_FAILED" - return fmt.Errorf("setup fluent-bit failed: %w", err) - } // 测试 _, stderr, err = this.client.Exec(dir + "/edge-dns/bin/edge-dns test") diff --git a/EdgeAPI/internal/nodes/api_node_services_hook_plus.go b/EdgeAPI/internal/nodes/api_node_services_hook_plus.go index 2738227..3b5c5f7 100644 --- a/EdgeAPI/internal/nodes/api_node_services_hook_plus.go +++ b/EdgeAPI/internal/nodes/api_node_services_hook_plus.go @@ -7,6 +7,7 @@ import ( "github.com/TeaOSLab/EdgeAPI/internal/rpc/services" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/accounts" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/anti-ddos" + httpdnsServices "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/httpdns" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/nameservers" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/posts" "github.com/TeaOSLab/EdgeAPI/internal/rpc/services/reporters" @@ -313,4 +314,9 @@ func APINodeServicesRegister(node *APINode, server *grpc.Server) { pb.RegisterPostCategoryServiceServer(server, instance) node.rest(instance) } + { + var instance = node.serviceInstance(&httpdnsServices.HTTPDNSBoardService{}).(*httpdnsServices.HTTPDNSBoardService) + pb.RegisterHTTPDNSBoardServiceServer(server, instance) + node.rest(instance) + } } diff --git a/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_board.go b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_board.go new file mode 100644 index 0000000..68ca624 --- /dev/null +++ b/EdgeAPI/internal/rpc/services/httpdns/service_httpdns_board.go @@ -0,0 +1,324 @@ +package httpdns + +import ( + "context" + "time" + + "github.com/TeaOSLab/EdgeAPI/internal/clickhouse" + "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/TeaOSLab/EdgeAPI/internal/rpc/services" + "github.com/TeaOSLab/EdgeAPI/internal/utils" + "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/dbs" + timeutil "github.com/iwind/TeaGo/utils/time" +) + +// HTTPDNSBoardService HTTPDNS 仪表盘服务 +type HTTPDNSBoardService struct { + services.BaseService +} + +// ComposeHTTPDNSBoard 组合看板数据 +func (this *HTTPDNSBoardService) ComposeHTTPDNSBoard(ctx context.Context, req *pb.ComposeHTTPDNSBoardRequest) (*pb.ComposeHTTPDNSBoardResponse, error) { + _, err := this.ValidateAdmin(ctx) + if err != nil { + return nil, err + } + + tx := this.NullTx() + result := &pb.ComposeHTTPDNSBoardResponse{} + + countApps, err := models.SharedHTTPDNSAppDAO.CountEnabledApps(tx, "") + if err != nil { + return nil, err + } + result.CountApps = countApps + + countDomains, err := models.SharedHTTPDNSDomainDAO.CountEnabledDomains(tx, 0) + if err != nil { + return nil, err + } + result.CountDomains = countDomains + + countClusters, err := models.SharedHTTPDNSClusterDAO.CountEnabledClusters(tx, "") + if err != nil { + return nil, err + } + result.CountClusters = countClusters + + allNodes, err := models.SharedHTTPDNSNodeDAO.ListEnabledNodes(tx, 0) + if err != nil { + return nil, err + } + result.CountNodes = int64(len(allNodes)) + + var countOffline int64 + for _, node := range allNodes { + if !node.IsActive { + countOffline++ + } + } + result.CountOfflineNodes = countOffline + + hourFrom := timeutil.Format("YmdH", time.Now().Add(-23*time.Hour)) + hourTo := timeutil.Format("YmdH") + dayFrom := timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14)) + dayTo := timeutil.Format("Ymd") + todayFrom := timeutil.Format("Ymd", time.Now().Add(-24*time.Hour)) + + store := clickhouse.NewHTTPDNSAccessLogsStore() + if store.Client().IsConfigured() { + err = this.composeTrafficAndRanksFromClickHouse(ctx, tx, store, result, hourFrom, hourTo, dayFrom, dayTo, todayFrom) + } + if err != nil || !store.Client().IsConfigured() { + err = this.composeTrafficAndRanksFromMySQL(tx, result, hourFrom, hourTo, dayFrom, dayTo, todayFrom) + if err != nil { + return nil, err + } + } + + err = this.fillNodeValues(tx, result) + if err != nil { + return nil, err + } + + return result, nil +} + +func (this *HTTPDNSBoardService) composeTrafficAndRanksFromClickHouse(ctx context.Context, tx *dbs.Tx, store *clickhouse.HTTPDNSAccessLogsStore, result *pb.ComposeHTTPDNSBoardResponse, hourFrom string, hourTo string, dayFrom string, dayTo string, todayFrom string) error { + hourlyStats, err := store.FindHourlyStats(ctx, hourFrom, hourTo) + if err != nil { + return err + } + hourlyMap := map[string]*clickhouse.HTTPDNSAccessLogHourlyStat{} + for _, stat := range hourlyStats { + hourlyMap[stat.Hour] = stat + } + hours, err := utils.RangeHours(hourFrom, hourTo) + if err != nil { + return err + } + for _, hour := range hours { + stat, ok := hourlyMap[hour] + if ok { + result.HourlyTrafficStats = append(result.HourlyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_HourlyTrafficStat{ + Hour: hour, + CountRequests: stat.CountRequests, + }) + } else { + result.HourlyTrafficStats = append(result.HourlyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_HourlyTrafficStat{Hour: hour}) + } + } + + dailyStats, err := store.FindDailyStats(ctx, dayFrom, dayTo) + if err != nil { + return err + } + dailyMap := map[string]*clickhouse.HTTPDNSAccessLogDailyStat{} + for _, stat := range dailyStats { + dailyMap[stat.Day] = stat + } + days, err := utils.RangeDays(dayFrom, dayTo) + if err != nil { + return err + } + for _, day := range days { + stat, ok := dailyMap[day] + if ok { + result.DailyTrafficStats = append(result.DailyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_DailyTrafficStat{ + Day: day, + CountRequests: stat.CountRequests, + }) + } else { + result.DailyTrafficStats = append(result.DailyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_DailyTrafficStat{Day: day}) + } + } + + topAppStats, err := store.ListTopApps(ctx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topAppStats { + appName := stat.AppName + if len(appName) == 0 { + appName = stat.AppId + } + result.TopAppStats = append(result.TopAppStats, &pb.ComposeHTTPDNSBoardResponse_TopAppStat{ + AppId: 0, + AppName: appName, + CountRequests: stat.CountRequests, + }) + } + + topDomainStats, err := store.ListTopDomains(ctx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topDomainStats { + result.TopDomainStats = append(result.TopDomainStats, &pb.ComposeHTTPDNSBoardResponse_TopDomainStat{ + DomainName: stat.Domain, + CountRequests: stat.CountRequests, + }) + } + + topNodeStats, err := store.ListTopNodes(ctx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topNodeStats { + nodeName := "" + node, nodeErr := models.SharedHTTPDNSNodeDAO.FindEnabledNode(tx, int64(stat.NodeId)) + if nodeErr == nil && node != nil { + nodeName = node.Name + } + if len(nodeName) == 0 { + continue + } + result.TopNodeStats = append(result.TopNodeStats, &pb.ComposeHTTPDNSBoardResponse_TopNodeStat{ + ClusterId: int64(stat.ClusterId), + NodeId: int64(stat.NodeId), + NodeName: nodeName, + CountRequests: stat.CountRequests, + }) + } + + return nil +} + +func (this *HTTPDNSBoardService) composeTrafficAndRanksFromMySQL(tx *dbs.Tx, result *pb.ComposeHTTPDNSBoardResponse, hourFrom string, hourTo string, dayFrom string, dayTo string, todayFrom string) error { + hourlyStats, err := models.SharedHTTPDNSAccessLogDAO.FindHourlyStats(tx, hourFrom, hourTo) + if err != nil { + return err + } + hourlyMap := map[string]*models.HTTPDNSAccessLogHourlyStat{} + for _, stat := range hourlyStats { + hourlyMap[stat.Hour] = stat + } + hours, err := utils.RangeHours(hourFrom, hourTo) + if err != nil { + return err + } + for _, hour := range hours { + stat, ok := hourlyMap[hour] + if ok { + result.HourlyTrafficStats = append(result.HourlyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_HourlyTrafficStat{ + Hour: hour, + CountRequests: stat.CountRequests, + }) + } else { + result.HourlyTrafficStats = append(result.HourlyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_HourlyTrafficStat{Hour: hour}) + } + } + + dailyStats, err := models.SharedHTTPDNSAccessLogDAO.FindDailyStats(tx, dayFrom, dayTo) + if err != nil { + return err + } + dailyMap := map[string]*models.HTTPDNSAccessLogDailyStat{} + for _, stat := range dailyStats { + dailyMap[stat.Day] = stat + } + days, err := utils.RangeDays(dayFrom, dayTo) + if err != nil { + return err + } + for _, day := range days { + stat, ok := dailyMap[day] + if ok { + result.DailyTrafficStats = append(result.DailyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_DailyTrafficStat{ + Day: day, + CountRequests: stat.CountRequests, + }) + } else { + result.DailyTrafficStats = append(result.DailyTrafficStats, &pb.ComposeHTTPDNSBoardResponse_DailyTrafficStat{Day: day}) + } + } + + topAppStats, err := models.SharedHTTPDNSAccessLogDAO.ListTopApps(tx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topAppStats { + appName := stat.AppName + if len(appName) == 0 { + appName = stat.AppId + } + result.TopAppStats = append(result.TopAppStats, &pb.ComposeHTTPDNSBoardResponse_TopAppStat{ + AppId: 0, + AppName: appName, + CountRequests: stat.CountRequests, + }) + } + + topDomainStats, err := models.SharedHTTPDNSAccessLogDAO.ListTopDomains(tx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topDomainStats { + result.TopDomainStats = append(result.TopDomainStats, &pb.ComposeHTTPDNSBoardResponse_TopDomainStat{ + DomainName: stat.Domain, + CountRequests: stat.CountRequests, + }) + } + + topNodeStats, err := models.SharedHTTPDNSAccessLogDAO.ListTopNodes(tx, todayFrom, dayTo, 10) + if err != nil { + return err + } + for _, stat := range topNodeStats { + nodeName := "" + node, nodeErr := models.SharedHTTPDNSNodeDAO.FindEnabledNode(tx, int64(stat.NodeId)) + if nodeErr == nil && node != nil { + nodeName = node.Name + } + if len(nodeName) == 0 { + continue + } + result.TopNodeStats = append(result.TopNodeStats, &pb.ComposeHTTPDNSBoardResponse_TopNodeStat{ + ClusterId: int64(stat.ClusterId), + NodeId: int64(stat.NodeId), + NodeName: nodeName, + CountRequests: stat.CountRequests, + }) + } + + return nil +} + +func (this *HTTPDNSBoardService) fillNodeValues(tx *dbs.Tx, result *pb.ComposeHTTPDNSBoardResponse) error { + cpuValues, err := models.SharedNodeValueDAO.ListValuesForHTTPDNSNodes(tx, nodeconfigs.NodeValueItemCPU, "usage", nodeconfigs.NodeValueRangeMinute) + if err != nil { + return err + } + for _, v := range cpuValues { + result.CpuNodeValues = append(result.CpuNodeValues, &pb.NodeValue{ + ValueJSON: v.Value, + CreatedAt: int64(v.CreatedAt), + }) + } + + memoryValues, err := models.SharedNodeValueDAO.ListValuesForHTTPDNSNodes(tx, nodeconfigs.NodeValueItemMemory, "usage", nodeconfigs.NodeValueRangeMinute) + if err != nil { + return err + } + for _, v := range memoryValues { + result.MemoryNodeValues = append(result.MemoryNodeValues, &pb.NodeValue{ + ValueJSON: v.Value, + CreatedAt: int64(v.CreatedAt), + }) + } + + loadValues, err := models.SharedNodeValueDAO.ListValuesForHTTPDNSNodes(tx, nodeconfigs.NodeValueItemLoad, "load1m", nodeconfigs.NodeValueRangeMinute) + if err != nil { + return err + } + for _, v := range loadValues { + result.LoadNodeValues = append(result.LoadNodeValues, &pb.NodeValue{ + ValueJSON: v.Value, + CreatedAt: int64(v.CreatedAt), + }) + } + + return nil +} diff --git a/EdgeAPI/internal/rpc/services/service_node_value.go b/EdgeAPI/internal/rpc/services/service_node_value.go index a1ec90d..0484e7a 100644 --- a/EdgeAPI/internal/rpc/services/service_node_value.go +++ b/EdgeAPI/internal/rpc/services/service_node_value.go @@ -17,7 +17,7 @@ type NodeValueService struct { // CreateNodeValue 记录数据 func (this *NodeValueService) CreateNodeValue(ctx context.Context, req *pb.CreateNodeValueRequest) (*pb.RPCSuccess, error) { - role, nodeId, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS, rpcutils.UserTypeUser) + role, nodeId, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeNode, rpcutils.UserTypeDNS, rpcutils.UserTypeUser, rpcutils.UserTypeHTTPDNS) if err != nil { return nil, err } @@ -30,6 +30,8 @@ func (this *NodeValueService) CreateNodeValue(ctx context.Context, req *pb.Creat clusterId, err = models.SharedNodeDAO.FindNodeClusterId(tx, nodeId) case rpcutils.UserTypeDNS: clusterId, err = models.SharedNSNodeDAO.FindNodeClusterId(tx, nodeId) + case rpcutils.UserTypeHTTPDNS: + clusterId, err = models.SharedHTTPDNSNodeDAO.FindNodeClusterId(tx, nodeId) case rpcutils.UserTypeUser: } if err != nil { diff --git a/EdgeAdmin/build/build.sh b/EdgeAdmin/build/build.sh index e3eb1ac..d699c4c 100644 --- a/EdgeAdmin/build/build.sh +++ b/EdgeAdmin/build/build.sh @@ -97,12 +97,10 @@ function build() { # create dir & copy files echo "copying ..." - if [ ! -d "$DIST" ]; then - mkdir "$DIST" - mkdir "$DIST"/bin - mkdir "$DIST"/configs - mkdir "$DIST"/logs - fi + rm -rf "$DIST" + mkdir -p "$DIST"/bin + mkdir -p "$DIST"/configs + mkdir -p "$DIST"/logs cp -R "$ROOT"/../web "$DIST"/ rm -f "$DIST"/web/tmp/* @@ -135,30 +133,6 @@ function build() { rm -f "$(basename "$EDGE_API_ZIP_FILE")" # ensure edge-api package always contains fluent-bit runtime assets/packages - FLUENT_ROOT="$ROOT/../../deploy/fluent-bit" - FLUENT_DIST="$DIST/edge-api/deploy/fluent-bit" - if [ -d "$FLUENT_ROOT" ]; then - verify_fluent_bit_package_matrix "$FLUENT_ROOT" "$ARCH" || exit 1 - rm -rf "$FLUENT_DIST" - mkdir -p "$FLUENT_DIST" - - FLUENT_FILES=( - "parsers.conf" - ) - for file in "${FLUENT_FILES[@]}"; do - if [ -f "$FLUENT_ROOT/$file" ]; then - cp "$FLUENT_ROOT/$file" "$FLUENT_DIST/" - fi - done - - if [ -d "$FLUENT_ROOT/packages" ]; then - cp -R "$FLUENT_ROOT/packages" "$FLUENT_DIST/" - fi - - rm -f "$FLUENT_DIST/.gitignore" - rm -f "$FLUENT_DIST"/logs.db* - rm -rf "$FLUENT_DIST/storage" - fi # 鍒犻櫎 MaxMind 鏁版嵁搴撴枃浠讹紙浣跨敤宓屽叆鐨勬暟鎹簱锛屼笉闇€瑕佸閮ㄦ枃浠讹級 find . -name "*.mmdb" -type f -delete @@ -220,39 +194,6 @@ function build() { echo "[done]" } -function verify_fluent_bit_package_matrix() { - FLUENT_ROOT=$1 - ARCH=$2 - REQUIRED_FILES=() - if [ "$ARCH" = "amd64" ]; then - REQUIRED_FILES=( - "packages/linux-amd64/fluent-bit_4.2.2_amd64.deb" - "packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm" - ) - elif [ "$ARCH" = "arm64" ]; then - REQUIRED_FILES=( - "packages/linux-arm64/fluent-bit_4.2.2_arm64.deb" - "packages/linux-arm64/fluent-bit-4.2.2-1.aarch64.rpm" - ) - else - echo "[error] unsupported arch for fluent-bit package validation: $ARCH" - return 1 - fi - - MISSING=0 - for FILE in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$FLUENT_ROOT/$FILE" ]; then - echo "[error] fluent-bit matrix package missing: $FLUENT_ROOT/$FILE" - MISSING=1 - fi - done - - if [ "$MISSING" -ne 0 ]; then - return 1 - fi - return 0 -} - function lookup-version() { FILE=$1 VERSION_DATA=$(cat "$FILE") diff --git a/EdgeAdmin/internal/const/const.go b/EdgeAdmin/internal/const/const.go index 55a74ae..6eabbb7 100644 --- a/EdgeAdmin/internal/const/const.go +++ b/EdgeAdmin/internal/const/const.go @@ -1,9 +1,9 @@ package teaconst const ( - Version = "1.4.9" //1.3.9 + Version = "1.5.0" //1.3.9 - APINodeVersion = "1.4.9" //1.3.9 + APINodeVersion = "1.5.0" //1.3.9 ProductName = "Edge Admin" ProcessName = "edge-admin" diff --git a/EdgeAdmin/internal/rpc/rpc_client_plus.go b/EdgeAdmin/internal/rpc/rpc_client_plus.go index e391146..6eab88e 100644 --- a/EdgeAdmin/internal/rpc/rpc_client_plus.go +++ b/EdgeAdmin/internal/rpc/rpc_client_plus.go @@ -248,3 +248,7 @@ func (this *RPCClient) PostCategoryRPC() pb.PostCategoryServiceClient { func (this *RPCClient) PostRPC() pb.PostServiceClient { return pb.NewPostServiceClient(this.pickConn()) } + +func (this *RPCClient) HTTPDNSBoardRPC() pb.HTTPDNSBoardServiceClient { + return pb.NewHTTPDNSBoardServiceClient(this.pickConn()) +} diff --git a/EdgeAdmin/internal/web/actions/default/clusters/cluster/init_plus.go b/EdgeAdmin/internal/web/actions/default/clusters/cluster/init_plus.go index c4b8851..3305849 100644 --- a/EdgeAdmin/internal/web/actions/default/clusters/cluster/init_plus.go +++ b/EdgeAdmin/internal/web/actions/default/clusters/cluster/init_plus.go @@ -11,7 +11,6 @@ import ( nodethresholds "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/settings/thresholds" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/cc" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/http3" - networksecurity "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/network-security" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/pages" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/thresholds" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/uam" @@ -53,7 +52,6 @@ func init() { GetPost("/thresholds", new(thresholds.IndexAction)). // - GetPost("/network-security", new(networksecurity.IndexAction)). // 节点设置相关 Prefix("/clusters/cluster/node/settings"). diff --git a/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/network-security/index.go b/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/network-security/index.go deleted file mode 100644 index f620d43..0000000 --- a/EdgeAdmin/internal/web/actions/default/clusters/cluster/settings/network-security/index.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus - -package networksecurity - -import ( - "encoding/json" - "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" - "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" - "github.com/iwind/TeaGo/actions" -) - -type IndexAction struct { - actionutils.ParentAction -} - -func (this *IndexAction) Init() { - this.Nav("", "setting", "index") - this.SecondMenu("networkSecurity") -} - -func (this *IndexAction) RunGet(params struct { - ClusterId int64 -}) { - policyResp, err := this.RPC().NodeClusterRPC().FindNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.FindNodeClusterNetworkSecurityPolicyRequest{ - NodeClusterId: params.ClusterId, - }) - if err != nil { - this.ErrorPage(err) - return - } - - var policy = nodeconfigs.NewNetworkSecurityPolicy() - if len(policyResp.NetworkSecurityPolicyJSON) > 0 { - err = json.Unmarshal(policyResp.NetworkSecurityPolicyJSON, policy) - if err != nil { - this.ErrorPage(err) - return - } - } - this.Data["policy"] = policy - - this.Show() -} - -func (this *IndexAction) RunPost(params struct { - ClusterId int64 - Status string - - Must *actions.Must - CSRF *actionutils.CSRF -}) { - policyResp, err := this.RPC().NodeClusterRPC().FindNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.FindNodeClusterNetworkSecurityPolicyRequest{ - NodeClusterId: params.ClusterId, - }) - if err != nil { - this.ErrorPage(err) - return - } - - var policy = nodeconfigs.NewNetworkSecurityPolicy() - if len(policyResp.NetworkSecurityPolicyJSON) > 0 { - err = json.Unmarshal(policyResp.NetworkSecurityPolicyJSON, policy) - if err != nil { - this.ErrorPage(err) - return - } - } - - policy.Status = params.Status - - err = policy.Init() - if err != nil { - this.Fail("配置校验失败:" + err.Error()) - return - } - - policyJSON, err := json.Marshal(policy) - if err != nil { - this.ErrorPage(err) - return - } - - _, err = this.RPC().NodeClusterRPC().UpdateNodeClusterNetworkSecurityPolicy(this.AdminContext(), &pb.UpdateNodeClusterNetworkSecurityPolicyRequest{ - NodeClusterId: params.ClusterId, - NetworkSecurityPolicyJSON: policyJSON, - }) - if err != nil { - this.ErrorPage(err) - return - } - - this.Success() -} diff --git a/EdgeAdmin/internal/web/actions/default/clusters/clusterutils/cluster_helper_ext_plus.go b/EdgeAdmin/internal/web/actions/default/clusters/clusterutils/cluster_helper_ext_plus.go index 9f3b68b..d8c0102 100644 --- a/EdgeAdmin/internal/web/actions/default/clusters/clusterutils/cluster_helper_ext_plus.go +++ b/EdgeAdmin/internal/web/actions/default/clusters/clusterutils/cluster_helper_ext_plus.go @@ -44,17 +44,10 @@ func (this *ClusterHelper) filterMenuItems1(items []maps.Map, info *pb.FindEnabl func (this *ClusterHelper) filterMenuItems2(items []maps.Map, info *pb.FindEnabledNodeClusterConfigInfoResponse, clusterIdString string, selectedItem string, actionPtr actions.ActionWrapper) []maps.Map { if teaconst.IsPlus { - items = append(items, maps.Map{ - "name": this.Lang(actionPtr, codes.NodeClusterMenu_SettingSecurityPolicy), - "url": "/clusters/cluster/settings/network-security?clusterId=" + clusterIdString, - "isActive": selectedItem == "networkSecurity", - "isOn": info != nil && info.HasNetworkSecurityPolicy, // TODO 将来 加入 info.HasDDoSProtection - }) - - items = append(items, maps.Map{ - "name": "-", - }) if plusutils.CheckComponent(plusutils.ComponentCodeScheduling) { + items = append(items, maps.Map{ + "name": "-", + }) items = append(items, maps.Map{ "name": this.Lang(actionPtr, codes.NodeClusterMenu_SettingSchedule), "url": "/clusters/cluster/settings/schedule?clusterId=" + clusterIdString, @@ -89,14 +82,12 @@ func (this *ClusterHelper) filterMenuItems2(items []maps.Map, info *pb.FindEnabl "isOn": info != nil && info.HasSystemServices, }) - { - items = append(items, maps.Map{ - "name": this.Lang(actionPtr, codes.NodeClusterMenu_SettingTOA), - "url": "/clusters/cluster/settings/toa?clusterId=" + clusterIdString, - "isActive": selectedItem == "toa", - "isOn": info != nil && info.IsTOAEnabled, - }) - } + items = append(items, maps.Map{ + "name": this.Lang(actionPtr, codes.NodeClusterMenu_SettingTOA), + "url": "/clusters/cluster/settings/toa?clusterId=" + clusterIdString, + "isActive": selectedItem == "toa", + "isOn": info != nil && info.IsTOAEnabled, + }) } return items } diff --git a/EdgeAdmin/internal/web/actions/default/dashboard/boards/httpdns.go b/EdgeAdmin/internal/web/actions/default/dashboard/boards/httpdns.go new file mode 100644 index 0000000..3f6bbbf --- /dev/null +++ b/EdgeAdmin/internal/web/actions/default/dashboard/boards/httpdns.go @@ -0,0 +1,127 @@ +// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. +//go:build plus + +package boards + +import ( + teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dashboard/boards/boardutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) + +type HTTPDNSAction struct { + actionutils.ParentAction +} + +func (this *HTTPDNSAction) Init() { + this.Nav("", "", "httpdns") + this.ViewDir("@default") + this.View("dashboard/boards/httpdns") +} + +func (this *HTTPDNSAction) RunGet(params struct{}) { + if !teaconst.IsPlus { + this.RedirectURL("/dashboard") + return + } + + err := boardutils.InitBoard(this.Parent()) + if err != nil { + this.ErrorPage(err) + return + } + + this.Data["board"] = maps.Map{ + "countApps": 0, + "countDomains": 0, + "countClusters": 0, + "countNodes": 0, + "countOfflineNodes": 0, + } + + this.Show() +} + +func (this *HTTPDNSAction) RunPost(params struct{}) { + resp, err := this.RPC().HTTPDNSBoardRPC().ComposeHTTPDNSBoard(this.AdminContext(), &pb.ComposeHTTPDNSBoardRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + this.Data["board"] = maps.Map{ + "countApps": resp.CountApps, + "countDomains": resp.CountDomains, + "countClusters": resp.CountClusters, + "countNodes": resp.CountNodes, + "countOfflineNodes": resp.CountOfflineNodes, + } + + { + var statMaps = []maps.Map{} + for _, stat := range resp.HourlyTrafficStats { + statMaps = append(statMaps, maps.Map{ + "day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日", + "hour": stat.Hour[8:], + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["hourlyStats"] = statMaps + } + + { + var statMaps = []maps.Map{} + for _, stat := range resp.DailyTrafficStats { + statMaps = append(statMaps, maps.Map{ + "day": stat.Day[4:6] + "月" + stat.Day[6:] + "日", + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["dailyStats"] = statMaps + } + + { + var statMaps = []maps.Map{} + for _, stat := range resp.TopAppStats { + statMaps = append(statMaps, maps.Map{ + "appId": stat.AppId, + "appName": stat.AppName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topAppStats"] = statMaps + } + + { + var statMaps = []maps.Map{} + for _, stat := range resp.TopDomainStats { + statMaps = append(statMaps, maps.Map{ + "domainId": stat.DomainId, + "domainName": stat.DomainName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topDomainStats"] = statMaps + } + + { + var statMaps = []maps.Map{} + for _, stat := range resp.TopNodeStats { + statMaps = append(statMaps, maps.Map{ + "clusterId": stat.ClusterId, + "nodeId": stat.NodeId, + "nodeName": stat.NodeName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topNodeStats"] = statMaps + } + + this.Success() +} diff --git a/EdgeAdmin/internal/web/actions/default/dashboard/boards/index.go b/EdgeAdmin/internal/web/actions/default/dashboard/boards/index.go index 2cf3087..e3e43f4 100644 --- a/EdgeAdmin/internal/web/actions/default/dashboard/boards/index.go +++ b/EdgeAdmin/internal/web/actions/default/dashboard/boards/index.go @@ -19,6 +19,7 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/types" + stringutil "github.com/iwind/TeaGo/utils/string" timeutil "github.com/iwind/TeaGo/utils/time" "regexp" "time" @@ -409,5 +410,55 @@ func (this *IndexAction) RunPost(params struct { } this.Data["countWeakAdmins"] = countWeakAdminsResp.Count + upgradeConfig, err := configloaders.LoadUpgradeConfig() + if err != nil { + this.ErrorPage(err) + return + } + this.Data["autoUpgrade"] = upgradeConfig.AutoUpgrade + + httpdnsNodeUpgradeInfo, err := this.composeHTTPDNSNodeUpgradeInfo() + if err != nil { + this.ErrorPage(err) + return + } + this.Data["httpdnsNodeUpgradeInfo"] = httpdnsNodeUpgradeInfo + this.Success() } + +func (this *IndexAction) composeHTTPDNSNodeUpgradeInfo() (maps.Map, error) { + clustersResp, err := this.RPC().HTTPDNSClusterRPC().ListHTTPDNSClusters(this.AdminContext(), &pb.ListHTTPDNSClustersRequest{ + Offset: 0, + Size: 10000, + }) + if err != nil { + return nil, err + } + + count := 0 + version := "" + for _, cluster := range clustersResp.Clusters { + resp, err := this.RPC().HTTPDNSNodeRPC().FindAllUpgradeHTTPDNSNodesWithClusterId(this.AdminContext(), &pb.FindAllUpgradeHTTPDNSNodesWithClusterIdRequest{ + ClusterId: cluster.Id, + }) + if err != nil { + return nil, err + } + + count += len(resp.Nodes) + for _, nodeUpgrade := range resp.Nodes { + if len(nodeUpgrade.NewVersion) == 0 { + continue + } + if len(version) == 0 || stringutil.VersionCompare(version, nodeUpgrade.NewVersion) < 0 { + version = nodeUpgrade.NewVersion + } + } + } + + return maps.Map{ + "count": count, + "version": version, + }, nil +} diff --git a/EdgeAdmin/internal/web/actions/default/dashboard/index.go b/EdgeAdmin/internal/web/actions/default/dashboard/index.go index 7ac18e6..0737798 100644 --- a/EdgeAdmin/internal/web/actions/default/dashboard/index.go +++ b/EdgeAdmin/internal/web/actions/default/dashboard/index.go @@ -245,5 +245,12 @@ func (this *IndexAction) RunPost(params struct{}) { } this.Data["countWeakAdmins"] = countWeakAdminsResp.Count + upgradeConfig, err := configloaders.LoadUpgradeConfig() + if err != nil { + this.ErrorPage(err) + return + } + this.Data["autoUpgrade"] = upgradeConfig.AutoUpgrade + this.Success() } diff --git a/EdgeAdmin/internal/web/actions/default/dashboard/init_plus.go b/EdgeAdmin/internal/web/actions/default/dashboard/init_plus.go index 67aff3f..f95cd10 100644 --- a/EdgeAdmin/internal/web/actions/default/dashboard/init_plus.go +++ b/EdgeAdmin/internal/web/actions/default/dashboard/init_plus.go @@ -22,6 +22,7 @@ func init() { Get("/waf", new(boards.WafAction)). Post("/wafLogs", new(boards.WafLogsAction)). GetPost("/dns", new(boards.DnsAction)). + GetPost("/httpdns", new(boards.HTTPDNSAction)). Get("/user", new(boards.UserAction)). Get("/events", new(boards.EventsAction)). Post("/readLogs", new(boards.ReadLogsAction)). diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/index.go b/EdgeAdmin/internal/web/actions/default/httpdns/index.go index df37453..404d601 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/index.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/index.go @@ -1,11 +1,110 @@ package httpdns -import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" +) type IndexAction struct { actionutils.ParentAction } -func (this *IndexAction) RunGet(params struct{}) { - this.RedirectURL("/httpdns/clusters") +func (this *IndexAction) Init() { + this.Nav("", "", "httpdns") +} + +func (this *IndexAction) RunGet(params struct{}) { + this.Data["board"] = maps.Map{ + "countApps": 0, + "countDomains": 0, + "countClusters": 0, + "countNodes": 0, + "countOfflineNodes": 0, + } + + this.Show() +} + +func (this *IndexAction) RunPost(params struct{}) { + resp, err := this.RPC().HTTPDNSBoardRPC().ComposeHTTPDNSBoard(this.AdminContext(), &pb.ComposeHTTPDNSBoardRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Data["board"] = maps.Map{ + "countApps": resp.CountApps, + "countDomains": resp.CountDomains, + "countClusters": resp.CountClusters, + "countNodes": resp.CountNodes, + "countOfflineNodes": resp.CountOfflineNodes, + } + + { + statMaps := []maps.Map{} + for _, stat := range resp.HourlyTrafficStats { + statMaps = append(statMaps, maps.Map{ + "day": stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日", + "hour": stat.Hour[8:], + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["hourlyStats"] = statMaps + } + + { + statMaps := []maps.Map{} + for _, stat := range resp.DailyTrafficStats { + statMaps = append(statMaps, maps.Map{ + "day": stat.Day[4:6] + "月" + stat.Day[6:] + "日", + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["dailyStats"] = statMaps + } + + { + statMaps := []maps.Map{} + for _, stat := range resp.TopAppStats { + statMaps = append(statMaps, maps.Map{ + "appId": stat.AppId, + "appName": stat.AppName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topAppStats"] = statMaps + } + + { + statMaps := []maps.Map{} + for _, stat := range resp.TopDomainStats { + statMaps = append(statMaps, maps.Map{ + "domainId": stat.DomainId, + "domainName": stat.DomainName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topDomainStats"] = statMaps + } + + { + statMaps := []maps.Map{} + for _, stat := range resp.TopNodeStats { + statMaps = append(statMaps, maps.Map{ + "clusterId": stat.ClusterId, + "nodeId": stat.NodeId, + "nodeName": stat.NodeName, + "countRequests": stat.CountRequests, + "bytes": stat.Bytes, + }) + } + this.Data["topNodeStats"] = statMaps + } + + this.Success() } diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/init.go b/EdgeAdmin/internal/web/actions/default/httpdns/init.go index 78dc22b..ddede79 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/init.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/init.go @@ -11,9 +11,9 @@ func init() { server. Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeHttpDNS)). Data("teaMenu", "httpdns"). - Data("teaSubMenu", "cluster"). + Data("teaSubMenu", "board"). Prefix("/httpdns"). - Get("", new(IndexAction)). + GetPost("", new(IndexAction)). GetPost("/addPortPopup", new(AddPortPopupAction)). EndAll() }) diff --git a/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/createPopup_plus.go b/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/createPopup_plus.go index cec6a2a..a33acdc 100644 --- a/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/createPopup_plus.go +++ b/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/createPopup_plus.go @@ -25,7 +25,7 @@ func (this *CreatePopupAction) Init() { } func (this *CreatePopupAction) RunGet(params struct{}) { - var authMethods = []*serverconfigs.HTTPAuthTypeDefinition{} + authMethods := []*serverconfigs.HTTPAuthTypeDefinition{} for _, method := range serverconfigs.FindAllHTTPAuthTypes(teaconst.Role) { if !method.IsPlus || (method.IsPlus && teaconst.IsPlus) { authMethods = append(authMethods, method) @@ -59,6 +59,10 @@ func (this *CreatePopupAction) RunPost(params struct { TypeDTimestampParamName string TypeDLife int + // TypeE + TypeESecret string + TypeELife int + // BasicAuth HttpAuthBasicAuthUsersJSON []byte BasicAuthRealm string @@ -81,29 +85,25 @@ func (this *CreatePopupAction) RunPost(params struct { Field("type", params.Type). Require("请输入鉴权类型") - var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true} + ref := &serverconfigs.HTTPAuthPolicyRef{IsOn: true} var method serverconfigs.HTTPAuthMethodInterface - // 扩展名 - var exts = utils.NewStringsStream(params.Exts). + exts := utils.NewStringsStream(params.Exts). Map(strings.TrimSpace, strings.ToLower). Filter(utils.FilterNotEmpty). Map(utils.MapAddPrefixFunc(".")). Unique(). Result() - // 域名 - var domains = []string{} + domains := []string{} if len(params.DomainsJSON) > 0 { - var rawDomains = []string{} + rawDomains := []string{} err := json.Unmarshal(params.DomainsJSON, &rawDomains) if err != nil { this.ErrorPage(err) return } - // TODO 如果用户填写了一个网址,应该分析域名并填入 - domains = utils.NewStringsStream(rawDomains). Map(strings.TrimSpace, strings.ToLower). Filter(utils.FilterNotEmpty). @@ -116,11 +116,11 @@ func (this *CreatePopupAction) RunPost(params struct { params.Must. Field("typeASecret", params.TypeASecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字"). Field("typeASignParamName", params.TypeASignParamName). Require("请输入签名参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字、下划线") + Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字和下划线") if params.TypeALife < 0 { params.TypeALife = 0 @@ -135,8 +135,8 @@ func (this *CreatePopupAction) RunPost(params struct { params.Must. Field("typeBSecret", params.TypeBSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字") + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") method = &serverconfigs.HTTPAuthTypeBMethod{ Secret: params.TypeBSecret, @@ -146,8 +146,8 @@ func (this *CreatePopupAction) RunPost(params struct { params.Must. Field("typeCSecret", params.TypeCSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字") + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") method = &serverconfigs.HTTPAuthTypeCMethod{ Secret: params.TypeCSecret, @@ -157,14 +157,14 @@ func (this *CreatePopupAction) RunPost(params struct { params.Must. Field("typeDSecret", params.TypeDSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字"). Field("typeDSignParamName", params.TypeDSignParamName). Require("请输入签名参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字、下划线"). + Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字和下划线"). Field("typeDTimestampParamName", params.TypeDTimestampParamName). - Require("请输入时间戳参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "时间戳参数中只能包含字母、数字、下划线") + Require("请输入时间参数"). + Match(`^[a-zA-Z0-9_]{1,40}$`, "时间参数中只能包含字母、数字和下划线") method = &serverconfigs.HTTPAuthTypeDMethod{ Secret: params.TypeDSecret, @@ -172,15 +172,26 @@ func (this *CreatePopupAction) RunPost(params struct { TimestampParamName: params.TypeDTimestampParamName, Life: params.TypeDLife, } + case serverconfigs.HTTPAuthTypeTypeE: + params.Must. + Field("typeESecret", params.TypeESecret). + Require("请输入鉴权密钥"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") + + method = &serverconfigs.HTTPAuthTypeEMethod{ + Secret: params.TypeESecret, + Life: params.TypeELife, + } case serverconfigs.HTTPAuthTypeBasicAuth: - var users = []*serverconfigs.HTTPAuthBasicMethodUser{} + users := []*serverconfigs.HTTPAuthBasicMethodUser{} err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users) if err != nil { this.ErrorPage(err) return } if len(users) == 0 { - this.Fail("请添加至少一个用户") + this.Fail("请至少添加一个用户") } method = &serverconfigs.HTTPAuthBasicMethod{ Users: users, @@ -188,8 +199,9 @@ func (this *CreatePopupAction) RunPost(params struct { Charset: params.BasicAuthCharset, } case serverconfigs.HTTPAuthTypeSubRequest: - params.Must.Field("subRequestURL", params.SubRequestURL). - Require("请输入子请求URL") + params.Must. + Field("subRequestURL", params.SubRequestURL). + Require("请输入子请求 URL") if params.SubRequestFollowRequest { params.SubRequestMethod = "" } @@ -198,7 +210,7 @@ func (this *CreatePopupAction) RunPost(params struct { Method: params.SubRequestMethod, } default: - this.Fail("不支持的鉴权类型'" + params.Type + "'") + this.Fail("不支持的鉴权类型 '" + params.Type + "'") } if method == nil { @@ -214,7 +226,7 @@ func (this *CreatePopupAction) RunPost(params struct { return } - var paramsMap = maps.Map{} + paramsMap := maps.Map{} err = json.Unmarshal(methodJSON, ¶msMap) if err != nil { this.ErrorPage(err) @@ -231,6 +243,7 @@ func (this *CreatePopupAction) RunPost(params struct { return } defer this.CreateLogInfo(codes.HTTPAuthPolicy_LogCreateHTTPAuthPolicy, createResp.HttpAuthPolicyId) + ref.AuthPolicyId = createResp.HttpAuthPolicyId ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{ Id: createResp.HttpAuthPolicyId, diff --git a/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/updatePopup_plus.go b/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/updatePopup_plus.go index 4259e76..812519d 100644 --- a/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/updatePopup_plus.go +++ b/EdgeAdmin/internal/web/actions/default/servers/server/settings/access/updatePopup_plus.go @@ -27,7 +27,7 @@ func (this *UpdatePopupAction) Init() { func (this *UpdatePopupAction) RunGet(params struct { PolicyId int64 }) { - var authMethods = []*serverconfigs.HTTPAuthTypeDefinition{} + authMethods := []*serverconfigs.HTTPAuthTypeDefinition{} for _, method := range serverconfigs.FindAllHTTPAuthTypes(teaconst.Role) { if !method.IsPlus || (method.IsPlus && teaconst.IsPlus) { authMethods = append(authMethods, method) @@ -47,7 +47,7 @@ func (this *UpdatePopupAction) RunGet(params struct { return } - var authParams = map[string]interface{}{} + authParams := map[string]interface{}{} if len(policy.ParamsJSON) > 0 { err = json.Unmarshal(policy.ParamsJSON, &authParams) if err != nil { @@ -91,6 +91,10 @@ func (this *UpdatePopupAction) RunPost(params struct { TypeDTimestampParamName string TypeDLife int + // TypeE + TypeESecret string + TypeELife int + // BasicAuth HttpAuthBasicAuthUsersJSON []byte BasicAuthRealm string @@ -125,29 +129,25 @@ func (this *UpdatePopupAction) RunPost(params struct { Field("name", params.Name). Require("请输入名称") - var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true} + ref := &serverconfigs.HTTPAuthPolicyRef{IsOn: true} var method serverconfigs.HTTPAuthMethodInterface - // 扩展名 - var exts = utils.NewStringsStream(params.Exts). + exts := utils.NewStringsStream(params.Exts). Map(strings.TrimSpace, strings.ToLower). Filter(utils.FilterNotEmpty). Map(utils.MapAddPrefixFunc(".")). Unique(). Result() - // 域名 - var domains = []string{} + domains := []string{} if len(params.DomainsJSON) > 0 { - var rawDomains = []string{} + rawDomains := []string{} err := json.Unmarshal(params.DomainsJSON, &rawDomains) if err != nil { this.ErrorPage(err) return } - // TODO 如果用户填写了一个网址,应该分析域名并填入 - domains = utils.NewStringsStream(rawDomains). Map(strings.TrimSpace, strings.ToLower). Filter(utils.FilterNotEmpty). @@ -160,11 +160,11 @@ func (this *UpdatePopupAction) RunPost(params struct { params.Must. Field("typeASecret", params.TypeASecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字"). Field("typeASignParamName", params.TypeASignParamName). Require("请输入签名参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字、下划线") + Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字和下划线") if params.TypeALife < 0 { params.TypeALife = 0 @@ -179,8 +179,8 @@ func (this *UpdatePopupAction) RunPost(params struct { params.Must. Field("typeBSecret", params.TypeBSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字") + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") method = &serverconfigs.HTTPAuthTypeBMethod{ Secret: params.TypeBSecret, @@ -190,8 +190,8 @@ func (this *UpdatePopupAction) RunPost(params struct { params.Must. Field("typeCSecret", params.TypeCSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字") + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") method = &serverconfigs.HTTPAuthTypeCMethod{ Secret: params.TypeCSecret, @@ -201,14 +201,14 @@ func (this *UpdatePopupAction) RunPost(params struct { params.Must. Field("typeDSecret", params.TypeDSecret). Require("请输入鉴权密钥"). - MaxLength(40, "鉴权密钥不能超过40个字符"). - Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母、数字"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字"). Field("typeDSignParamName", params.TypeDSignParamName). Require("请输入签名参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字、下划线"). + Match(`^[a-zA-Z0-9_]{1,40}$`, "签名参数中只能包含字母、数字和下划线"). Field("typeDTimestampParamName", params.TypeDTimestampParamName). - Require("请输入时间戳参数"). - Match(`^[a-zA-Z0-9_]{1,40}$`, "时间戳参数中只能包含字母、数字、下划线") + Require("请输入时间参数"). + Match(`^[a-zA-Z0-9_]{1,40}$`, "时间参数中只能包含字母、数字和下划线") method = &serverconfigs.HTTPAuthTypeDMethod{ Secret: params.TypeDSecret, @@ -216,6 +216,17 @@ func (this *UpdatePopupAction) RunPost(params struct { TimestampParamName: params.TypeDTimestampParamName, Life: params.TypeDLife, } + case serverconfigs.HTTPAuthTypeTypeE: + params.Must. + Field("typeESecret", params.TypeESecret). + Require("请输入鉴权密钥"). + MaxLength(40, "鉴权密钥长度不能超过40个字符"). + Match(`^[a-zA-Z0-9]{1,40}$`, "鉴权密钥中只能包含字母和数字") + + method = &serverconfigs.HTTPAuthTypeEMethod{ + Secret: params.TypeESecret, + Life: params.TypeELife, + } case serverconfigs.HTTPAuthTypeBasicAuth: users := []*serverconfigs.HTTPAuthBasicMethodUser{} err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users) @@ -224,7 +235,7 @@ func (this *UpdatePopupAction) RunPost(params struct { return } if len(users) == 0 { - this.Fail("请添加至少一个用户") + this.Fail("请至少添加一个用户") } method = &serverconfigs.HTTPAuthBasicMethod{ Users: users, @@ -232,8 +243,9 @@ func (this *UpdatePopupAction) RunPost(params struct { Charset: params.BasicAuthCharset, } case serverconfigs.HTTPAuthTypeSubRequest: - params.Must.Field("subRequestURL", params.SubRequestURL). - Require("请输入子请求URL") + params.Must. + Field("subRequestURL", params.SubRequestURL). + Require("请输入子请求 URL") if params.SubRequestFollowRequest { params.SubRequestMethod = "" } @@ -242,7 +254,7 @@ func (this *UpdatePopupAction) RunPost(params struct { Method: params.SubRequestMethod, } default: - this.Fail("不支持的鉴权类型'" + policyType + "'") + this.Fail("不支持的鉴权类型 '" + policyType + "'") } if method == nil { @@ -275,6 +287,7 @@ func (this *UpdatePopupAction) RunPost(params struct { this.ErrorPage(err) return } + ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{ Id: params.PolicyId, Name: params.Name, diff --git a/EdgeAdmin/internal/web/actions/default/ui/components.go b/EdgeAdmin/internal/web/actions/default/ui/components.go index 2c7dbfd..9decb16 100644 --- a/EdgeAdmin/internal/web/actions/default/ui/components.go +++ b/EdgeAdmin/internal/web/actions/default/ui/components.go @@ -16,6 +16,8 @@ import ( "github.com/iwind/TeaGo/logs" "github.com/iwind/TeaGo/maps" "net/http" + "os" + "path/filepath" ) type ComponentsAction actions.Action @@ -41,12 +43,7 @@ func (this *ComponentsAction) RunGet(params struct{}) { var buffer = bytes.NewBuffer([]byte{}) - var webRoot string - if Tea.IsTesting() { - webRoot = Tea.Root + "/../web/public/js/components/" - } else { - webRoot = Tea.Root + "/web/public/js/components/" - } + webRoot := findComponentsRoot() f := files.NewFile(webRoot) f.Range(func(file *files.File) { @@ -173,3 +170,27 @@ func (this *ComponentsAction) RunGet(params struct{}) { _, _ = this.Write(componentsData) } + +func findComponentsRoot() string { + candidates := []string{ + filepath.Join(Tea.Root, "web", "public", "js", "components"), + filepath.Join(Tea.Root, "..", "web", "public", "js", "components"), + filepath.Join(Tea.Root, "..", "..", "web", "public", "js", "components"), + } + + if cwd, err := os.Getwd(); err == nil && len(cwd) > 0 { + candidates = append(candidates, + filepath.Join(cwd, "web", "public", "js", "components"), + filepath.Join(cwd, "EdgeAdmin", "web", "public", "js", "components"), + ) + } + + for _, candidate := range candidates { + info, err := os.Stat(candidate) + if err == nil && info.IsDir() { + return candidate + string(filepath.Separator) + } + } + + return filepath.Join(Tea.Root, "web", "public", "js", "components") + string(filepath.Separator) +} diff --git a/EdgeAdmin/internal/web/import.go b/EdgeAdmin/internal/web/import.go index 73167f8..79cc14f 100644 --- a/EdgeAdmin/internal/web/import.go +++ b/EdgeAdmin/internal/web/import.go @@ -141,7 +141,6 @@ import ( _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/apps" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/clusters" - _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/clusters" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/resolveLogs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/runtimeLogs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/sandbox" diff --git a/EdgeAdmin/web/public/js/components.js b/EdgeAdmin/web/public/js/components.js index e333e92..09b483a 100644 --- a/EdgeAdmin/web/public/js/components.js +++ b/EdgeAdmin/web/public/js/components.js @@ -2272,6 +2272,57 @@ Vue.component("health-check-config-box", { ` }) +Vue.component("httpdns-clusters-selector", { + props: ["vClusters", "vName"], + data: function () { + let inputClusters = this.vClusters + let clusters = [] + + if (inputClusters != null && inputClusters.length > 0) { + if (inputClusters[0].isChecked !== undefined) { + // 带 isChecked 标志的完整集群列表 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: c.isChecked} + }) + } else { + // 仅包含已选集群,全部标记为选中 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: true} + }) + } + } + + // 无 prop 时从根实例读取所有集群(如创建应用页面) + if (clusters.length === 0) { + let rootClusters = this.$root.clusters + if (rootClusters != null && rootClusters.length > 0) { + clusters = rootClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: false} + }) + } + } + + return { + clusters: clusters, + fieldName: this.vName || "clusterIds" + } + }, + methods: { + changeCluster: function (cluster) { + cluster.isChecked = !cluster.isChecked + } + }, + template: `
+
+ + {{cluster.name}} + +
+ 暂无可用集群 +
` +}) + + /** * 菜单项 */ @@ -11294,10 +11345,18 @@ Vue.component("http-auth-config-box", { if (authConfig.policyRefs == null) { authConfig.policyRefs = [] } - return { + return { authConfig: authConfig } }, + watch: { + "authConfig.isOn": function () { + this.change() + }, + "authConfig.isPrior": function () { + this.change() + } + }, methods: { isOn: function () { return (!this.vIsLocation || this.authConfig.isPrior) && this.authConfig.isOn @@ -11309,18 +11368,17 @@ Vue.component("http-auth-config-box", { that.authConfig.policyRefs.push(resp.data.policyRef) that.change() }, - height: "28em" + height: "32em" }) }, update: function (index, policyId) { - let that = this teaweb.popup("/servers/server/settings/access/updatePopup?policyId=" + policyId, { - callback: function (resp) { + callback: function () { teaweb.success("保存成功", function () { teaweb.reload() }) }, - height: "28em" + height: "32em" }) }, remove: function (index) { @@ -11341,14 +11399,15 @@ Vue.component("http-auth-config-box", { return "URL鉴权C" case "typeD": return "URL鉴权D" + case "typeE": + return "URL鉴权E" } return "" }, change: function () { let that = this setTimeout(function () { - // 延时通知,是为了让表单有机会变更数据 - that.$emit("change", this.authConfig) + that.$emit("change", that.authConfig) }, 100) } }, @@ -11369,7 +11428,6 @@ Vue.component("http-auth-config-box", {
-

鉴权方式

@@ -11385,9 +11443,7 @@ Vue.component("http-auth-config-box", { - +
{{ref.authPolicy.name}} - {{methodName(ref.authPolicy.type)}} - {{methodName(ref.authPolicy.type)}} {{ref.authPolicy.params.users.length}}个用户 @@ -11398,7 +11454,7 @@ Vue.component("http-auth-config-box", { 有效期{{ref.authPolicy.params.life}}秒 有效期{{ref.authPolicy.params.life}}秒 {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 - + 路径模式/有效期{{ref.authPolicy.params.life}}秒
扩展名:{{ext}} 域名:{{domain}} @@ -11420,6 +11476,7 @@ Vue.component("http-auth-config-box", {
` }) + Vue.component("http-cache-config-box", { props: ["v-cache-config", "v-is-location", "v-is-group", "v-cache-policy", "v-web-id"], data: function () { diff --git a/EdgeAdmin/web/public/js/components.src.js b/EdgeAdmin/web/public/js/components.src.js index e333e92..09b483a 100644 --- a/EdgeAdmin/web/public/js/components.src.js +++ b/EdgeAdmin/web/public/js/components.src.js @@ -2272,6 +2272,57 @@ Vue.component("health-check-config-box", { ` }) +Vue.component("httpdns-clusters-selector", { + props: ["vClusters", "vName"], + data: function () { + let inputClusters = this.vClusters + let clusters = [] + + if (inputClusters != null && inputClusters.length > 0) { + if (inputClusters[0].isChecked !== undefined) { + // 带 isChecked 标志的完整集群列表 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: c.isChecked} + }) + } else { + // 仅包含已选集群,全部标记为选中 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: true} + }) + } + } + + // 无 prop 时从根实例读取所有集群(如创建应用页面) + if (clusters.length === 0) { + let rootClusters = this.$root.clusters + if (rootClusters != null && rootClusters.length > 0) { + clusters = rootClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: false} + }) + } + } + + return { + clusters: clusters, + fieldName: this.vName || "clusterIds" + } + }, + methods: { + changeCluster: function (cluster) { + cluster.isChecked = !cluster.isChecked + } + }, + template: `
+
+ + {{cluster.name}} + +
+ 暂无可用集群 +
` +}) + + /** * 菜单项 */ @@ -11294,10 +11345,18 @@ Vue.component("http-auth-config-box", { if (authConfig.policyRefs == null) { authConfig.policyRefs = [] } - return { + return { authConfig: authConfig } }, + watch: { + "authConfig.isOn": function () { + this.change() + }, + "authConfig.isPrior": function () { + this.change() + } + }, methods: { isOn: function () { return (!this.vIsLocation || this.authConfig.isPrior) && this.authConfig.isOn @@ -11309,18 +11368,17 @@ Vue.component("http-auth-config-box", { that.authConfig.policyRefs.push(resp.data.policyRef) that.change() }, - height: "28em" + height: "32em" }) }, update: function (index, policyId) { - let that = this teaweb.popup("/servers/server/settings/access/updatePopup?policyId=" + policyId, { - callback: function (resp) { + callback: function () { teaweb.success("保存成功", function () { teaweb.reload() }) }, - height: "28em" + height: "32em" }) }, remove: function (index) { @@ -11341,14 +11399,15 @@ Vue.component("http-auth-config-box", { return "URL鉴权C" case "typeD": return "URL鉴权D" + case "typeE": + return "URL鉴权E" } return "" }, change: function () { let that = this setTimeout(function () { - // 延时通知,是为了让表单有机会变更数据 - that.$emit("change", this.authConfig) + that.$emit("change", that.authConfig) }, 100) } }, @@ -11369,7 +11428,6 @@ Vue.component("http-auth-config-box", {
-

鉴权方式

@@ -11385,9 +11443,7 @@ Vue.component("http-auth-config-box", { - +
{{ref.authPolicy.name}} - {{methodName(ref.authPolicy.type)}} - {{methodName(ref.authPolicy.type)}} {{ref.authPolicy.params.users.length}}个用户 @@ -11398,7 +11454,7 @@ Vue.component("http-auth-config-box", { 有效期{{ref.authPolicy.params.life}}秒 有效期{{ref.authPolicy.params.life}}秒 {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 - + 路径模式/有效期{{ref.authPolicy.params.life}}秒
扩展名:{{ext}} 域名:{{domain}} @@ -11420,6 +11476,7 @@ Vue.component("http-auth-config-box", {
` }) + Vue.component("http-cache-config-box", { props: ["v-cache-config", "v-is-location", "v-is-group", "v-cache-policy", "v-web-id"], data: function () { diff --git a/EdgeAdmin/web/public/js/components/common/httpdns-clusters-selector.js b/EdgeAdmin/web/public/js/components/common/httpdns-clusters-selector.js new file mode 100644 index 0000000..0c4d0d5 --- /dev/null +++ b/EdgeAdmin/web/public/js/components/common/httpdns-clusters-selector.js @@ -0,0 +1,49 @@ +Vue.component("httpdns-clusters-selector", { + props: ["vClusters", "vName"], + data: function () { + let inputClusters = this.vClusters + let clusters = [] + + if (inputClusters != null && inputClusters.length > 0) { + if (inputClusters[0].isChecked !== undefined) { + // 带 isChecked 标志的完整集群列表 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: c.isChecked} + }) + } else { + // 仅包含已选集群,全部标记为选中 + clusters = inputClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: true} + }) + } + } + + // 无 prop 时从根实例读取所有集群(如创建应用页面) + if (clusters.length === 0) { + let rootClusters = this.$root.clusters + if (rootClusters != null && rootClusters.length > 0) { + clusters = rootClusters.map(function (c) { + return {id: c.id, name: c.name, isChecked: false} + }) + } + } + + return { + clusters: clusters, + fieldName: this.vName || "clusterIds" + } + }, + methods: { + changeCluster: function (cluster) { + cluster.isChecked = !cluster.isChecked + } + }, + template: `
+
+ + {{cluster.name}} + +
+ 暂无可用集群 +
` +}) diff --git a/EdgeAdmin/web/public/js/components/server/http-auth-config-box.js b/EdgeAdmin/web/public/js/components/server/http-auth-config-box.js index 02a5487..75f513c 100644 --- a/EdgeAdmin/web/public/js/components/server/http-auth-config-box.js +++ b/EdgeAdmin/web/public/js/components/server/http-auth-config-box.js @@ -12,10 +12,18 @@ Vue.component("http-auth-config-box", { if (authConfig.policyRefs == null) { authConfig.policyRefs = [] } - return { + return { authConfig: authConfig } }, + watch: { + "authConfig.isOn": function () { + this.change() + }, + "authConfig.isPrior": function () { + this.change() + } + }, methods: { isOn: function () { return (!this.vIsLocation || this.authConfig.isPrior) && this.authConfig.isOn @@ -27,18 +35,17 @@ Vue.component("http-auth-config-box", { that.authConfig.policyRefs.push(resp.data.policyRef) that.change() }, - height: "28em" + height: "32em" }) }, update: function (index, policyId) { - let that = this teaweb.popup("/servers/server/settings/access/updatePopup?policyId=" + policyId, { - callback: function (resp) { + callback: function () { teaweb.success("保存成功", function () { teaweb.reload() }) }, - height: "28em" + height: "32em" }) }, remove: function (index) { @@ -59,14 +66,15 @@ Vue.component("http-auth-config-box", { return "URL鉴权C" case "typeD": return "URL鉴权D" + case "typeE": + return "URL鉴权E" } return "" }, change: function () { let that = this setTimeout(function () { - // 延时通知,是为了让表单有机会变更数据 - that.$emit("change", this.authConfig) + that.$emit("change", that.authConfig) }, 100) } }, @@ -87,7 +95,6 @@ Vue.component("http-auth-config-box", {
-

鉴权方式

@@ -103,9 +110,7 @@ Vue.component("http-auth-config-box", { - + + + + + + + + + + + + + @@ -138,7 +159,7 @@ - + @@ -147,7 +168,7 @@ @@ -186,7 +207,7 @@ @@ -200,4 +221,4 @@
{{ref.authPolicy.name}} - {{methodName(ref.authPolicy.type)}} - {{methodName(ref.authPolicy.type)}} {{ref.authPolicy.params.users.length}}个用户 @@ -116,7 +121,7 @@ Vue.component("http-auth-config-box", { 有效期{{ref.authPolicy.params.life}}秒 有效期{{ref.authPolicy.params.life}}秒 {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 - + 路径模式/有效期{{ref.authPolicy.params.life}}秒
扩展名:{{ext}} 域名:{{domain}} @@ -136,4 +141,4 @@ Vue.component("http-auth-config-box", {
` -}) \ No newline at end of file +}) diff --git a/EdgeAdmin/web/views/@default/@layout.html b/EdgeAdmin/web/views/@default/@layout.html index 722a93c..837c78c 100644 --- a/EdgeAdmin/web/views/@default/@layout.html +++ b/EdgeAdmin/web/views/@default/@layout.html @@ -37,7 +37,7 @@ - + diff --git a/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.html b/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.html deleted file mode 100644 index c5e03ba..0000000 --- a/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.html +++ /dev/null @@ -1,32 +0,0 @@ -{$layout} - -{$template "../menu"} -{$template "/left_menu_with_menu"} - -
-
- - 此功能为试验功能,目前只能做一些简单的网络数据包统计。 - -
- - - - - - - - -
启用数据包统计 - -

自动根据服务器硬件配置决定是否启用,避免影响性能。

-

强制启用;如果节点服务器配置较低,可能会严重影响性能,建议仅在8线程以上CPU节点服务器上选择强制启用。

-

完全关闭此功能。

-
- -
-
\ No newline at end of file diff --git a/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.js b/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.js deleted file mode 100644 index 295a9aa..0000000 --- a/EdgeAdmin/web/views/@default/clusters/cluster/settings/network-security/index.js +++ /dev/null @@ -1,3 +0,0 @@ -Tea.context(function () { - this.success = NotifyReloadSuccess("保存成功") -}) \ No newline at end of file diff --git a/EdgeAdmin/web/views/@default/dashboard/boards/@menu.html b/EdgeAdmin/web/views/@default/dashboard/boards/@menu.html index d9ac6ff..cb5de8d 100644 --- a/EdgeAdmin/web/views/@default/dashboard/boards/@menu.html +++ b/EdgeAdmin/web/views/@default/dashboard/boards/@menu.html @@ -6,6 +6,7 @@ ({{countTodayAttacksFormat}}) {{LANG('admin_dashboard@ui_dns')}} + HTTPDNS {{LANG('admin_dashboard@ui_user')}} {{LANG('admin_dashboard@ui_events')}}({{countEvents}}) - \ No newline at end of file + diff --git a/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.css b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.css new file mode 100644 index 0000000..660af90 --- /dev/null +++ b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.css @@ -0,0 +1,8 @@ +.ui.message .icon { + position: absolute; + right: 1em; + top: 1.8em; +} +.chart-box { + height: 14em; +} diff --git a/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.html b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.html new file mode 100644 index 0000000..50bc8cc --- /dev/null +++ b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.html @@ -0,0 +1,67 @@ +{$layout} +{$template "menu"} +{$template "/echarts"} + +
+
+
  数据加载中... +
+
+ +
+ +
+

应用

+
{{board.countApps}}
+
+
+

域名

+
{{board.countDomains}}
+
+
+

集群

+
{{board.countClusters}}
+
+
+

节点

+
{{board.countNodes}} + + / {{board.countOfflineNodes}}离线 + + +
+
+
+ + + + +
+

应用请求排行 (24小时)

+
+
+
+ +
+

域名请求排行 (24小时)

+
+
+
+ +
+

节点访问排行 (24小时)

+
+
+
+ +
+
diff --git a/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.js b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.js new file mode 100644 index 0000000..2cf6eb7 --- /dev/null +++ b/EdgeAdmin/web/views/@default/dashboard/boards/httpdns.js @@ -0,0 +1,192 @@ +Tea.context(function () { + this.isLoading = true + + this.$delay(function () { + this.$post("$") + .success(function (resp) { + for (let k in resp.data) { + this[k] = resp.data[k] + } + + this.$delay(function () { + this.reloadHourlyTrafficChart() + this.reloadTopAppsChart() + this.reloadTopDomainsChart() + this.reloadTopNodesChart() + }) + + this.isLoading = false + }) + }) + + this.trafficTab = "hourly" + + this.selectTrafficTab = function (tab) { + this.trafficTab = tab + if (tab == "hourly") { + this.$delay(function () { + this.reloadHourlyTrafficChart() + }) + } else if (tab == "daily") { + this.$delay(function () { + this.reloadDailyTrafficChart() + }) + } + } + + this.reloadHourlyTrafficChart = function () { + let stats = this.hourlyStats + if (stats == null || stats.length == 0) { + return + } + this.reloadTrafficChart("hourly-traffic-chart", stats, function (args) { + return stats[args.dataIndex].day + " " + stats[args.dataIndex].hour + "时
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }) + } + + this.reloadDailyTrafficChart = function () { + let stats = this.dailyStats + if (stats == null || stats.length == 0) { + return + } + this.reloadTrafficChart("daily-traffic-chart", stats, function (args) { + return stats[args.dataIndex].day + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }) + } + + this.reloadTrafficChart = function (chartId, stats, tooltipFunc) { + let chartBox = document.getElementById(chartId) + if (chartBox == null) { + return + } + + let axis = teaweb.countAxis(stats, function (v) { + return v.countRequests + }) + + let chart = teaweb.initChart(chartBox) + let option = { + xAxis: { + data: stats.map(function (v) { + if (v.hour != null) { + return v.hour + } + return v.day + }) + }, + yAxis: { + axisLabel: { + formatter: function (value) { + return value + axis.unit + } + } + }, + tooltip: { + show: true, + trigger: "item", + formatter: tooltipFunc + }, + grid: { + left: 50, + top: 10, + right: 20, + bottom: 20 + }, + series: [ + { + name: "请求数", + type: "line", + data: stats.map(function (v) { + return v.countRequests / axis.divider + }), + itemStyle: { + color: teaweb.DefaultChartColor + }, + areaStyle: { + color: teaweb.DefaultChartColor + }, + smooth: true + } + ], + animation: true + } + chart.setOption(option) + chart.resize() + } + + this.reloadTopAppsChart = function () { + if (this.topAppStats == null || this.topAppStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topAppStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-apps-chart", + name: "应用", + values: this.topAppStats, + x: function (v) { + return v.appName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].appName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis + }) + } + + this.reloadTopDomainsChart = function () { + if (this.topDomainStats == null || this.topDomainStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topDomainStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-domains-chart", + name: "域名", + values: this.topDomainStats, + x: function (v) { + return v.domainName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].domainName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis + }) + } + + this.reloadTopNodesChart = function () { + if (this.topNodeStats == null || this.topNodeStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topNodeStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-nodes-chart", + name: "节点", + values: this.topNodeStats, + x: function (v) { + return v.nodeName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].nodeName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis, + click: function (args, stats) { + window.location = "/httpdns/clusters/cluster/node?nodeId=" + stats[args.dataIndex].nodeId + "&clusterId=" + stats[args.dataIndex].clusterId + } + }) + } + +}) diff --git a/EdgeAdmin/web/views/@default/dashboard/boards/index.html b/EdgeAdmin/web/views/@default/dashboard/boards/index.html index cc67d25..ffb0475 100644 --- a/EdgeAdmin/web/views/@default/dashboard/boards/index.html +++ b/EdgeAdmin/web/views/@default/dashboard/boards/index.html @@ -53,8 +53,9 @@
@@ -73,7 +74,15 @@ +
diff --git a/EdgeAdmin/web/views/@default/dashboard/index.html b/EdgeAdmin/web/views/@default/dashboard/index.html index f79e5f9..0697ee7 100644 --- a/EdgeAdmin/web/views/@default/dashboard/index.html +++ b/EdgeAdmin/web/views/@default/dashboard/index.html @@ -33,7 +33,9 @@ diff --git a/EdgeAdmin/web/views/@default/httpdns/clusters/create.js b/EdgeAdmin/web/views/@default/httpdns/clusters/create.js index 0918023..8234e7c 100644 --- a/EdgeAdmin/web/views/@default/httpdns/clusters/create.js +++ b/EdgeAdmin/web/views/@default/httpdns/clusters/create.js @@ -1,6 +1,9 @@ Tea.context(function () { this.isOn = true + this.syncDefaultClusterEnabled = function () { + } + this.success = function (resp) { let clusterId = 0 if (resp != null && resp.data != null && typeof resp.data.clusterId != "undefined") { diff --git a/EdgeAdmin/web/views/@default/httpdns/index.css b/EdgeAdmin/web/views/@default/httpdns/index.css new file mode 100644 index 0000000..660af90 --- /dev/null +++ b/EdgeAdmin/web/views/@default/httpdns/index.css @@ -0,0 +1,8 @@ +.ui.message .icon { + position: absolute; + right: 1em; + top: 1.8em; +} +.chart-box { + height: 14em; +} diff --git a/EdgeAdmin/web/views/@default/httpdns/index.html b/EdgeAdmin/web/views/@default/httpdns/index.html new file mode 100644 index 0000000..2f234a2 --- /dev/null +++ b/EdgeAdmin/web/views/@default/httpdns/index.html @@ -0,0 +1,62 @@ +{$layout} +{$template "/echarts"} + +
+
+
  数据加载中... +
+
+ +
+
+
+

应用

+
{{board.countApps}}
+
+
+

域名

+
{{board.countDomains}}
+
+
+

集群

+
{{board.countClusters}}
+
+
+

节点

+
{{board.countNodes}} + {{board.countOfflineNodes}}离线 + +
+
+
+ +
+ + +
+

应用请求排行 (24小时)

+
+
+
+ +
+

域名请求排行 (24小时)

+
+
+
+ +
+

节点访问排行 (24小时)

+
+
+
+
+
diff --git a/EdgeAdmin/web/views/@default/httpdns/index.js b/EdgeAdmin/web/views/@default/httpdns/index.js new file mode 100644 index 0000000..c7d2ede --- /dev/null +++ b/EdgeAdmin/web/views/@default/httpdns/index.js @@ -0,0 +1,191 @@ +Tea.context(function () { + this.isLoading = true + + this.$delay(function () { + this.$post("$") + .success(function (resp) { + for (let k in resp.data) { + this[k] = resp.data[k] + } + + this.$delay(function () { + this.reloadHourlyTrafficChart() + this.reloadTopAppsChart() + this.reloadTopDomainsChart() + this.reloadTopNodesChart() + }) + + this.isLoading = false + }) + }) + + this.trafficTab = "hourly" + + this.selectTrafficTab = function (tab) { + this.trafficTab = tab + if (tab == "hourly") { + this.$delay(function () { + this.reloadHourlyTrafficChart() + }) + } else if (tab == "daily") { + this.$delay(function () { + this.reloadDailyTrafficChart() + }) + } + } + + this.reloadHourlyTrafficChart = function () { + let stats = this.hourlyStats + if (stats == null || stats.length == 0) { + return + } + this.reloadTrafficChart("hourly-traffic-chart", stats, function (args) { + return stats[args.dataIndex].day + " " + stats[args.dataIndex].hour + "时
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }) + } + + this.reloadDailyTrafficChart = function () { + let stats = this.dailyStats + if (stats == null || stats.length == 0) { + return + } + this.reloadTrafficChart("daily-traffic-chart", stats, function (args) { + return stats[args.dataIndex].day + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }) + } + + this.reloadTrafficChart = function (chartId, stats, tooltipFunc) { + let chartBox = document.getElementById(chartId) + if (chartBox == null) { + return + } + + let axis = teaweb.countAxis(stats, function (v) { + return v.countRequests + }) + + let chart = teaweb.initChart(chartBox) + let option = { + xAxis: { + data: stats.map(function (v) { + if (v.hour != null) { + return v.hour + } + return v.day + }) + }, + yAxis: { + axisLabel: { + formatter: function (value) { + return value + axis.unit + } + } + }, + tooltip: { + show: true, + trigger: "item", + formatter: tooltipFunc + }, + grid: { + left: 50, + top: 10, + right: 20, + bottom: 20 + }, + series: [ + { + name: "请求数", + type: "line", + data: stats.map(function (v) { + return v.countRequests / axis.divider + }), + itemStyle: { + color: teaweb.DefaultChartColor + }, + areaStyle: { + color: teaweb.DefaultChartColor + }, + smooth: true + } + ], + animation: true + } + chart.setOption(option) + chart.resize() + } + + this.reloadTopAppsChart = function () { + if (this.topAppStats == null || this.topAppStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topAppStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-apps-chart", + name: "应用", + values: this.topAppStats, + x: function (v) { + return v.appName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].appName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis + }) + } + + this.reloadTopDomainsChart = function () { + if (this.topDomainStats == null || this.topDomainStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topDomainStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-domains-chart", + name: "域名", + values: this.topDomainStats, + x: function (v) { + return v.domainName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].domainName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis + }) + } + + this.reloadTopNodesChart = function () { + if (this.topNodeStats == null || this.topNodeStats.length == 0) { + return + } + let axis = teaweb.countAxis(this.topNodeStats, function (v) { + return v.countRequests + }) + teaweb.renderBarChart({ + id: "top-nodes-chart", + name: "节点", + values: this.topNodeStats, + x: function (v) { + return v.nodeName + }, + tooltip: function (args, stats) { + return stats[args.dataIndex].nodeName + "
请求数:" + teaweb.formatNumber(stats[args.dataIndex].countRequests) + }, + value: function (v) { + return v.countRequests / axis.divider + }, + axis: axis, + click: function (args, stats) { + window.location = "/httpdns/clusters/cluster/node?nodeId=" + stats[args.dataIndex].nodeId + "&clusterId=" + stats[args.dataIndex].clusterId + } + }) + } +}) diff --git a/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.html b/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.html index 413d08e..55028b3 100644 --- a/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.html +++ b/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.html @@ -124,6 +124,27 @@
鉴权密钥 * + +

只能包含字母、数字,长度不超过40。[随机生成]

+
有效时间 +
+ + +
+

URL 格式:/hash/timestamp/path;签名算法:md5(secret + uri + timestamp);timestamp 为十六进制 Unix 秒数。

+
认证领域名(Realm)认证领域名 (Realm) 字符集 -

类似于UTF-8

+

类似于 UTF-8

限定文件扩展名 -

如果不为空,则表示只有这些扩展名的文件才需要鉴权;扩展名需要包含点符号(.),比如.png

+

如果不为空,则表示只有这些扩展名的文件才需要鉴权;扩展名需要包含点符号,比如 .png

- \ No newline at end of file + diff --git a/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.js b/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.js index 93c9905..9216c7f 100644 --- a/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.js +++ b/EdgeAdmin/web/views/@default/servers/server/settings/access/createPopup.js @@ -84,6 +84,18 @@ Tea.context(function () { this.authDescription = this.authDescription.replace("t=", this.typeDTimestampParamName + "=") } + /** + * TypeE + */ + this.typeESecret = "" + + this.generateTypeESecret = function () { + this.$post(".random") + .success(function (resp) { + this.typeESecret = resp.data.random + }) + } + /** * 基本认证 */ @@ -97,4 +109,4 @@ Tea.context(function () { * 子请求 */ this.subRequestFollowRequest = 1 -}) \ No newline at end of file +}) diff --git a/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.html b/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.html index 7b4f98a..17bb03d 100644 --- a/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.html +++ b/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.html @@ -122,6 +122,27 @@ + + + + 鉴权密钥 * + + +

只能包含字母、数字,长度不超过40。[随机生成]

+ + + + 有效时间 + +
+ + +
+

URL 格式:/hash/timestamp/path;签名算法:md5(secret + uri + timestamp);timestamp 为十六进制 Unix 秒数。

+ + + + @@ -136,7 +157,7 @@ - 认证领域名(Realm) + 认证领域名 (Realm) @@ -145,7 +166,7 @@ 字符集 -

类似于utf-8

+

类似于 utf-8

@@ -185,7 +206,7 @@ 限定文件扩展名 -

如果不为空,则表示只有这些扩展名的文件才需要鉴权;扩展名需要包含点符号(.),比如.png

+

如果不为空,则表示只有这些扩展名的文件才需要鉴权;扩展名需要包含点符号,比如 .png

@@ -203,4 +224,4 @@ - \ No newline at end of file + diff --git a/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.js b/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.js index 8891308..365a308 100644 --- a/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.js +++ b/EdgeAdmin/web/views/@default/servers/server/settings/access/updatePopup.js @@ -115,6 +115,22 @@ Tea.context(function () { this.authDescription = this.authDescription.replace("t=", this.typeDTimestampParamName + "=") } + /** + * TypeE + */ + this.typeESecret = "" + + if (this.policy.type == "typeE") { + this.typeESecret = this.policy.params.secret + } + + this.generateTypeESecret = function () { + this.$post(".random") + .success(function (resp) { + this.typeESecret = resp.data.random + }) + } + /** * 基本鉴权 */ @@ -128,4 +144,4 @@ Tea.context(function () { * 子请求 */ this.subRequestFollowRequest = (this.policy.params.method != null && this.policy.params.method.length > 0) ? 0 : 1 -}) \ No newline at end of file +}) diff --git a/EdgeCommon/.gitignore b/EdgeCommon/.gitignore index e69de29..a12dacd 100644 --- a/EdgeCommon/.gitignore +++ b/EdgeCommon/.gitignore @@ -0,0 +1 @@ +build/temp_build.sh diff --git a/EdgeCommon/build/rpc.json b/EdgeCommon/build/rpc.json index d43ae82..87d8b81 100644 --- a/EdgeCommon/build/rpc.json +++ b/EdgeCommon/build/rpc.json @@ -3682,6 +3682,564 @@ "filename": "service_http_websocket.proto", "doc": "HTTP Websocket管理服务" }, + { + "name": "HTTPDNSAccessLogService", + "methods": [ + { + "name": "createHTTPDNSAccessLogs", + "requestMessageName": "CreateHTTPDNSAccessLogsRequest", + "responseMessageName": "CreateHTTPDNSAccessLogsResponse", + "code": "rpc createHTTPDNSAccessLogs (CreateHTTPDNSAccessLogsRequest) returns (CreateHTTPDNSAccessLogsResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSAccessLogs", + "requestMessageName": "ListHTTPDNSAccessLogsRequest", + "responseMessageName": "ListHTTPDNSAccessLogsResponse", + "code": "rpc listHTTPDNSAccessLogs (ListHTTPDNSAccessLogsRequest) returns (ListHTTPDNSAccessLogsResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_access_log.proto", + "doc": "" + }, + { + "name": "HTTPDNSAppService", + "methods": [ + { + "name": "createHTTPDNSApp", + "requestMessageName": "CreateHTTPDNSAppRequest", + "responseMessageName": "CreateHTTPDNSAppResponse", + "code": "rpc createHTTPDNSApp (CreateHTTPDNSAppRequest) returns (CreateHTTPDNSAppResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSApp", + "requestMessageName": "UpdateHTTPDNSAppRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSApp (UpdateHTTPDNSAppRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "deleteHTTPDNSApp", + "requestMessageName": "DeleteHTTPDNSAppRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc deleteHTTPDNSApp (DeleteHTTPDNSAppRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "findHTTPDNSApp", + "requestMessageName": "FindHTTPDNSAppRequest", + "responseMessageName": "FindHTTPDNSAppResponse", + "code": "rpc findHTTPDNSApp (FindHTTPDNSAppRequest) returns (FindHTTPDNSAppResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSApps", + "requestMessageName": "ListHTTPDNSAppsRequest", + "responseMessageName": "ListHTTPDNSAppsResponse", + "code": "rpc listHTTPDNSApps (ListHTTPDNSAppsRequest) returns (ListHTTPDNSAppsResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "findAllHTTPDNSApps", + "requestMessageName": "FindAllHTTPDNSAppsRequest", + "responseMessageName": "FindAllHTTPDNSAppsResponse", + "code": "rpc findAllHTTPDNSApps (FindAllHTTPDNSAppsRequest) returns (FindAllHTTPDNSAppsResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSAppSignEnabled", + "requestMessageName": "UpdateHTTPDNSAppSignEnabledRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSAppSignEnabled (UpdateHTTPDNSAppSignEnabledRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "resetHTTPDNSAppSignSecret", + "requestMessageName": "ResetHTTPDNSAppSignSecretRequest", + "responseMessageName": "ResetHTTPDNSAppSignSecretResponse", + "code": "rpc resetHTTPDNSAppSignSecret (ResetHTTPDNSAppSignSecretRequest) returns (ResetHTTPDNSAppSignSecretResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_app.proto", + "doc": "" + }, + { + "name": "HTTPDNSBoardService", + "methods": [ + { + "name": "composeHTTPDNSBoard", + "requestMessageName": "ComposeHTTPDNSBoardRequest", + "responseMessageName": "ComposeHTTPDNSBoardResponse", + "code": "rpc composeHTTPDNSBoard (ComposeHTTPDNSBoardRequest) returns (ComposeHTTPDNSBoardResponse);", + "doc": "组合看板数据", + "roles": [ + "admin" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_board.proto", + "doc": "HTTPDNS 看板服务" + }, + { + "name": "HTTPDNSClusterService", + "methods": [ + { + "name": "createHTTPDNSCluster", + "requestMessageName": "CreateHTTPDNSClusterRequest", + "responseMessageName": "CreateHTTPDNSClusterResponse", + "code": "rpc createHTTPDNSCluster (CreateHTTPDNSClusterRequest) returns (CreateHTTPDNSClusterResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSCluster", + "requestMessageName": "UpdateHTTPDNSClusterRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSCluster (UpdateHTTPDNSClusterRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "deleteHTTPDNSCluster", + "requestMessageName": "DeleteHTTPDNSClusterRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc deleteHTTPDNSCluster (DeleteHTTPDNSClusterRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "findHTTPDNSCluster", + "requestMessageName": "FindHTTPDNSClusterRequest", + "responseMessageName": "FindHTTPDNSClusterResponse", + "code": "rpc findHTTPDNSCluster (FindHTTPDNSClusterRequest) returns (FindHTTPDNSClusterResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSClusters", + "requestMessageName": "ListHTTPDNSClustersRequest", + "responseMessageName": "ListHTTPDNSClustersResponse", + "code": "rpc listHTTPDNSClusters (ListHTTPDNSClustersRequest) returns (ListHTTPDNSClustersResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "findAllHTTPDNSClusters", + "requestMessageName": "FindAllHTTPDNSClustersRequest", + "responseMessageName": "FindAllHTTPDNSClustersResponse", + "code": "rpc findAllHTTPDNSClusters (FindAllHTTPDNSClustersRequest) returns (FindAllHTTPDNSClustersResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSClusterDefault", + "requestMessageName": "UpdateHTTPDNSClusterDefaultRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSClusterDefault (UpdateHTTPDNSClusterDefaultRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSNodesWithClusterId", + "requestMessageName": "ListHTTPDNSNodesWithClusterIdRequest", + "responseMessageName": "ListHTTPDNSNodesWithClusterIdResponse", + "code": "rpc listHTTPDNSNodesWithClusterId (ListHTTPDNSNodesWithClusterIdRequest) returns (ListHTTPDNSNodesWithClusterIdResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_cluster.proto", + "doc": "" + }, + { + "name": "HTTPDNSDomainService", + "methods": [ + { + "name": "createHTTPDNSDomain", + "requestMessageName": "CreateHTTPDNSDomainRequest", + "responseMessageName": "CreateHTTPDNSDomainResponse", + "code": "rpc createHTTPDNSDomain (CreateHTTPDNSDomainRequest) returns (CreateHTTPDNSDomainResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "deleteHTTPDNSDomain", + "requestMessageName": "DeleteHTTPDNSDomainRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc deleteHTTPDNSDomain (DeleteHTTPDNSDomainRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSDomainStatus", + "requestMessageName": "UpdateHTTPDNSDomainStatusRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSDomainStatus (UpdateHTTPDNSDomainStatusRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSDomainsWithAppId", + "requestMessageName": "ListHTTPDNSDomainsWithAppIdRequest", + "responseMessageName": "ListHTTPDNSDomainsWithAppIdResponse", + "code": "rpc listHTTPDNSDomainsWithAppId (ListHTTPDNSDomainsWithAppIdRequest) returns (ListHTTPDNSDomainsWithAppIdResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_domain.proto", + "doc": "" + }, + { + "name": "HTTPDNSNodeService", + "methods": [ + { + "name": "createHTTPDNSNode", + "requestMessageName": "CreateHTTPDNSNodeRequest", + "responseMessageName": "CreateHTTPDNSNodeResponse", + "code": "rpc createHTTPDNSNode (CreateHTTPDNSNodeRequest) returns (CreateHTTPDNSNodeResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSNode", + "requestMessageName": "UpdateHTTPDNSNodeRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSNode (UpdateHTTPDNSNodeRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "deleteHTTPDNSNode", + "requestMessageName": "DeleteHTTPDNSNodeRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc deleteHTTPDNSNode (DeleteHTTPDNSNodeRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "findHTTPDNSNode", + "requestMessageName": "FindHTTPDNSNodeRequest", + "responseMessageName": "FindHTTPDNSNodeResponse", + "code": "rpc findHTTPDNSNode (FindHTTPDNSNodeRequest) returns (FindHTTPDNSNodeResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSNodes", + "requestMessageName": "ListHTTPDNSNodesRequest", + "responseMessageName": "ListHTTPDNSNodesResponse", + "code": "rpc listHTTPDNSNodes (ListHTTPDNSNodesRequest) returns (ListHTTPDNSNodesResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSNodeStatus", + "requestMessageName": "UpdateHTTPDNSNodeStatusRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSNodeStatus (UpdateHTTPDNSNodeStatusRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSNodeLogin", + "requestMessageName": "UpdateHTTPDNSNodeLoginRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSNodeLogin (UpdateHTTPDNSNodeLoginRequest) returns (RPCSuccess);", + "doc": "修改HTTPDNS节点登录信息", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "checkHTTPDNSNodeLatestVersion", + "requestMessageName": "CheckHTTPDNSNodeLatestVersionRequest", + "responseMessageName": "CheckHTTPDNSNodeLatestVersionResponse", + "code": "rpc checkHTTPDNSNodeLatestVersion (CheckHTTPDNSNodeLatestVersionRequest) returns (CheckHTTPDNSNodeLatestVersionResponse);", + "doc": "检查HTTPDNS节点新版本", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "downloadHTTPDNSNodeInstallationFile", + "requestMessageName": "DownloadHTTPDNSNodeInstallationFileRequest", + "responseMessageName": "DownloadHTTPDNSNodeInstallationFileResponse", + "code": "rpc downloadHTTPDNSNodeInstallationFile (DownloadHTTPDNSNodeInstallationFileRequest) returns (DownloadHTTPDNSNodeInstallationFileResponse);", + "doc": "下载最新HTTPDNS节点安装文件", + "roles": [], + "isDeprecated": false + }, + { + "name": "countAllUpgradeHTTPDNSNodesWithClusterId", + "requestMessageName": "CountAllUpgradeHTTPDNSNodesWithClusterIdRequest", + "responseMessageName": "RPCCountResponse", + "code": "rpc countAllUpgradeHTTPDNSNodesWithClusterId (CountAllUpgradeHTTPDNSNodesWithClusterIdRequest) returns (RPCCountResponse);", + "doc": "计算需要升级的HTTPDNS节点数量", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "findAllUpgradeHTTPDNSNodesWithClusterId", + "requestMessageName": "FindAllUpgradeHTTPDNSNodesWithClusterIdRequest", + "responseMessageName": "FindAllUpgradeHTTPDNSNodesWithClusterIdResponse", + "code": "rpc findAllUpgradeHTTPDNSNodesWithClusterId (FindAllUpgradeHTTPDNSNodesWithClusterIdRequest) returns (FindAllUpgradeHTTPDNSNodesWithClusterIdResponse);", + "doc": "列出所有需要升级的HTTPDNS节点", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "upgradeHTTPDNSNode", + "requestMessageName": "UpgradeHTTPDNSNodeRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc upgradeHTTPDNSNode (UpgradeHTTPDNSNodeRequest) returns (RPCSuccess);", + "doc": "升级单个HTTPDNS节点", + "roles": [ + "admin" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_node.proto", + "doc": "" + }, + { + "name": "HTTPDNSRuleService", + "methods": [ + { + "name": "createHTTPDNSCustomRule", + "requestMessageName": "CreateHTTPDNSCustomRuleRequest", + "responseMessageName": "CreateHTTPDNSCustomRuleResponse", + "code": "rpc createHTTPDNSCustomRule (CreateHTTPDNSCustomRuleRequest) returns (CreateHTTPDNSCustomRuleResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSCustomRule", + "requestMessageName": "UpdateHTTPDNSCustomRuleRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSCustomRule (UpdateHTTPDNSCustomRuleRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "deleteHTTPDNSCustomRule", + "requestMessageName": "DeleteHTTPDNSCustomRuleRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc deleteHTTPDNSCustomRule (DeleteHTTPDNSCustomRuleRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "updateHTTPDNSCustomRuleStatus", + "requestMessageName": "UpdateHTTPDNSCustomRuleStatusRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc updateHTTPDNSCustomRuleStatus (UpdateHTTPDNSCustomRuleStatusRequest) returns (RPCSuccess);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSCustomRulesWithDomainId", + "requestMessageName": "ListHTTPDNSCustomRulesWithDomainIdRequest", + "responseMessageName": "ListHTTPDNSCustomRulesWithDomainIdResponse", + "code": "rpc listHTTPDNSCustomRulesWithDomainId (ListHTTPDNSCustomRulesWithDomainIdRequest) returns (ListHTTPDNSCustomRulesWithDomainIdResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_rule.proto", + "doc": "" + }, + { + "name": "HTTPDNSRuntimeLogService", + "methods": [ + { + "name": "createHTTPDNSRuntimeLogs", + "requestMessageName": "CreateHTTPDNSRuntimeLogsRequest", + "responseMessageName": "CreateHTTPDNSRuntimeLogsResponse", + "code": "rpc createHTTPDNSRuntimeLogs (CreateHTTPDNSRuntimeLogsRequest) returns (CreateHTTPDNSRuntimeLogsResponse);", + "doc": "", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "listHTTPDNSRuntimeLogs", + "requestMessageName": "ListHTTPDNSRuntimeLogsRequest", + "responseMessageName": "ListHTTPDNSRuntimeLogsResponse", + "code": "rpc listHTTPDNSRuntimeLogs (ListHTTPDNSRuntimeLogsRequest) returns (ListHTTPDNSRuntimeLogsResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_runtime_log.proto", + "doc": "" + }, + { + "name": "HTTPDNSSandboxService", + "methods": [ + { + "name": "testHTTPDNSResolve", + "requestMessageName": "TestHTTPDNSResolveRequest", + "responseMessageName": "TestHTTPDNSResolveResponse", + "code": "rpc testHTTPDNSResolve (TestHTTPDNSResolveRequest) returns (TestHTTPDNSResolveResponse);", + "doc": "", + "roles": [ + "admin", + "user" + ], + "isDeprecated": false + } + ], + "filename": "service_httpdns_sandbox.proto", + "doc": "" + }, { "name": "IPItemService", "methods": [ @@ -8505,6 +9063,28 @@ ], "isDeprecated": false }, + { + "name": "findAllUpgradeNSNodesWithNSClusterId", + "requestMessageName": "FindAllUpgradeNSNodesWithNSClusterIdRequest", + "responseMessageName": "FindAllUpgradeNSNodesWithNSClusterIdResponse", + "code": "rpc findAllUpgradeNSNodesWithNSClusterId (FindAllUpgradeNSNodesWithNSClusterIdRequest) returns (FindAllUpgradeNSNodesWithNSClusterIdResponse);", + "doc": "列出所有需要升级的NS节点", + "roles": [ + "admin" + ], + "isDeprecated": false + }, + { + "name": "upgradeNSNode", + "requestMessageName": "UpgradeNSNodeRequest", + "responseMessageName": "RPCSuccess", + "code": "rpc upgradeNSNode (UpgradeNSNodeRequest) returns (RPCSuccess);", + "doc": "升级单个NS节点", + "roles": [ + "admin" + ], + "isDeprecated": false + }, { "name": "createNSNode", "requestMessageName": "CreateNSNodeRequest", @@ -14382,6 +14962,16 @@ "code": "message CheckDBNodeStatusResponse {\n\tDBNodeStatus dbNodeStatus = 1;\n}", "doc": "" }, + { + "name": "CheckHTTPDNSNodeLatestVersionRequest", + "code": "message CheckHTTPDNSNodeLatestVersionRequest {\r\n\tstring os = 1;\r\n\tstring arch = 2;\r\n\tstring currentVersion = 3;\r\n}", + "doc": "检查HTTPDNS节点新版本" + }, + { + "name": "CheckHTTPDNSNodeLatestVersionResponse", + "code": "message CheckHTTPDNSNodeLatestVersionResponse {\r\n\tbool hasNewVersion = 1;\r\n\tstring newVersion = 2;\r\n}", + "doc": "" + }, { "name": "CheckHTTPFirewallPolicyIPStatusRequest", "code": "message CheckHTTPFirewallPolicyIPStatusRequest {\n\tint64 httpFirewallPolicyId = 1;\n\tstring ip = 2;\n}", @@ -14404,12 +14994,12 @@ }, { "name": "CheckNSNodeLatestVersionRequest", - "code": "message CheckNSNodeLatestVersionRequest {\n\tstring os = 1;\n\tstring arch = 2;\n\tstring currentVersion = 3;\n}", + "code": "message CheckNSNodeLatestVersionRequest {\r\n\tstring os = 1;\r\n\tstring arch = 2;\r\n\tstring currentVersion = 3;\r\n}", "doc": "检查NS节点新版本" }, { "name": "CheckNSNodeLatestVersionResponse", - "code": "message CheckNSNodeLatestVersionResponse {\n\tbool hasNewVersion = 1;\n\tstring newVersion = 2;\n}", + "code": "message CheckNSNodeLatestVersionResponse {\r\n\tbool hasNewVersion = 1;\r\n\tstring newVersion = 2;\r\n}", "doc": "" }, { @@ -14514,12 +15104,12 @@ }, { "name": "CheckUserEmailRequest", - "code": "message CheckUserEmailRequest {\n\tstring email = 1; // 邮箱地址\n}", + "code": "message CheckUserEmailRequest {\r\n\tstring email = 1; // 邮箱地址\r\n}", "doc": "检查邮箱是否已被验证" }, { "name": "CheckUserEmailResponse", - "code": "message CheckUserEmailResponse {\n\tbool exists = 1; // 是否已被使用\n}", + "code": "message CheckUserEmailResponse {\r\n\tbool exists = 1; // 是否已被使用\r\n}", "doc": "" }, { @@ -14534,22 +15124,22 @@ }, { "name": "CheckUserMobileRequest", - "code": "message CheckUserMobileRequest {\n\tstring mobile = 1; // 手机号码\n}", + "code": "message CheckUserMobileRequest {\r\n\tstring mobile = 1; // 手机号码\r\n}", "doc": "检查手机号码是否已被验证" }, { "name": "CheckUserMobileResponse", - "code": "message CheckUserMobileResponse {\n\tbool exists = 1; // 是否已被使用\n}", + "code": "message CheckUserMobileResponse {\r\n\tbool exists = 1; // 是否已被使用\r\n}", "doc": "" }, { "name": "CheckUserOTPWithUsernameRequest", - "code": "message CheckUserOTPWithUsernameRequest {\n\tstring username = 1;\n}", + "code": "message CheckUserOTPWithUsernameRequest {\r\n\tstring username = 1;\r\n}", "doc": "根据用户名检查是否需要输入OTP" }, { "name": "CheckUserOTPWithUsernameResponse", - "code": "message CheckUserOTPWithUsernameResponse {\n\tbool requireOTP = 1;\n}", + "code": "message CheckUserOTPWithUsernameResponse {\r\n\tbool requireOTP = 1;\r\n}", "doc": "" }, { @@ -14559,22 +15149,22 @@ }, { "name": "CheckUserServersStateRequest", - "code": "message CheckUserServersStateRequest {\n\tint64 userId = 1;\n}", + "code": "message CheckUserServersStateRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "检查用户服务可用状态" }, { "name": "CheckUserServersStateResponse", - "code": "message CheckUserServersStateResponse {\n\tbool isEnabled = 1;\n}", + "code": "message CheckUserServersStateResponse {\r\n\tbool isEnabled = 1;\r\n}", "doc": "" }, { "name": "CheckUserUsernameRequest", - "code": "message CheckUserUsernameRequest {\n\tint64 userId = 1;\n\tstring username = 2;\n}", + "code": "message CheckUserUsernameRequest {\r\n\tint64 userId = 1;\r\n\tstring username = 2;\r\n}", "doc": "检查用户名是否存在" }, { "name": "CheckUserUsernameResponse", - "code": "message CheckUserUsernameResponse {\n\tbool exists = 1;\n}", + "code": "message CheckUserUsernameResponse {\r\n\tbool exists = 1;\r\n}", "doc": "" }, { @@ -14642,6 +15232,11 @@ "code": "message ComposeFirewallGlobalBoardResponse {\n\tint64 countDailyLogs = 1;\n\tint64 countDailyBlocks = 2;\n\tint64 countDailyCaptcha = 3;\n\tint64 countWeeklyBlocks = 4;\n\n\trepeated HTTPFirewallRuleGroupStat httpFirewallRuleGroups = 30;\n\trepeated DailyStat dailyStats = 31;\n\trepeated HourlyStat hourlyStats = 32;\n\trepeated NodeStat topNodeStats = 33;\n\trepeated DomainStat topDomainStats = 34;\n\trepeated CountryStat topCountryStats = 35;\n\n\n\tmessage HTTPFirewallRuleGroupStat {\n\t\tHTTPFirewallRuleGroup httpFirewallRuleGroup = 1;\n\t\tint64 count = 2;\n\t}\n\n\n\tmessage HourlyStat {\n\t\tstring hour = 1;\n\t\tint64 countLogs = 2;\n\t\tint64 countCaptcha = 3;\n\t\tint64 countBlocks = 4;\n\t}\n\n\n\tmessage DailyStat {\n\t\tstring day = 1;\n\t\tint64 countLogs = 2;\n\t\tint64 countCaptcha = 3;\n\t\tint64 countBlocks = 4;\n\t}\n\n\n\tmessage NodeStat {\n\t\tint64 nodeId = 1;\n\t\tstring nodeName = 2;\n\t\tint64 countRequests = 3;\n\t\tint64 bytes = 4;\n\t\tint64 countAttackRequests = 6;\n\t\tint64 attackBytes = 7;\n\t}\n\n\n\tmessage DomainStat {\n\t\tint64 serverId = 1;\n\t\tstring domain = 2;\n\t\tint64 countRequests = 3;\n\t\tint64 bytes = 4;\n\t\tint64 countAttackRequests = 6;\n\t\tint64 attackBytes = 7;\n\t}\n\n\n\tmessage CountryStat {\n\t\tstring countryName = 1;\n\t\tint64 bytes = 2;\n\t\tint64 countRequests = 3;\n\t\tfloat percent = 4; // 流量占比\n\t\tint64 countAttackRequests = 6;\n\t\tint64 attackBytes = 7;\n\t}\n}", "doc": "" }, + { + "name": "ComposeHTTPDNSBoardResponse", + "code": "message ComposeHTTPDNSBoardResponse {\n\tint64 countApps = 1;\n\tint64 countDomains = 2;\n\tint64 countClusters = 3;\n\tint64 countNodes = 4;\n\tint64 countOfflineNodes = 5;\n\n\n\tmessage DailyTrafficStat {\n\t\tstring day = 1;\n\t\tint64 bytes = 2;\n\t\tint64 countRequests = 3;\n\t}\n\n\n\tmessage HourlyTrafficStat {\n\t\tstring hour = 1;\n\t\tint64 bytes = 2;\n\t\tint64 countRequests = 3;\n\t}\n\n\n\tmessage TopAppStat {\n\t\tint64 appId = 1;\n\t\tstring appName = 2;\n\t\tint64 countRequests = 3;\n\t\tint64 bytes = 4;\n\t}\n\n\n\tmessage TopDomainStat {\n\t\tint64 domainId = 1;\n\t\tstring domainName = 2;\n\t\tint64 countRequests = 3;\n\t\tint64 bytes = 4;\n\t}\n\n\n\tmessage TopNodeStat {\n\t\tint64 clusterId = 1;\n\t\tint64 nodeId = 2;\n\t\tstring nodeName = 3;\n\t\tint64 countRequests = 4;\n\t\tint64 bytes = 5;\n\t}\n\n\trepeated DailyTrafficStat dailyTrafficStats = 30;\n\trepeated HourlyTrafficStat hourlyTrafficStats = 31;\n\trepeated TopAppStat topAppStats = 32;\n\trepeated TopDomainStat topDomainStats = 33;\n\trepeated TopNodeStat topNodeStats = 34;\n\trepeated NodeValue cpuNodeValues = 35;\n\trepeated NodeValue memoryNodeValues = 36;\n\trepeated NodeValue loadNodeValues = 37;\n}", + "doc": "组合看板数据响应" + }, { "name": "ComposeNSBoardRequest", "code": "message ComposeNSBoardRequest {\n\n}", @@ -14724,22 +15319,22 @@ }, { "name": "ComposeUserDashboardRequest", - "code": "message ComposeUserDashboardRequest {\n\tint64 userId = 1;\n}", + "code": "message ComposeUserDashboardRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "取得用户Dashboard数据" }, { "name": "ComposeUserDashboardResponse", - "code": "message ComposeUserDashboardResponse {\n\tint64 countServers = 1;\n\tint64 monthlyTrafficBytes = 2;\n\tint64 monthlyPeekBandwidthBytes = 3;\n\tint64 dailyTrafficBytes = 4;\n\tint64 dailyPeekBandwidthBytes = 5;\n\trepeated DailyTrafficStat dailyTrafficStats = 6;\n\trepeated DailyPeekBandwidthStat dailyPeekBandwidthStats = 7;\n\tint32 bandwidthPercentile = 8; // 带宽百分位\n\tint64 bandwidthPercentileBits = 9; // 带宽百分位上的比特数\n\n\n\tmessage DailyTrafficStat {\n\t\tstring day = 1;\n\t\tint64 bytes = 2;\n\t\tint64 cachedBytes = 3;\n\t\tint64 attackBytes = 4;\n\t\tint64 countRequests = 5;\n\t\tint64 countCachedRequests = 6;\n\t\tint64 countAttackRequests = 7;\n\t}\n\n\n\tmessage DailyPeekBandwidthStat {\n\t\tstring day = 1;\n\t\tint64 bytes = 2;\n\t}\n}", + "code": "message ComposeUserDashboardResponse {\r\n\tint64 countServers = 1;\r\n\tint64 monthlyTrafficBytes = 2;\r\n\tint64 monthlyPeekBandwidthBytes = 3;\r\n\tint64 dailyTrafficBytes = 4;\r\n\tint64 dailyPeekBandwidthBytes = 5;\r\n\trepeated DailyTrafficStat dailyTrafficStats = 6;\r\n\trepeated DailyPeekBandwidthStat dailyPeekBandwidthStats = 7;\r\n\tint32 bandwidthPercentile = 8; // 带宽百分位\r\n\tint64 bandwidthPercentileBits = 9; // 带宽百分位上的比特数\r\n\n\r\n\tmessage DailyTrafficStat {\r\n\t\tstring day = 1;\r\n\t\tint64 bytes = 2;\r\n\t\tint64 cachedBytes = 3;\r\n\t\tint64 attackBytes = 4;\r\n\t\tint64 countRequests = 5;\r\n\t\tint64 countCachedRequests = 6;\r\n\t\tint64 countAttackRequests = 7;\r\n\t}\r\n\n\r\n\tmessage DailyPeekBandwidthStat {\r\n\t\tstring day = 1;\r\n\t\tint64 bytes = 2;\r\n\t}\r\n}", "doc": "" }, { "name": "ComposeUserGlobalBoardRequest", - "code": "message ComposeUserGlobalBoardRequest {\n\n}", + "code": "message ComposeUserGlobalBoardRequest {\r\n\r\n}", "doc": "组合看板数据" }, { "name": "ComposeUserGlobalBoardResponse", - "code": "message ComposeUserGlobalBoardResponse {\n\tint64 totalUsers = 1;\n\tint64 countTodayUsers = 2;\n\tint64 countWeeklyUsers = 3;\n\tint64 countUserNodes = 4;\n\tint64 countOfflineUserNodes = 5;\n\tint64 countVerifyingUsers = 6;\n\n\trepeated DailyStat dailyStats = 30;\n\trepeated NodeValue cpuNodeValues = 31;\n\trepeated NodeValue memoryNodeValues = 32;\n\trepeated NodeValue loadNodeValues = 33;\n\trepeated TrafficStat topTrafficStats = 34;\n\n\n\tmessage DailyStat {\n\t\tstring day = 1;\n\t\tint64 count = 2;\n\t}\n\n\n\tmessage TrafficStat {\n\t\tint64 userId = 1;\n\t\tstring userName = 2;\n\t\tint64 countRequests = 3;\n\t\tint64 bytes = 4;\n\t}\n}", + "code": "message ComposeUserGlobalBoardResponse {\r\n\tint64 totalUsers = 1;\r\n\tint64 countTodayUsers = 2;\r\n\tint64 countWeeklyUsers = 3;\r\n\tint64 countUserNodes = 4;\r\n\tint64 countOfflineUserNodes = 5;\r\n\tint64 countVerifyingUsers = 6;\r\n\r\n\trepeated DailyStat dailyStats = 30;\r\n\trepeated NodeValue cpuNodeValues = 31;\r\n\trepeated NodeValue memoryNodeValues = 32;\r\n\trepeated NodeValue loadNodeValues = 33;\r\n\trepeated TrafficStat topTrafficStats = 34;\r\n\n\r\n\tmessage DailyStat {\r\n\t\tstring day = 1;\r\n\t\tint64 count = 2;\r\n\t}\r\n\n\r\n\tmessage TrafficStat {\r\n\t\tint64 userId = 1;\r\n\t\tstring userName = 2;\r\n\t\tint64 countRequests = 3;\r\n\t\tint64 bytes = 4;\r\n\t}\r\n}", "doc": "" }, { @@ -15019,12 +15614,12 @@ }, { "name": "CountAllEnabledUsersRequest", - "code": "message CountAllEnabledUsersRequest {\n\tstring keyword = 1;\n\tbool isVerifying = 2;\n\tint32 mobileIsVerified = 3; // 手机号是否已验证,1表示已验证,0表示未验证,-1表示所有状态\n}", + "code": "message CountAllEnabledUsersRequest {\r\n\tstring keyword = 1;\r\n\tbool isVerifying = 2;\r\n\tint32 mobileIsVerified = 3; // 手机号是否已验证,1表示已验证,0表示未验证,-1表示所有状态\r\n}", "doc": "计算用户数量" }, { "name": "CountAllHTTPAccessLogPoliciesRequest", - "code": "message CountAllHTTPAccessLogPoliciesRequest {\n\n}", + "code": "message CountAllHTTPAccessLogPoliciesRequest {\r\n\r\n}", "doc": "计算访问日志策略数量" }, { @@ -15049,12 +15644,12 @@ }, { "name": "CountAllNSNodesMatchRequest", - "code": "message CountAllNSNodesMatchRequest {\n\tint64 nsClusterId = 1;\n\tint32 installState = 2;\n\tint32 activeState = 3;\n\tstring keyword = 4;\n\t//int64 nodeGroupId = 5;\n\t//int64 nodeRegionId = 6;\n}", + "code": "message CountAllNSNodesMatchRequest {\r\n\tint64 nsClusterId = 1;\r\n\tint32 installState = 2;\r\n\tint32 activeState = 3;\r\n\tstring keyword = 4;\r\n\t//int64 nodeGroupId = 5;\r\n\t//int64 nodeRegionId = 6;\r\n}", "doc": "计算匹配的NS节点数量" }, { "name": "CountAllNSNodesRequest", - "code": "message CountAllNSNodesRequest {\n\n}", + "code": "message CountAllNSNodesRequest {\r\n\r\n}", "doc": "所有可用的NS节点数量" }, { @@ -15112,9 +15707,14 @@ "code": "message CountAllServerNamesWithUserIdRequest {\n\tint64 userId = 1; // 用户ID\n\tint64 userPlanId = 2; // 用户套餐ID\n}", "doc": "计算一个用户下的所有域名数量" }, + { + "name": "CountAllUpgradeHTTPDNSNodesWithClusterIdRequest", + "code": "message CountAllUpgradeHTTPDNSNodesWithClusterIdRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "计算需要升级的HTTPDNS节点数量" + }, { "name": "CountAllUpgradeNSNodesWithNSClusterIdRequest", - "code": "message CountAllUpgradeNSNodesWithNSClusterIdRequest {\n\tint64 nsClusterId = 1;\n}", + "code": "message CountAllUpgradeNSNodesWithNSClusterIdRequest {\r\n\tint64 nsClusterId = 1;\r\n}", "doc": "计算需要升级的NS节点数量" }, { @@ -15479,12 +16079,12 @@ }, { "name": "CreateHTTPAccessLogPolicyRequest", - "code": "message CreateHTTPAccessLogPolicyRequest {\n\tstring name = 1;\n\tstring type = 2;\n\tbytes optionsJSON = 3;\n\tbytes condsJSON = 4;\n\tbool isPublic = 5;\n\tbool firewallOnly = 6;\n\tbool disableDefaultDB = 7;\n}", + "code": "message CreateHTTPAccessLogPolicyRequest {\r\n\tstring name = 1;\r\n\tstring type = 2;\r\n\tbytes optionsJSON = 3;\r\n\tbytes condsJSON = 4;\r\n\tbool isPublic = 5;\r\n\tbool firewallOnly = 6;\r\n\tbool disableDefaultDB = 7;\r\n\tbytes writeTargetsJSON = 8;\r\n}", "doc": "创建访问日志策略" }, { "name": "CreateHTTPAccessLogPolicyResponse", - "code": "message CreateHTTPAccessLogPolicyResponse {\n\tint64 httpAccessLogPolicyId = 1;\n}", + "code": "message CreateHTTPAccessLogPolicyResponse {\r\n\tint64 httpAccessLogPolicyId = 1;\r\n}", "doc": "" }, { @@ -15527,6 +16127,76 @@ "code": "message CreateHTTPCacheTaskResponse {\n\tint64 httpCacheTaskId = 1; // 生成的任务ID\n\tint64 countKeys = 2; // 任务中包含的Key\n}", "doc": "" }, + { + "name": "CreateHTTPDNSAccessLogsRequest", + "code": "message CreateHTTPDNSAccessLogsRequest {\r\n\trepeated HTTPDNSAccessLog logs = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSAccessLogsResponse", + "code": "message CreateHTTPDNSAccessLogsResponse {\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSAppRequest", + "code": "message CreateHTTPDNSAppRequest {\r\n\tstring name = 1;\r\n\tstring appId = 2;\r\n\treserved 3, 4; // removed: primaryClusterId, backupClusterId\r\n\tbool isOn = 5;\r\n\tbool signEnabled = 6;\r\n\tint64 userId = 7;\r\n\tbytes clusterIdsJSON = 8;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSAppResponse", + "code": "message CreateHTTPDNSAppResponse {\r\n\tint64 appDbId = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSClusterRequest", + "code": "message CreateHTTPDNSClusterRequest {\r\n\tstring name = 1;\r\n\tstring serviceDomain = 2;\r\n\tint32 defaultTTL = 3;\r\n\tint32 fallbackTimeoutMs = 4;\r\n\tstring installDir = 5;\r\n\tbytes tlsPolicyJSON = 6;\r\n\tbool isOn = 7;\r\n\tbool isDefault = 8;\r\n\tbool autoRemoteStart = 9;\r\n\tbool accessLogIsOn = 10;\r\n\tstring timeZone = 11;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSClusterResponse", + "code": "message CreateHTTPDNSClusterResponse {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSCustomRuleRequest", + "code": "message CreateHTTPDNSCustomRuleRequest {\r\n\tHTTPDNSCustomRule rule = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSCustomRuleResponse", + "code": "message CreateHTTPDNSCustomRuleResponse {\r\n\tint64 ruleId = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSDomainRequest", + "code": "message CreateHTTPDNSDomainRequest {\r\n\tint64 appDbId = 1;\r\n\tstring domain = 2;\r\n\tbool isOn = 3;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSDomainResponse", + "code": "message CreateHTTPDNSDomainResponse {\r\n\tint64 domainId = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSNodeRequest", + "code": "message CreateHTTPDNSNodeRequest {\r\n\tint64 clusterId = 1;\r\n\tstring name = 2;\r\n\tstring installDir = 3;\r\n\tbool isOn = 4;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSNodeResponse", + "code": "message CreateHTTPDNSNodeResponse {\r\n\tint64 nodeId = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSRuntimeLogsRequest", + "code": "message CreateHTTPDNSRuntimeLogsRequest {\r\n\trepeated HTTPDNSRuntimeLog logs = 1;\r\n}", + "doc": "" + }, + { + "name": "CreateHTTPDNSRuntimeLogsResponse", + "code": "message CreateHTTPDNSRuntimeLogsResponse {\r\n}", + "doc": "" + }, { "name": "CreateHTTPFastcgiRequest", "code": "message CreateHTTPFastcgiRequest {\n\tbool isOn = 1;\n\tstring address = 2;\n\tbytes paramsJSON = 3;\n\tbytes readTimeoutJSON = 4;\n\tbytes connTimeoutJSON = 5;\n\tint32 poolSize = 6;\n\tstring pathInfoPattern = 7;\n}", @@ -15839,12 +16509,12 @@ }, { "name": "CreateNSNodeRequest", - "code": "message CreateNSNodeRequest {\n\tstring name = 1;\n\tint64 nodeClusterId = 2;\n\tNodeLogin nodeLogin = 3;\n}", + "code": "message CreateNSNodeRequest {\r\n\tstring name = 1;\r\n\tint64 nodeClusterId = 2;\r\n\tNodeLogin nodeLogin = 3;\r\n}", "doc": "创建NS节点" }, { "name": "CreateNSNodeResponse", - "code": "message CreateNSNodeResponse {\n\tint64 nsNodeId = 1;\n}", + "code": "message CreateNSNodeResponse {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "" }, { @@ -16284,12 +16954,12 @@ }, { "name": "CreateUserRequest", - "code": "message CreateUserRequest {\n\tstring username = 1;\n\tstring password = 2;\n\tstring fullname = 3;\n\tstring mobile = 4;\n\tstring tel = 5;\n\tstring email = 6;\n\tstring remark = 7;\n\tstring source = 8;\n\tint64 nodeClusterId = 9;\n}", + "code": "message CreateUserRequest {\r\n\tstring username = 1;\r\n\tstring password = 2;\r\n\tstring fullname = 3;\r\n\tstring mobile = 4;\r\n\tstring tel = 5;\r\n\tstring email = 6;\r\n\tstring remark = 7;\r\n\tstring source = 8;\r\n\tint64 nodeClusterId = 9;\r\n}", "doc": "创建用户" }, { "name": "CreateUserResponse", - "code": "message CreateUserResponse {\n\tint64 userId = 1;\n}", + "code": "message CreateUserResponse {\r\n\tint64 userId = 1;\r\n}", "doc": "" }, { @@ -16474,7 +17144,7 @@ }, { "name": "DeleteHTTPAccessLogPolicyRequest", - "code": "message DeleteHTTPAccessLogPolicyRequest {\n\tint64 httpAccessLogPolicyId = 1;\n}", + "code": "message DeleteHTTPAccessLogPolicyRequest {\r\n\tint64 httpAccessLogPolicyId = 1;\r\n}", "doc": "删除策略" }, { @@ -16487,6 +17157,31 @@ "code": "message DeleteHTTPCacheTaskRequest {\n\tint64 httpCacheTaskId = 1; // 任务ID\n}", "doc": "删除任务" }, + { + "name": "DeleteHTTPDNSAppRequest", + "code": "message DeleteHTTPDNSAppRequest {\r\n\tint64 appDbId = 1;\r\n}", + "doc": "" + }, + { + "name": "DeleteHTTPDNSClusterRequest", + "code": "message DeleteHTTPDNSClusterRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "DeleteHTTPDNSCustomRuleRequest", + "code": "message DeleteHTTPDNSCustomRuleRequest {\r\n\tint64 ruleId = 1;\r\n}", + "doc": "" + }, + { + "name": "DeleteHTTPDNSDomainRequest", + "code": "message DeleteHTTPDNSDomainRequest {\r\n\tint64 domainId = 1;\r\n}", + "doc": "" + }, + { + "name": "DeleteHTTPDNSNodeRequest", + "code": "message DeleteHTTPDNSNodeRequest {\r\n\tint64 nodeId = 1;\r\n}", + "doc": "" + }, { "name": "DeleteHTTPFirewallPolicyRequest", "code": "message DeleteHTTPFirewallPolicyRequest {\n\tint64 httpFirewallPolicyId = 1;\n}", @@ -16609,7 +17304,7 @@ }, { "name": "DeleteNSNodeRequest", - "code": "message DeleteNSNodeRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message DeleteNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "删除NS节点" }, { @@ -16804,7 +17499,7 @@ }, { "name": "DeleteUserRequest", - "code": "message DeleteUserRequest {\n\tint64 userId = 1;\n}", + "code": "message DeleteUserRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "删除用户" }, { @@ -16877,14 +17572,24 @@ "code": "message DownloadFileChunkResponse {\n\tFileChunk fileChunk = 1;\n}", "doc": "" }, + { + "name": "DownloadHTTPDNSNodeInstallationFileRequest", + "code": "message DownloadHTTPDNSNodeInstallationFileRequest {\r\n\tstring os = 1;\r\n\tstring arch = 2;\r\n\tint64 chunkOffset = 3;\r\n}", + "doc": "下载最新HTTPDNS节点安装文件" + }, + { + "name": "DownloadHTTPDNSNodeInstallationFileResponse", + "code": "message DownloadHTTPDNSNodeInstallationFileResponse {\r\n\tbytes chunkData = 1;\r\n\tstring sum = 2;\r\n\tint64 offset = 3;\r\n\tstring version = 4;\r\n\tstring filename = 5;\r\n}", + "doc": "" + }, { "name": "DownloadNSNodeInstallationFileRequest", - "code": "message DownloadNSNodeInstallationFileRequest {\n\tstring os = 1;\n\tstring arch = 2;\n\tint64 chunkOffset = 3;\n}", + "code": "message DownloadNSNodeInstallationFileRequest {\r\n\tstring os = 1;\r\n\tstring arch = 2;\r\n\tint64 chunkOffset = 3;\r\n}", "doc": "下载最新NS节点安装文件" }, { "name": "DownloadNSNodeInstallationFileResponse", - "code": "message DownloadNSNodeInstallationFileResponse {\n\tbytes chunkData = 1;\n\tstring sum = 2; // 文件的md5sum\n\tint64 offset = 3;\n\tstring version = 4;\n\tstring filename = 5;\n}", + "code": "message DownloadNSNodeInstallationFileResponse {\r\n\tbytes chunkData = 1;\r\n\tstring sum = 2; // 文件的md5sum\r\n\tint64 offset = 3;\r\n\tstring version = 4;\r\n\tstring filename = 5;\r\n}", "doc": "" }, { @@ -17907,6 +18612,26 @@ "code": "message FindAllFinishedIPLibraryFilesResponse {\n\trepeated IPLibraryFile ipLibraryFiles = 1;\n}", "doc": "" }, + { + "name": "FindAllHTTPDNSAppsRequest", + "code": "message FindAllHTTPDNSAppsRequest {\r\n}", + "doc": "" + }, + { + "name": "FindAllHTTPDNSAppsResponse", + "code": "message FindAllHTTPDNSAppsResponse {\r\n\trepeated HTTPDNSApp apps = 1;\r\n}", + "doc": "" + }, + { + "name": "FindAllHTTPDNSClustersRequest", + "code": "message FindAllHTTPDNSClustersRequest {\r\n}", + "doc": "" + }, + { + "name": "FindAllHTTPDNSClustersResponse", + "code": "message FindAllHTTPDNSClustersResponse {\r\n\trepeated HTTPDNSCluster clusters = 1;\r\n}", + "doc": "" + }, { "name": "FindAllIPLibraryArtifactsRequest", "code": "message FindAllIPLibraryArtifactsRequest {\n\n}", @@ -17959,12 +18684,12 @@ }, { "name": "FindAllNSNodesWithNSClusterIdRequest", - "code": "message FindAllNSNodesWithNSClusterIdRequest {\n\tint64 nsClusterId = 1;\n}", + "code": "message FindAllNSNodesWithNSClusterIdRequest {\r\n\tint64 nsClusterId = 1;\r\n}", "doc": "根据集群查找所有NS节点" }, { "name": "FindAllNSNodesWithNSClusterIdResponse", - "code": "message FindAllNSNodesWithNSClusterIdResponse {\n\trepeated NSNode nsNodes = 1;\n}", + "code": "message FindAllNSNodesWithNSClusterIdResponse {\r\n\trepeated NSNode nsNodes = 1;\r\n}", "doc": "" }, { @@ -18197,6 +18922,26 @@ "code": "message FindAllUnfinishedIPLibraryFilesResponse {\n\trepeated IPLibraryFile ipLibraryFiles = 1;\n}", "doc": "" }, + { + "name": "FindAllUpgradeHTTPDNSNodesWithClusterIdRequest", + "code": "message FindAllUpgradeHTTPDNSNodesWithClusterIdRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "列出所有需要升级的HTTPDNS节点" + }, + { + "name": "FindAllUpgradeHTTPDNSNodesWithClusterIdResponse", + "code": "message FindAllUpgradeHTTPDNSNodesWithClusterIdResponse {\r\n\trepeated HTTPDNSNodeUpgrade nodes = 1;\r\n\n\r\n\tmessage HTTPDNSNodeUpgrade {\r\n\t\tHTTPDNSNode node = 1;\r\n\t\tstring os = 2;\r\n\t\tstring arch = 3;\r\n\t\tstring oldVersion = 4;\r\n\t\tstring newVersion = 5;\r\n\t}\r\n}", + "doc": "" + }, + { + "name": "FindAllUpgradeNSNodesWithNSClusterIdRequest", + "code": "message FindAllUpgradeNSNodesWithNSClusterIdRequest {\r\n\tint64 nsClusterId = 1;\r\n}", + "doc": "列出所有需要升级的NS节点" + }, + { + "name": "FindAllUpgradeNSNodesWithNSClusterIdResponse", + "code": "message FindAllUpgradeNSNodesWithNSClusterIdResponse {\r\n\trepeated NSNodeUpgrade nodes = 1;\r\n\n\r\n\tmessage NSNodeUpgrade {\r\n\t\tNSNode nsNode = 1;\r\n\t\tstring os = 2;\r\n\t\tstring arch = 3;\r\n\t\tstring oldVersion = 4;\r\n\t\tstring newVersion = 5;\r\n\t}\r\n}", + "doc": "" + }, { "name": "FindAllUpgradeNodesWithNodeClusterIdRequest", "code": "message FindAllUpgradeNodesWithNodeClusterIdRequest {\n\tint64 nodeClusterId = 1;\n}", @@ -18209,12 +18954,12 @@ }, { "name": "FindAllUserFeatureDefinitionsRequest", - "code": "message FindAllUserFeatureDefinitionsRequest {\n\n}", + "code": "message FindAllUserFeatureDefinitionsRequest {\r\n\r\n}", "doc": "获取所有的功能定义" }, { "name": "FindAllUserFeatureDefinitionsResponse", - "code": "message FindAllUserFeatureDefinitionsResponse {\n\trepeated UserFeature features = 1;\n}", + "code": "message FindAllUserFeatureDefinitionsResponse {\r\n\trepeated UserFeature features = 1;\r\n}", "doc": "" }, { @@ -18364,12 +19109,12 @@ }, { "name": "FindCurrentNSNodeConfigRequest", - "code": "message FindCurrentNSNodeConfigRequest {\n\n}", + "code": "message FindCurrentNSNodeConfigRequest {\r\n\r\n}", "doc": "获取当前NS节点信息" }, { "name": "FindCurrentNSNodeConfigResponse", - "code": "message FindCurrentNSNodeConfigResponse {\n\tbytes nsNodeJSON = 1;\n}", + "code": "message FindCurrentNSNodeConfigResponse {\r\n\tbytes nsNodeJSON = 1;\r\n}", "doc": "" }, { @@ -19324,12 +20069,12 @@ }, { "name": "FindEnabledUserRequest", - "code": "message FindEnabledUserRequest {\n\tint64 userId = 1;\n}", + "code": "message FindEnabledUserRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "查询单个用户信息" }, { "name": "FindEnabledUserResponse", - "code": "message FindEnabledUserResponse {\n\tUser user = 1;\n}", + "code": "message FindEnabledUserResponse {\r\n\tUser user = 1;\r\n}", "doc": "" }, { @@ -19384,12 +20129,12 @@ }, { "name": "FindHTTPAccessLogPolicyRequest", - "code": "message FindHTTPAccessLogPolicyRequest {\n\tint64 httpAccessLogPolicyId = 1;\n}", + "code": "message FindHTTPAccessLogPolicyRequest {\r\n\tint64 httpAccessLogPolicyId = 1;\r\n}", "doc": "查找单个访问日志策略" }, { "name": "FindHTTPAccessLogPolicyResponse", - "code": "message FindHTTPAccessLogPolicyResponse {\n\tHTTPAccessLogPolicy httpAccessLogPolicy = 1;\n}", + "code": "message FindHTTPAccessLogPolicyResponse {\r\n\tHTTPAccessLogPolicy httpAccessLogPolicy = 1;\r\n}", "doc": "" }, { @@ -19402,6 +20147,36 @@ "code": "message FindHTTPAccessLogResponse {\n\tHTTPAccessLog httpAccessLog = 1;\n}", "doc": "" }, + { + "name": "FindHTTPDNSAppRequest", + "code": "message FindHTTPDNSAppRequest {\r\n\tint64 appDbId = 1;\r\n}", + "doc": "" + }, + { + "name": "FindHTTPDNSAppResponse", + "code": "message FindHTTPDNSAppResponse {\r\n\tHTTPDNSApp app = 1;\r\n}", + "doc": "" + }, + { + "name": "FindHTTPDNSClusterRequest", + "code": "message FindHTTPDNSClusterRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "FindHTTPDNSClusterResponse", + "code": "message FindHTTPDNSClusterResponse {\r\n\tHTTPDNSCluster cluster = 1;\r\n}", + "doc": "" + }, + { + "name": "FindHTTPDNSNodeRequest", + "code": "message FindHTTPDNSNodeRequest {\r\n\tint64 nodeId = 1;\r\n}", + "doc": "" + }, + { + "name": "FindHTTPDNSNodeResponse", + "code": "message FindHTTPDNSNodeResponse {\r\n\tHTTPDNSNode node = 1;\r\n}", + "doc": "" + }, { "name": "FindHTTPWebCCRequest", "code": "message FindHTTPWebCCRequest {\n\tint64 httpWebId = 1;\n}", @@ -19544,12 +20319,12 @@ }, { "name": "FindLatestNSNodeVersionRequest", - "code": "message FindLatestNSNodeVersionRequest {\n\n}", + "code": "message FindLatestNSNodeVersionRequest {\r\n\r\n}", "doc": "取得最新的版本号" }, { "name": "FindLatestNSNodeVersionResponse", - "code": "message FindLatestNSNodeVersionResponse {\n\tstring version = 1;\n}", + "code": "message FindLatestNSNodeVersionResponse {\r\n\tstring version = 1;\r\n}", "doc": "" }, { @@ -19864,42 +20639,42 @@ }, { "name": "FindNSNodeAPIConfigRequest", - "code": "message FindNSNodeAPIConfigRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message FindNSNodeAPIConfigRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "查找单个节点的API相关配置" }, { "name": "FindNSNodeAPIConfigResponse", - "code": "message FindNSNodeAPIConfigResponse {\n\tbytes apiNodeAddrsJSON = 1;\n}", + "code": "message FindNSNodeAPIConfigResponse {\r\n\tbytes apiNodeAddrsJSON = 1;\r\n}", "doc": "" }, { "name": "FindNSNodeDDoSProtectionRequest", - "code": "message FindNSNodeDDoSProtectionRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message FindNSNodeDDoSProtectionRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "获取NS节点的DDoS设置" }, { "name": "FindNSNodeDDoSProtectionResponse", - "code": "message FindNSNodeDDoSProtectionResponse {\n\tbytes ddosProtectionJSON = 1;\n}", + "code": "message FindNSNodeDDoSProtectionResponse {\r\n\tbytes ddosProtectionJSON = 1;\r\n}", "doc": "" }, { "name": "FindNSNodeInstallStatusRequest", - "code": "message FindNSNodeInstallStatusRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message FindNSNodeInstallStatusRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "读取NS节点安装状态" }, { "name": "FindNSNodeInstallStatusResponse", - "code": "message FindNSNodeInstallStatusResponse {\n\tNodeInstallStatus installStatus = 1;\n}", + "code": "message FindNSNodeInstallStatusResponse {\r\n\tNodeInstallStatus installStatus = 1;\r\n}", "doc": "" }, { "name": "FindNSNodeRequest", - "code": "message FindNSNodeRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message FindNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "获取单个NS节点信息" }, { "name": "FindNSNodeResponse", - "code": "message FindNSNodeResponse {\n\tNSNode nsNode = 1;\n}", + "code": "message FindNSNodeResponse {\r\n\tNSNode nsNode = 1;\r\n}", "doc": "" }, { @@ -20609,12 +21384,12 @@ }, { "name": "FindUserFeaturesRequest", - "code": "message FindUserFeaturesRequest {\n\tint64 userId = 1;\n}", + "code": "message FindUserFeaturesRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "获取用户所有的功能列表" }, { "name": "FindUserFeaturesResponse", - "code": "message FindUserFeaturesResponse {\n\trepeated UserFeature features = 1;\n}", + "code": "message FindUserFeaturesResponse {\r\n\trepeated UserFeature features = 1;\r\n}", "doc": "" }, { @@ -20629,22 +21404,22 @@ }, { "name": "FindUserNodeClusterIdRequest", - "code": "message FindUserNodeClusterIdRequest {\n\tint64 userId = 1;\n}", + "code": "message FindUserNodeClusterIdRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "获取用户所在的集群ID" }, { "name": "FindUserNodeClusterIdResponse", - "code": "message FindUserNodeClusterIdResponse {\n\tint64 nodeClusterId = 1;\n}", + "code": "message FindUserNodeClusterIdResponse {\r\n\tint64 nodeClusterId = 1;\r\n}", "doc": "" }, { "name": "FindUserPriceInfoRequest", - "code": "message FindUserPriceInfoRequest {\n\tint64 userId = 1;\n}", + "code": "message FindUserPriceInfoRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "读取用户计费信息" }, { "name": "FindUserPriceInfoResponse", - "code": "message FindUserPriceInfoResponse {\n\tstring priceType = 1;\n\tstring pricePeriod = 2;\n}", + "code": "message FindUserPriceInfoResponse {\r\n\tstring priceType = 1;\r\n\tstring pricePeriod = 2;\r\n}", "doc": "" }, { @@ -20699,12 +21474,12 @@ }, { "name": "FindUserVerifiedEmailWithUsernameRequest", - "code": "message FindUserVerifiedEmailWithUsernameRequest {\n\tstring username = 1; // 用户名\n}", + "code": "message FindUserVerifiedEmailWithUsernameRequest {\r\n\tstring username = 1; // 用户名\r\n}", "doc": "根据用户名查询用户绑定的邮箱" }, { "name": "FindUserVerifiedEmailWithUsernameResponse", - "code": "message FindUserVerifiedEmailWithUsernameResponse {\n\tstring email = 1; // 已绑定邮箱地址\n}", + "code": "message FindUserVerifiedEmailWithUsernameResponse {\r\n\tstring email = 1; // 已绑定邮箱地址\r\n}", "doc": "" }, { @@ -20767,11 +21542,6 @@ "code": "message HTTPAccessLog {\n\tstring requestId = 48;\n\n\tint64 serverId = 1;\n\tint64 nodeId = 2;\n\tint64 locationId = 3;\n\tint64 rewriteId = 4;\n\tint64 originId = 5;\n\n\tstring remoteAddr = 6;\n\tstring rawRemoteAddr = 7;\n\tint32 remotePort = 8;\n\tstring remoteUser = 9;\n\tstring requestURI = 10;\n\tstring requestPath = 11;\n\tint64 requestLength = 12;\n\tdouble requestTime = 13;\n\tstring requestMethod = 14;\n\tstring requestFilename = 15;\n\tbytes requestBody = 51;\n\tstring scheme = 16;\n\tstring proto = 17;\n\tint64 bytesSent = 18;\n\tint64 bodyBytesSent = 19;\n\tint32 status = 20;\n\tstring statusMessage = 21;\n\tmap\u003cstring, Strings\u003e sentHeader = 22;\n\n\tstring timeISO8601 = 23;\n\tstring timeLocal = 24;\n\tdouble msec = 25;\n\tint64 timestamp = 26;\n\tstring host = 27;\n\tstring referer = 28;\n\tstring userAgent = 29;\n\tstring request = 30;\n\tstring contentType = 31;\n\tmap\u003cstring, string\u003e cookie = 32;\n\tstring args = 34;\n\tstring queryString = 35;\n\tmap\u003cstring, Strings\u003e header = 36;\n\tstring serverName = 37;\n\tint32 serverPort = 38;\n\tstring serverProtocol = 39;\n\tstring hostname = 40;\n\n\t// 源站相关\n\tstring originAddress = 41;\n\tint32 originStatus = 52;\n\n\t// 错误信息\n\trepeated string errors = 42;\n\n\t// 扩展\n\tmap\u003cstring, string\u003e attrs = 43;\n\n\t// WAF相关\n\tint64 firewallPolicyId = 44;\n\tint64 firewallRuleGroupId = 45;\n\tint64 firewallRuleSetId = 46;\n\tint64 firewallRuleId = 47;\n\n\trepeated string firewallActions = 49;\n\trepeated string tags = 50;\n\n\t// 详情\n\tNode node = 100;\n\n}", "doc": "HTTP访问日志" }, - { - "name": "HTTPAccessLogPolicy", - "code": "message HTTPAccessLogPolicy {\n\tint64 id = 1; // 策略ID\n\tstring name = 2; // 策略名称\n\tbool isOn = 3; // 是否启用\n\tstring type = 4; // 策略类型\n\tbytes optionsJSON = 5; // 策略选项\n\tbytes condsJSON = 6; // 记录条件选项\n\tbool isPublic = 7; // 是否公用\n\tbool firewallOnly = 8; // 是否只记录WAF相关访问日志\n\tbool disableDefaultDB = 9; // 停用默认数据库存储\n}", - "doc": "" - }, { "name": "HTTPAuthPolicy", "code": "message HTTPAuthPolicy {\n\tint64 id = 1;\n\tbool isOn = 2;\n\tstring name = 3;\n\tstring type = 4;\n\tbytes paramsJSON = 5;\n}", @@ -20792,6 +21562,51 @@ "code": "message HTTPCacheTaskKey {\n\tint64 id = 1; // 缓存键ID\n\tint64 taskId = 2; // 任务ID\n\tstring key = 3; // 缓存键\n\tstring type = 4; // 操作类型:purge|fetch\n\tstring keyType = 5; // 键类型:key|prefix\n\tbool isDone = 6; // 是否已完成\n\tbool isDoing = 9; // 是否执行中\n\tbytes errorsJSON = 7; // 错误信息\n\tint64 nodeClusterId = 8; // 所属集群ID\n\n\tNodeCluster nodeCluster = 30; // 所属集群,不一定有内容\n}", "doc": "" }, + { + "name": "HTTPDNSAccessLog", + "code": "message HTTPDNSAccessLog {\r\n\tint64 id = 1;\r\n\tstring requestId = 2;\r\n\tint64 clusterId = 3;\r\n\tint64 nodeId = 4;\r\n\tstring appId = 5;\r\n\tstring appName = 6;\r\n\tstring domain = 7;\r\n\tstring qtype = 8;\r\n\tstring clientIP = 9;\r\n\tstring clientRegion = 10;\r\n\tstring carrier = 11;\r\n\tstring sdkVersion = 12;\r\n\tstring os = 13;\r\n\tstring resultIPs = 14;\r\n\tstring status = 15;\r\n\tstring errorCode = 16;\r\n\tint32 costMs = 17;\r\n\tint64 createdAt = 18;\r\n\tstring day = 19;\r\n\tstring summary = 20;\r\n\tstring nodeName = 21;\r\n\tstring clusterName = 22;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSApp", + "code": "message HTTPDNSApp {\r\n\tint64 id = 1;\r\n\tstring name = 2;\r\n\tstring appId = 3;\r\n\tbool isOn = 4;\r\n\treserved 5, 6; // removed: primaryClusterId, backupClusterId\r\n\tstring sniMode = 7;\r\n\tbool signEnabled = 8;\r\n\tstring signSecret = 9;\r\n\tint64 signUpdatedAt = 10;\r\n\tint64 createdAt = 11;\r\n\tint64 updatedAt = 12;\r\n\tint64 userId = 13;\r\n\tbytes clusterIdsJSON = 14;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSCluster", + "code": "message HTTPDNSCluster {\r\n\tint64 id = 1;\r\n\tbool isOn = 2;\r\n\tbool isDefault = 3;\r\n\tstring name = 4;\r\n\tstring serviceDomain = 5;\r\n\tint32 defaultTTL = 6;\r\n\tint32 fallbackTimeoutMs = 7;\r\n\tstring installDir = 8;\r\n\tbytes tlsPolicyJSON = 9;\r\n\tint64 createdAt = 10;\r\n\tint64 updatedAt = 11;\r\n\tbool autoRemoteStart = 12;\r\n\tbool accessLogIsOn = 13;\r\n\tstring timeZone = 14;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSCustomRule", + "code": "message HTTPDNSCustomRule {\r\n\tint64 id = 1;\r\n\tint64 appId = 2;\r\n\tint64 domainId = 3;\r\n\tstring ruleName = 4;\r\n\tstring lineScope = 5;\r\n\tstring lineCarrier = 6;\r\n\tstring lineRegion = 7;\r\n\tstring lineProvince = 8;\r\n\tstring lineContinent = 9;\r\n\tstring lineCountry = 10;\r\n\tint32 ttl = 11;\r\n\tbool isOn = 12;\r\n\tint32 priority = 13;\r\n\tint64 updatedAt = 14;\r\n\trepeated HTTPDNSRuleRecord records = 15;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSDomain", + "code": "message HTTPDNSDomain {\r\n\tint64 id = 1;\r\n\tint64 appId = 2;\r\n\tstring domain = 3;\r\n\tbool isOn = 4;\r\n\tint64 createdAt = 5;\r\n\tint64 updatedAt = 6;\r\n\tint64 ruleCount = 7;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSNode", + "code": "message HTTPDNSNode {\r\n\tint64 id = 1;\r\n\tint64 clusterId = 2;\r\n\tstring name = 3;\r\n\tbool isOn = 4;\r\n\tbool isUp = 5;\r\n\tbool isInstalled = 6;\r\n\tbool isActive = 7;\r\n\tstring uniqueId = 8;\r\n\tstring secret = 9;\r\n\tstring installDir = 10;\r\n\tbytes statusJSON = 11;\r\n\tbytes installStatusJSON = 12;\r\n\tint64 createdAt = 13;\r\n\tint64 updatedAt = 14;\r\n\tNodeLogin nodeLogin = 15;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSResolveRecord", + "code": "message HTTPDNSResolveRecord {\r\n\tstring type = 1;\r\n\tstring ip = 2;\r\n\tint32 ttl = 3;\r\n\tint32 weight = 4;\r\n\tstring line = 5;\r\n\tstring region = 6;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSRuleRecord", + "code": "message HTTPDNSRuleRecord {\r\n\tint64 id = 1;\r\n\tint64 ruleId = 2;\r\n\tstring recordType = 3;\r\n\tstring recordValue = 4;\r\n\tint32 weight = 5;\r\n\tint32 sort = 6;\r\n}", + "doc": "" + }, + { + "name": "HTTPDNSRuntimeLog", + "code": "message HTTPDNSRuntimeLog {\r\n\tint64 id = 1;\r\n\tint64 clusterId = 2;\r\n\tint64 nodeId = 3;\r\n\tstring level = 4;\r\n\tstring type = 5;\r\n\tstring module = 6;\r\n\tstring description = 7;\r\n\tint64 count = 8;\r\n\tstring requestId = 9;\r\n\tint64 createdAt = 10;\r\n\tstring day = 11;\r\n\tstring clusterName = 12;\r\n\tstring nodeName = 13;\r\n}", + "doc": "" + }, { "name": "HTTPFastcgi", "code": "message HTTPFastcgi {\n\tint64 id = 1;\n\tbool isOn = 2;\n\tstring address = 3;\n\tbytes paramsJSON = 4;\n\tbytes readTimeoutJSON = 5;\n\tbytes connTimeoutJSON = 6;\n\tint32 poolSize = 7;\n\tstring pathInfoPattern = 8;\n}", @@ -20879,12 +21694,12 @@ }, { "name": "InstallNSNodeRequest", - "code": "message InstallNSNodeRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message InstallNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "安装NS节点" }, { "name": "InstallNSNodeResponse", - "code": "message InstallNSNodeResponse {\n\n}", + "code": "message InstallNSNodeResponse {\r\n\r\n}", "doc": "" }, { @@ -21209,12 +22024,12 @@ }, { "name": "ListEnabledUsersRequest", - "code": "message ListEnabledUsersRequest {\n\tstring keyword = 1;\n\tbool isVerifying = 4;\n\tint32 mobileIsVerified = 5; // 手机号是否已验证,1表示已验证,0表示未验证,-1表示所有状态\n\tint64 offset = 2;\n\tint64 size = 3;\n}", + "code": "message ListEnabledUsersRequest {\r\n\tstring keyword = 1;\r\n\tbool isVerifying = 4;\r\n\tint32 mobileIsVerified = 5; // 手机号是否已验证,1表示已验证,0表示未验证,-1表示所有状态\r\n\tint64 offset = 2;\r\n\tint64 size = 3;\r\n}", "doc": "列出单页用户" }, { "name": "ListEnabledUsersResponse", - "code": "message ListEnabledUsersResponse {\n\trepeated User users = 1;\n}", + "code": "message ListEnabledUsersResponse {\r\n\trepeated User users = 1;\r\n}", "doc": "" }, { @@ -21239,12 +22054,12 @@ }, { "name": "ListHTTPAccessLogPoliciesRequest", - "code": "message ListHTTPAccessLogPoliciesRequest {\n\tint64 offset = 1;\n\tint64 size = 2;\n}", + "code": "message ListHTTPAccessLogPoliciesRequest {\r\n\tint64 offset = 1;\r\n\tint64 size = 2;\r\n}", "doc": "列出单页访问日志策略" }, { "name": "ListHTTPAccessLogPoliciesResponse", - "code": "message ListHTTPAccessLogPoliciesResponse {\n\trepeated HTTPAccessLogPolicy httpAccessLogPolicies = 1;\n}", + "code": "message ListHTTPAccessLogPoliciesResponse {\r\n\trepeated HTTPAccessLogPolicy httpAccessLogPolicies = 1;\r\n}", "doc": "" }, { @@ -21267,6 +22082,86 @@ "code": "message ListHTTPCacheTasksResponse {\n\trepeated HTTPCacheTask httpCacheTasks = 1; // 一组任务信息\n}", "doc": "" }, + { + "name": "ListHTTPDNSAccessLogsRequest", + "code": "message ListHTTPDNSAccessLogsRequest {\r\n\tstring day = 1;\r\n\tint64 clusterId = 2;\r\n\tint64 nodeId = 3;\r\n\tstring appId = 4;\r\n\tstring domain = 5;\r\n\tstring status = 6;\r\n\tstring keyword = 7;\r\n\tint64 offset = 8;\r\n\tint64 size = 9;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSAccessLogsResponse", + "code": "message ListHTTPDNSAccessLogsResponse {\r\n\trepeated HTTPDNSAccessLog logs = 1;\r\n\tint64 total = 2;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSAppsRequest", + "code": "message ListHTTPDNSAppsRequest {\r\n\tint64 offset = 1;\r\n\tint64 size = 2;\r\n\tstring keyword = 3;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSAppsResponse", + "code": "message ListHTTPDNSAppsResponse {\r\n\trepeated HTTPDNSApp apps = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSClustersRequest", + "code": "message ListHTTPDNSClustersRequest {\r\n\tint64 offset = 1;\r\n\tint64 size = 2;\r\n\tstring keyword = 3;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSClustersResponse", + "code": "message ListHTTPDNSClustersResponse {\r\n\trepeated HTTPDNSCluster clusters = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSCustomRulesWithDomainIdRequest", + "code": "message ListHTTPDNSCustomRulesWithDomainIdRequest {\r\n\tint64 domainId = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSCustomRulesWithDomainIdResponse", + "code": "message ListHTTPDNSCustomRulesWithDomainIdResponse {\r\n\trepeated HTTPDNSCustomRule rules = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSDomainsWithAppIdRequest", + "code": "message ListHTTPDNSDomainsWithAppIdRequest {\r\n\tint64 appDbId = 1;\r\n\tstring keyword = 2;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSDomainsWithAppIdResponse", + "code": "message ListHTTPDNSDomainsWithAppIdResponse {\r\n\trepeated HTTPDNSDomain domains = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSNodesRequest", + "code": "message ListHTTPDNSNodesRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSNodesResponse", + "code": "message ListHTTPDNSNodesResponse {\r\n\trepeated HTTPDNSNode nodes = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSNodesWithClusterIdRequest", + "code": "message ListHTTPDNSNodesWithClusterIdRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSNodesWithClusterIdResponse", + "code": "message ListHTTPDNSNodesWithClusterIdResponse {\r\n\trepeated HTTPDNSNode nodes = 1;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSRuntimeLogsRequest", + "code": "message ListHTTPDNSRuntimeLogsRequest {\r\n\tstring day = 1;\r\n\tint64 clusterId = 2;\r\n\tint64 nodeId = 3;\r\n\tstring level = 4;\r\n\tstring keyword = 5;\r\n\tint64 offset = 6;\r\n\tint64 size = 7;\r\n}", + "doc": "" + }, + { + "name": "ListHTTPDNSRuntimeLogsResponse", + "code": "message ListHTTPDNSRuntimeLogsResponse {\r\n\trepeated HTTPDNSRuntimeLog logs = 1;\r\n\tint64 total = 2;\r\n}", + "doc": "" + }, { "name": "ListIPItemsAfterVersionRequest", "code": "message ListIPItemsAfterVersionRequest {\n\tint64 version = 1; // 版本号\n\tint64 size = 2; // 数量\n}", @@ -21384,12 +22279,12 @@ }, { "name": "ListNSNodesMatchRequest", - "code": "message ListNSNodesMatchRequest {\n\tint64 offset = 1;\n\tint64 size = 2;\n\tint64 nsClusterId = 3;\n\tint32 installState = 4;\n\tint32 activeState = 5;\n\tstring keyword = 6;\n\t//int64 nodeGroupId = 7;\n\t//int64 nodeRegionId = 8;\n}", + "code": "message ListNSNodesMatchRequest {\r\n\tint64 offset = 1;\r\n\tint64 size = 2;\r\n\tint64 nsClusterId = 3;\r\n\tint32 installState = 4;\r\n\tint32 activeState = 5;\r\n\tstring keyword = 6;\r\n\t//int64 nodeGroupId = 7;\r\n\t//int64 nodeRegionId = 8;\r\n}", "doc": "列出单页NS节点" }, { "name": "ListNSNodesMatchResponse", - "code": "message ListNSNodesMatchResponse {\n\trepeated NSNode nsNodes = 1;\n}", + "code": "message ListNSNodesMatchResponse {\r\n\trepeated NSNode nsNodes = 1;\r\n}", "doc": "" }, { @@ -21694,12 +22589,12 @@ }, { "name": "LoginUserRequest", - "code": "message LoginUserRequest {\n\tstring username = 1;\n\tstring password = 2;\n}", + "code": "message LoginUserRequest {\r\n\tstring username = 1;\r\n\tstring password = 2;\r\n}", "doc": "登录" }, { "name": "LoginUserResponse", - "code": "message LoginUserResponse {\n\tint64 userId = 1;\n\tbool isOk = 2;\n\tstring message = 3;\n}", + "code": "message LoginUserResponse {\r\n\tint64 userId = 1;\r\n\tbool isOk = 2;\r\n\tstring message = 3;\r\n}", "doc": "" }, { @@ -21819,7 +22714,7 @@ }, { "name": "NSNodeStreamMessage", - "code": "message NSNodeStreamMessage {\n\tint64 nsNodeId = 1;\n\tint64 requestId = 2;\n\tint32 timeoutSeconds = 3;\n\tstring code = 4;\n\tbytes dataJSON = 5;\n\tbool isOk = 6;\n\tstring message = 7;\n}", + "code": "message NSNodeStreamMessage {\r\n\tint64 nsNodeId = 1;\r\n\tint64 requestId = 2;\r\n\tint32 timeoutSeconds = 3;\r\n\tstring code = 4;\r\n\tbytes dataJSON = 5;\r\n\tbool isOk = 6;\r\n\tstring message = 7;\r\n}", "doc": "NS节点stream" }, { @@ -22129,12 +23024,12 @@ }, { "name": "RegisterUserRequest", - "code": "message RegisterUserRequest {\n\tstring username = 1;\n\tstring password = 2;\n\tstring mobile = 3;\n\tstring email = 4;\n\tstring fullname = 5;\n\tstring ip = 6;\n\tstring source = 7;\n}", + "code": "message RegisterUserRequest {\r\n\tstring username = 1;\r\n\tstring password = 2;\r\n\tstring mobile = 3;\r\n\tstring email = 4;\r\n\tstring fullname = 5;\r\n\tstring ip = 6;\r\n\tstring source = 7;\r\n}", "doc": "注册用户" }, { "name": "RegisterUserResponse", - "code": "message RegisterUserResponse {\n\tint64 userId = 1;\n\tbool requireEmailVerification = 2; // 是否需要激活邮件\n}", + "code": "message RegisterUserResponse {\r\n\tint64 userId = 1;\r\n\tbool requireEmailVerification = 2; // 是否需要激活邮件\r\n}", "doc": "" }, { @@ -22164,12 +23059,12 @@ }, { "name": "RenewUserServersStateRequest", - "code": "message RenewUserServersStateRequest {\n\tint64 userId = 1;\n}", + "code": "message RenewUserServersStateRequest {\r\n\tint64 userId = 1;\r\n}", "doc": "更新用户服务可用状态" }, { "name": "RenewUserServersStateResponse", - "code": "message RenewUserServersStateResponse {\n\tbool isEnabled = 1;\n}", + "code": "message RenewUserServersStateResponse {\r\n\tbool isEnabled = 1;\r\n}", "doc": "" }, { @@ -22207,6 +23102,16 @@ "code": "message ResetHTTPCacheTaskRequest {\n\tint64 httpCacheTaskId = 1; // 任务ID\n}", "doc": "重置任务状态" }, + { + "name": "ResetHTTPDNSAppSignSecretRequest", + "code": "message ResetHTTPDNSAppSignSecretRequest {\r\n\tint64 appDbId = 1;\r\n}", + "doc": "" + }, + { + "name": "ResetHTTPDNSAppSignSecretResponse", + "code": "message ResetHTTPDNSAppSignSecretResponse {\r\n\tstring signSecret = 1;\r\n\tint64 updatedAt = 2;\r\n}", + "doc": "" + }, { "name": "ResetNodeActionStatusRequest", "code": "message ResetNodeActionStatusRequest {\n\tint64 nodeId = 1; // 节点ID\n}", @@ -22374,12 +23279,12 @@ }, { "name": "StartNSNodeRequest", - "code": "message StartNSNodeRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message StartNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "启动NS节点" }, { "name": "StartNSNodeResponse", - "code": "message StartNSNodeResponse {\n\tbool isOk = 1;\n\tstring error = 2;\n}", + "code": "message StartNSNodeResponse {\r\n\tbool isOk = 1;\r\n\tstring error = 2;\r\n}", "doc": "" }, { @@ -22394,12 +23299,12 @@ }, { "name": "StopNSNodeRequest", - "code": "message StopNSNodeRequest {\n\tint64 nsNodeId = 1;\n}", + "code": "message StopNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", "doc": "停止NS节点" }, { "name": "StopNSNodeResponse", - "code": "message StopNSNodeResponse {\n\tbool isOk = 1;\n\tstring error = 2;\n}", + "code": "message StopNSNodeResponse {\r\n\tbool isOk = 1;\r\n\tstring error = 2;\r\n}", "doc": "" }, { @@ -22517,6 +23422,16 @@ "code": "message SysLockerUnlockRequest {\n\tstring key = 1;\n}", "doc": "释放锁" }, + { + "name": "TestHTTPDNSResolveRequest", + "code": "message TestHTTPDNSResolveRequest {\r\n\tint64 clusterId = 1;\r\n\tstring appId = 2;\r\n\tstring domain = 3;\r\n\tstring qtype = 4;\r\n\tstring clientIP = 5;\r\n\tstring sid = 6;\r\n\tstring sdkVersion = 7;\r\n\tstring os = 8;\r\n}", + "doc": "" + }, + { + "name": "TestHTTPDNSResolveResponse", + "code": "message TestHTTPDNSResolveResponse {\r\n\tstring code = 1;\r\n\tstring message = 2;\r\n\tstring requestId = 3;\r\n\tstring domain = 4;\r\n\tstring qtype = 5;\r\n\tint32 ttl = 6;\r\n\trepeated HTTPDNSResolveRecord records = 7;\r\n\tstring clientIP = 8;\r\n\tstring clientRegion = 9;\r\n\tstring clientCarrier = 10;\r\n\tstring clientCountry = 11;\r\n\tstring summary = 12;\r\n}", + "doc": "" + }, { "name": "TestNodeGrantRequest", "code": "message TestNodeGrantRequest {\n\tint64 nodeGrantId = 1;\n\tstring host = 2;\n\tint32 port = 3;\n}", @@ -22654,7 +23569,7 @@ }, { "name": "UpdateAllUsersFeaturesRequest", - "code": "message UpdateAllUsersFeaturesRequest {\n\trepeated string featureCodes = 1;\n\tbool overwrite = 2;\n}", + "code": "message UpdateAllUsersFeaturesRequest {\r\n\trepeated string featureCodes = 1;\r\n\tbool overwrite = 2;\r\n}", "doc": "设置所有用户能使用的功能" }, { @@ -22694,7 +23609,7 @@ }, { "name": "UpdateHTTPAccessLogPolicyRequest", - "code": "message UpdateHTTPAccessLogPolicyRequest {\n\tint64 httpAccessLogPolicyId = 1;\n\tstring name = 2;\n\tbool isOn = 3;\n\tbytes optionsJSON = 4;\n\tbytes condsJSON = 5;\n\tbool isPublic = 6;\n\tbool firewallOnly = 7;\n\tbool disableDefaultDB = 8;\n}", + "code": "message UpdateHTTPAccessLogPolicyRequest {\r\n\tint64 httpAccessLogPolicyId = 1;\r\n\tstring name = 2;\r\n\tstring type = 10; // 存储类型:file / es / tcp / syslog / command\r\n\tbool isOn = 3;\r\n\tbytes optionsJSON = 4;\r\n\tbytes condsJSON = 5;\r\n\tbool isPublic = 6;\r\n\tbool firewallOnly = 7;\r\n\tbool disableDefaultDB = 8;\r\n\tbytes writeTargetsJSON = 9;\r\n}", "doc": "修改访问日志策略" }, { @@ -22717,6 +23632,56 @@ "code": "message UpdateHTTPCacheTaskKeysStatusRequest {\n\trepeated KeyResult keyResults = 1;\n\n\n\tmessage KeyResult {\n\t\tint64 id = 1;\n\t\tint64 nodeClusterId = 2; // 特意设置的冗余数据\n\t\tstring error = 3;\n\t}\n}", "doc": "更新一组Key状态" }, + { + "name": "UpdateHTTPDNSAppRequest", + "code": "message UpdateHTTPDNSAppRequest {\r\n\tint64 appDbId = 1;\r\n\tstring name = 2;\r\n\treserved 3, 4; // removed: primaryClusterId, backupClusterId\r\n\tbool isOn = 5;\r\n\tint64 userId = 6;\r\n\tbytes clusterIdsJSON = 7;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSAppSignEnabledRequest", + "code": "message UpdateHTTPDNSAppSignEnabledRequest {\r\n\tint64 appDbId = 1;\r\n\tbool signEnabled = 2;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSClusterDefaultRequest", + "code": "message UpdateHTTPDNSClusterDefaultRequest {\r\n\tint64 clusterId = 1;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSClusterRequest", + "code": "message UpdateHTTPDNSClusterRequest {\r\n\tint64 clusterId = 1;\r\n\tstring name = 2;\r\n\tstring serviceDomain = 3;\r\n\tint32 defaultTTL = 4;\r\n\tint32 fallbackTimeoutMs = 5;\r\n\tstring installDir = 6;\r\n\tbytes tlsPolicyJSON = 7;\r\n\tbool isOn = 8;\r\n\tbool isDefault = 9;\r\n\tbool autoRemoteStart = 10;\r\n\tbool accessLogIsOn = 11;\r\n\tstring timeZone = 12;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSCustomRuleRequest", + "code": "message UpdateHTTPDNSCustomRuleRequest {\r\n\tHTTPDNSCustomRule rule = 1;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSCustomRuleStatusRequest", + "code": "message UpdateHTTPDNSCustomRuleStatusRequest {\r\n\tint64 ruleId = 1;\r\n\tbool isOn = 2;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSDomainStatusRequest", + "code": "message UpdateHTTPDNSDomainStatusRequest {\r\n\tint64 domainId = 1;\r\n\tbool isOn = 2;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSNodeLoginRequest", + "code": "message UpdateHTTPDNSNodeLoginRequest {\r\n\tint64 nodeId = 1;\r\n\tNodeLogin nodeLogin = 2;\r\n}", + "doc": "修改HTTPDNS节点登录信息" + }, + { + "name": "UpdateHTTPDNSNodeRequest", + "code": "message UpdateHTTPDNSNodeRequest {\r\n\tint64 nodeId = 1;\r\n\tstring name = 2;\r\n\tstring installDir = 3;\r\n\tbool isOn = 4;\r\n}", + "doc": "" + }, + { + "name": "UpdateHTTPDNSNodeStatusRequest", + "code": "message UpdateHTTPDNSNodeStatusRequest {\r\n\tint64 nodeId = 1;\r\n\tbool isUp = 2;\r\n\tbool isInstalled = 3;\r\n\tbool isActive = 4;\r\n\tbytes statusJSON = 5;\r\n\tbytes installStatusJSON = 6;\r\n}", + "doc": "" + }, { "name": "UpdateHTTPFastcgiRequest", "code": "message UpdateHTTPFastcgiRequest {\n\tint64 httpFastcgiId = 1;\n\tbool isOn = 2;\n\tstring address = 3;\n\tbytes paramsJSON = 4;\n\tbytes readTimeoutJSON = 5;\n\tbytes connTimeoutJSON = 6;\n\tint32 poolSize = 7;\n\tstring pathInfoPattern = 8;\n}", @@ -23134,37 +24099,37 @@ }, { "name": "UpdateNSNodeAPIConfigRequest", - "code": "message UpdateNSNodeAPIConfigRequest {\n\tint64 nsNodeId = 1;\n\tbytes apiNodeAddrsJSON = 2;\n}", + "code": "message UpdateNSNodeAPIConfigRequest {\r\n\tint64 nsNodeId = 1;\r\n\tbytes apiNodeAddrsJSON = 2;\r\n}", "doc": "修改某个节点的API相关配置" }, { "name": "UpdateNSNodeConnectedAPINodesRequest", - "code": "message UpdateNSNodeConnectedAPINodesRequest {\n\trepeated int64 apiNodeIds = 1;\n}", + "code": "message UpdateNSNodeConnectedAPINodesRequest {\r\n\trepeated int64 apiNodeIds = 1;\r\n}", "doc": "更改NS节点连接的API节点信息" }, { "name": "UpdateNSNodeDDoSProtectionRequest", - "code": "message UpdateNSNodeDDoSProtectionRequest {\n\tint64 nsNodeId = 1;\n\tbytes ddosProtectionJSON = 2;\n}", + "code": "message UpdateNSNodeDDoSProtectionRequest {\r\n\tint64 nsNodeId = 1;\r\n\tbytes ddosProtectionJSON = 2;\r\n}", "doc": "修改NS节点的DDoS设置" }, { "name": "UpdateNSNodeIsInstalledRequest", - "code": "message UpdateNSNodeIsInstalledRequest {\n\tint64 nsNodeId = 1;\n\tbool isInstalled = 2;\n}", + "code": "message UpdateNSNodeIsInstalledRequest {\r\n\tint64 nsNodeId = 1;\r\n\tbool isInstalled = 2;\r\n}", "doc": "修改NS节点安装状态" }, { "name": "UpdateNSNodeLoginRequest", - "code": "message UpdateNSNodeLoginRequest {\n\tint64 nsNodeId = 1;\n\tNodeLogin nodeLogin = 2;\n}", + "code": "message UpdateNSNodeLoginRequest {\r\n\tint64 nsNodeId = 1;\r\n\tNodeLogin nodeLogin = 2;\r\n}", "doc": "修改NS节点登录信息" }, { "name": "UpdateNSNodeRequest", - "code": "message UpdateNSNodeRequest {\n\tint64 nsNodeId = 1;\n\tstring name = 2;\n\tint64 nsClusterId = 3;\n\tNodeLogin nodeLogin = 4;\n\tbool isOn = 6;\n}", + "code": "message UpdateNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n\tstring name = 2;\r\n\tint64 nsClusterId = 3;\r\n\tNodeLogin nodeLogin = 4;\r\n\tbool isOn = 6;\r\n}", "doc": "修改NS节点" }, { "name": "UpdateNSNodeStatusRequest", - "code": "message UpdateNSNodeStatusRequest {\n\tint64 nodeId = 1;\n\tbytes statusJSON = 2;\n}", + "code": "message UpdateNSNodeStatusRequest {\r\n\tint64 nodeId = 1;\r\n\tbytes statusJSON = 2;\r\n}", "doc": "更新NS节点状态" }, { @@ -23734,7 +24699,7 @@ }, { "name": "UpdateUserFeaturesRequest", - "code": "message UpdateUserFeaturesRequest {\n\tint64 userId = 1;\n\trepeated string featureCodes = 2;\n}", + "code": "message UpdateUserFeaturesRequest {\r\n\tint64 userId = 1;\r\n\trepeated string featureCodes = 2;\r\n}", "doc": "设置单个用户能使用的功能" }, { @@ -23744,12 +24709,12 @@ }, { "name": "UpdateUserInfoRequest", - "code": "message UpdateUserInfoRequest {\n\tint64 userId = 1;\n\tstring fullname = 2;\n\tstring mobile = 3;\n\tstring email = 4;\n}", + "code": "message UpdateUserInfoRequest {\r\n\tint64 userId = 1;\r\n\tstring fullname = 2;\r\n\tstring mobile = 3;\r\n\tstring email = 4;\r\n}", "doc": "修改用户基本信息" }, { "name": "UpdateUserLoginRequest", - "code": "message UpdateUserLoginRequest {\n\tint64 userId = 1;\n\tstring username = 2;\n\tstring password = 3;\n}", + "code": "message UpdateUserLoginRequest {\r\n\tint64 userId = 1;\r\n\tstring username = 2;\r\n\tstring password = 3;\r\n}", "doc": "修改用户登录信息" }, { @@ -23769,17 +24734,17 @@ }, { "name": "UpdateUserPricePeriodRequest", - "code": "message UpdateUserPricePeriodRequest {\n\tint64 userId = 1;\n\tstring pricePeriod = 2;\n}", + "code": "message UpdateUserPricePeriodRequest {\r\n\tint64 userId = 1;\r\n\tstring pricePeriod = 2;\r\n}", "doc": "修改用户计费周期" }, { "name": "UpdateUserPriceTypeRequest", - "code": "message UpdateUserPriceTypeRequest {\n\tint64 userId = 1;\n\tstring priceType = 2;\n}", + "code": "message UpdateUserPriceTypeRequest {\r\n\tint64 userId = 1;\r\n\tstring priceType = 2;\r\n}", "doc": "修改用户计费方式" }, { "name": "UpdateUserRequest", - "code": "message UpdateUserRequest {\n\tint64 userId = 1;\n\tstring username = 2;\n\tstring password = 3;\n\tstring fullname = 4;\n\tstring mobile = 5;\n\tstring tel = 6;\n\tstring email = 7;\n\tstring remark = 8;\n\tbool isOn = 9;\n\tint64 nodeClusterId = 10;\n\tstring bandwidthAlgo = 11;\n}", + "code": "message UpdateUserRequest {\r\n\tint64 userId = 1;\r\n\tstring username = 2;\r\n\tstring password = 3;\r\n\tstring fullname = 4;\r\n\tstring mobile = 5;\r\n\tstring tel = 6;\r\n\tstring email = 7;\r\n\tstring remark = 8;\r\n\tbool isOn = 9;\r\n\tint64 nodeClusterId = 10;\r\n\tstring bandwidthAlgo = 11;\r\n\tbytes httpdnsClusterIdsJSON = 12; // HTTPDNS关联集群ID列表\r\n}", "doc": "修改用户" }, { @@ -23792,6 +24757,16 @@ "code": "message UpdateUserTicketRequest {\n\tint64 userTicketId = 1;\n\tint64 userTicketCategoryId = 2;\n\tstring subject = 3;\n\tstring body = 4;\n}", "doc": "修改工单" }, + { + "name": "UpgradeHTTPDNSNodeRequest", + "code": "message UpgradeHTTPDNSNodeRequest {\r\n\tint64 nodeId = 1;\r\n}", + "doc": "升级单个HTTPDNS节点" + }, + { + "name": "UpgradeNSNodeRequest", + "code": "message UpgradeNSNodeRequest {\r\n\tint64 nsNodeId = 1;\r\n}", + "doc": "升级单个NS节点" + }, { "name": "UpgradeNodeRequest", "code": "message UpgradeNodeRequest {\n\tint64 nodeId = 1;\n}", @@ -23849,7 +24824,7 @@ }, { "name": "User", - "code": "message User {\n\tint64 id = 1; // 用户ID\n\tstring username = 2; // 用户名\n\tstring fullname = 3; // 全称\n\tstring mobile = 4; // 手机号码\n\tstring tel = 5; // 联系电话\n\tstring email = 6; // 联系邮箱\n\tstring verifiedEmail = 20; // 已验证邮箱\n\tstring verifiedMobile = 23; // 已验证手机号码\n\tstring remark = 7; // 备注\n\tbool isOn = 8; // 是否启用\n\tint64 createdAt = 9; // 创建时间\n\tstring registeredIP = 12; // 注册IP\n\tbool isVerified = 13; // 是否已实名认证\n\tbool isRejected = 14; // 实名认证是否已拒绝\n\tstring rejectReason = 15; // 实名认证拒绝理由\n\tbool isDeleted = 16; // 是否已删除\n\tbool isIndividualIdentified = 17; // 是否已通过个人验证\n\tbool isEnterpriseIdentified = 18; // 是否已通过企业验证\n\tstring bandwidthAlgo = 21; // 带宽算法\n\tstring lang = 22; // 语言代号\n\n\tLogin otpLogin = 19; // OTP认证\n\n\tNodeCluster nodeCluster = 10; // 集群信息\n\trepeated UserFeature features = 11; // 开通功能\n}", + "code": "message User {\r\n\tint64 id = 1; // 用户ID\r\n\tstring username = 2; // 用户名\r\n\tstring fullname = 3; // 全称\r\n\tstring mobile = 4; // 手机号码\r\n\tstring tel = 5; // 联系电话\r\n\tstring email = 6; // 联系邮箱\r\n\tstring verifiedEmail = 20; // 已验证邮箱\r\n\tstring verifiedMobile = 23; // 已验证手机号码\r\n\tstring remark = 7; // 备注\r\n\tbool isOn = 8; // 是否启用\r\n\tint64 createdAt = 9; // 创建时间\r\n\tstring registeredIP = 12; // 注册IP\r\n\tbool isVerified = 13; // 是否已实名认证\r\n\tbool isRejected = 14; // 实名认证是否已拒绝\r\n\tstring rejectReason = 15; // 实名认证拒绝理由\r\n\tbool isDeleted = 16; // 是否已删除\r\n\tbool isIndividualIdentified = 17; // 是否已通过个人验证\r\n\tbool isEnterpriseIdentified = 18; // 是否已通过企业验证\r\n\tstring bandwidthAlgo = 21; // 带宽算法\r\n\tstring lang = 22; // 语言代号\r\n\tbytes httpdnsClusterIdsJSON = 24; // HTTPDNS关联集群ID列表\r\n\r\n\tLogin otpLogin = 19; // OTP认证\r\n\r\n\tNodeCluster nodeCluster = 10; // 集群信息\r\n\trepeated UserFeature features = 11; // 开通功能\r\n}", "doc": "" }, { @@ -24009,12 +24984,12 @@ }, { "name": "VerifyUserRequest", - "code": "message VerifyUserRequest {\n\tint64 userId = 1;\n\tbool isRejected = 2;\n\tstring rejectReason = 3;\n}", + "code": "message VerifyUserRequest {\r\n\tint64 userId = 1;\r\n\tbool isRejected = 2;\r\n\tstring rejectReason = 3;\r\n}", "doc": "审核用户" }, { "name": "WriteHTTPAccessLogPolicyRequest", - "code": "message WriteHTTPAccessLogPolicyRequest {\n\tint64 httpAccessLogPolicyId = 1;\n\tHTTPAccessLog httpAccessLog = 2;\n}", + "code": "message WriteHTTPAccessLogPolicyRequest {\r\n\tint64 httpAccessLogPolicyId = 1;\r\n\tHTTPAccessLog httpAccessLog = 2;\r\n}", "doc": "测试写入某个访问日志策略" }, { diff --git a/EdgeCommon/pkg/rpc/pb/service_httpdns_board.pb.go b/EdgeCommon/pkg/rpc/pb/service_httpdns_board.pb.go new file mode 100644 index 0000000..5a6cf00 --- /dev/null +++ b/EdgeCommon/pkg/rpc/pb/service_httpdns_board.pb.go @@ -0,0 +1,650 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v3.12.4 +// source: service_httpdns_board.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 组合看板数据请求 +type ComposeHTTPDNSBoardRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardRequest) Reset() { + *x = ComposeHTTPDNSBoardRequest{} + mi := &file_service_httpdns_board_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardRequest) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardRequest) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[0] + 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 ComposeHTTPDNSBoardRequest.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardRequest) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{0} +} + +// 组合看板数据响应 +type ComposeHTTPDNSBoardResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + CountApps int64 `protobuf:"varint,1,opt,name=countApps,proto3" json:"countApps,omitempty"` + CountDomains int64 `protobuf:"varint,2,opt,name=countDomains,proto3" json:"countDomains,omitempty"` + CountClusters int64 `protobuf:"varint,3,opt,name=countClusters,proto3" json:"countClusters,omitempty"` + CountNodes int64 `protobuf:"varint,4,opt,name=countNodes,proto3" json:"countNodes,omitempty"` + CountOfflineNodes int64 `protobuf:"varint,5,opt,name=countOfflineNodes,proto3" json:"countOfflineNodes,omitempty"` + DailyTrafficStats []*ComposeHTTPDNSBoardResponse_DailyTrafficStat `protobuf:"bytes,30,rep,name=dailyTrafficStats,proto3" json:"dailyTrafficStats,omitempty"` + HourlyTrafficStats []*ComposeHTTPDNSBoardResponse_HourlyTrafficStat `protobuf:"bytes,31,rep,name=hourlyTrafficStats,proto3" json:"hourlyTrafficStats,omitempty"` + TopAppStats []*ComposeHTTPDNSBoardResponse_TopAppStat `protobuf:"bytes,32,rep,name=topAppStats,proto3" json:"topAppStats,omitempty"` + TopDomainStats []*ComposeHTTPDNSBoardResponse_TopDomainStat `protobuf:"bytes,33,rep,name=topDomainStats,proto3" json:"topDomainStats,omitempty"` + TopNodeStats []*ComposeHTTPDNSBoardResponse_TopNodeStat `protobuf:"bytes,34,rep,name=topNodeStats,proto3" json:"topNodeStats,omitempty"` + CpuNodeValues []*NodeValue `protobuf:"bytes,35,rep,name=cpuNodeValues,proto3" json:"cpuNodeValues,omitempty"` + MemoryNodeValues []*NodeValue `protobuf:"bytes,36,rep,name=memoryNodeValues,proto3" json:"memoryNodeValues,omitempty"` + LoadNodeValues []*NodeValue `protobuf:"bytes,37,rep,name=loadNodeValues,proto3" json:"loadNodeValues,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse) Reset() { + *x = ComposeHTTPDNSBoardResponse{} + mi := &file_service_httpdns_board_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[1] + 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 ComposeHTTPDNSBoardResponse.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1} +} + +func (x *ComposeHTTPDNSBoardResponse) GetCountApps() int64 { + if x != nil { + return x.CountApps + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse) GetCountDomains() int64 { + if x != nil { + return x.CountDomains + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse) GetCountClusters() int64 { + if x != nil { + return x.CountClusters + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse) GetCountNodes() int64 { + if x != nil { + return x.CountNodes + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse) GetCountOfflineNodes() int64 { + if x != nil { + return x.CountOfflineNodes + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse) GetDailyTrafficStats() []*ComposeHTTPDNSBoardResponse_DailyTrafficStat { + if x != nil { + return x.DailyTrafficStats + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetHourlyTrafficStats() []*ComposeHTTPDNSBoardResponse_HourlyTrafficStat { + if x != nil { + return x.HourlyTrafficStats + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetTopAppStats() []*ComposeHTTPDNSBoardResponse_TopAppStat { + if x != nil { + return x.TopAppStats + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetTopDomainStats() []*ComposeHTTPDNSBoardResponse_TopDomainStat { + if x != nil { + return x.TopDomainStats + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetTopNodeStats() []*ComposeHTTPDNSBoardResponse_TopNodeStat { + if x != nil { + return x.TopNodeStats + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetCpuNodeValues() []*NodeValue { + if x != nil { + return x.CpuNodeValues + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetMemoryNodeValues() []*NodeValue { + if x != nil { + return x.MemoryNodeValues + } + return nil +} + +func (x *ComposeHTTPDNSBoardResponse) GetLoadNodeValues() []*NodeValue { + if x != nil { + return x.LoadNodeValues + } + return nil +} + +type ComposeHTTPDNSBoardResponse_DailyTrafficStat struct { + state protoimpl.MessageState `protogen:"open.v1"` + Day string `protobuf:"bytes,1,opt,name=day,proto3" json:"day,omitempty"` + Bytes int64 `protobuf:"varint,2,opt,name=bytes,proto3" json:"bytes,omitempty"` + CountRequests int64 `protobuf:"varint,3,opt,name=countRequests,proto3" json:"countRequests,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) Reset() { + *x = ComposeHTTPDNSBoardResponse_DailyTrafficStat{} + mi := &file_service_httpdns_board_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse_DailyTrafficStat) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[2] + 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 ComposeHTTPDNSBoardResponse_DailyTrafficStat.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse_DailyTrafficStat) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) GetDay() string { + if x != nil { + return x.Day + } + return "" +} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) GetBytes() int64 { + if x != nil { + return x.Bytes + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_DailyTrafficStat) GetCountRequests() int64 { + if x != nil { + return x.CountRequests + } + return 0 +} + +type ComposeHTTPDNSBoardResponse_HourlyTrafficStat struct { + state protoimpl.MessageState `protogen:"open.v1"` + Hour string `protobuf:"bytes,1,opt,name=hour,proto3" json:"hour,omitempty"` + Bytes int64 `protobuf:"varint,2,opt,name=bytes,proto3" json:"bytes,omitempty"` + CountRequests int64 `protobuf:"varint,3,opt,name=countRequests,proto3" json:"countRequests,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) Reset() { + *x = ComposeHTTPDNSBoardResponse_HourlyTrafficStat{} + mi := &file_service_httpdns_board_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse_HourlyTrafficStat) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[3] + 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 ComposeHTTPDNSBoardResponse_HourlyTrafficStat.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse_HourlyTrafficStat) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) GetHour() string { + if x != nil { + return x.Hour + } + return "" +} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) GetBytes() int64 { + if x != nil { + return x.Bytes + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_HourlyTrafficStat) GetCountRequests() int64 { + if x != nil { + return x.CountRequests + } + return 0 +} + +type ComposeHTTPDNSBoardResponse_TopAppStat struct { + state protoimpl.MessageState `protogen:"open.v1"` + AppId int64 `protobuf:"varint,1,opt,name=appId,proto3" json:"appId,omitempty"` + AppName string `protobuf:"bytes,2,opt,name=appName,proto3" json:"appName,omitempty"` + CountRequests int64 `protobuf:"varint,3,opt,name=countRequests,proto3" json:"countRequests,omitempty"` + Bytes int64 `protobuf:"varint,4,opt,name=bytes,proto3" json:"bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) Reset() { + *x = ComposeHTTPDNSBoardResponse_TopAppStat{} + mi := &file_service_httpdns_board_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse_TopAppStat) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[4] + 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 ComposeHTTPDNSBoardResponse_TopAppStat.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse_TopAppStat) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1, 2} +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) GetAppId() int64 { + if x != nil { + return x.AppId + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) GetAppName() string { + if x != nil { + return x.AppName + } + return "" +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) GetCountRequests() int64 { + if x != nil { + return x.CountRequests + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopAppStat) GetBytes() int64 { + if x != nil { + return x.Bytes + } + return 0 +} + +type ComposeHTTPDNSBoardResponse_TopDomainStat struct { + state protoimpl.MessageState `protogen:"open.v1"` + DomainId int64 `protobuf:"varint,1,opt,name=domainId,proto3" json:"domainId,omitempty"` + DomainName string `protobuf:"bytes,2,opt,name=domainName,proto3" json:"domainName,omitempty"` + CountRequests int64 `protobuf:"varint,3,opt,name=countRequests,proto3" json:"countRequests,omitempty"` + Bytes int64 `protobuf:"varint,4,opt,name=bytes,proto3" json:"bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) Reset() { + *x = ComposeHTTPDNSBoardResponse_TopDomainStat{} + mi := &file_service_httpdns_board_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse_TopDomainStat) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[5] + 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 ComposeHTTPDNSBoardResponse_TopDomainStat.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse_TopDomainStat) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1, 3} +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) GetDomainId() int64 { + if x != nil { + return x.DomainId + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) GetDomainName() string { + if x != nil { + return x.DomainName + } + return "" +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) GetCountRequests() int64 { + if x != nil { + return x.CountRequests + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopDomainStat) GetBytes() int64 { + if x != nil { + return x.Bytes + } + return 0 +} + +type ComposeHTTPDNSBoardResponse_TopNodeStat struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClusterId int64 `protobuf:"varint,1,opt,name=clusterId,proto3" json:"clusterId,omitempty"` + NodeId int64 `protobuf:"varint,2,opt,name=nodeId,proto3" json:"nodeId,omitempty"` + NodeName string `protobuf:"bytes,3,opt,name=nodeName,proto3" json:"nodeName,omitempty"` + CountRequests int64 `protobuf:"varint,4,opt,name=countRequests,proto3" json:"countRequests,omitempty"` + Bytes int64 `protobuf:"varint,5,opt,name=bytes,proto3" json:"bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) Reset() { + *x = ComposeHTTPDNSBoardResponse_TopNodeStat{} + mi := &file_service_httpdns_board_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeHTTPDNSBoardResponse_TopNodeStat) ProtoMessage() {} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) ProtoReflect() protoreflect.Message { + mi := &file_service_httpdns_board_proto_msgTypes[6] + 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 ComposeHTTPDNSBoardResponse_TopNodeStat.ProtoReflect.Descriptor instead. +func (*ComposeHTTPDNSBoardResponse_TopNodeStat) Descriptor() ([]byte, []int) { + return file_service_httpdns_board_proto_rawDescGZIP(), []int{1, 4} +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) GetClusterId() int64 { + if x != nil { + return x.ClusterId + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) GetNodeId() int64 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) GetCountRequests() int64 { + if x != nil { + return x.CountRequests + } + return 0 +} + +func (x *ComposeHTTPDNSBoardResponse_TopNodeStat) GetBytes() int64 { + if x != nil { + return x.Bytes + } + return 0 +} + +var File_service_httpdns_board_proto protoreflect.FileDescriptor + +const file_service_httpdns_board_proto_rawDesc = "" + + "\n" + + "\x1bservice_httpdns_board.proto\x12\x02pb\x1a\x1dmodels/model_node_value.proto\"\x1c\n" + + "\x1aComposeHTTPDNSBoardRequest\"\x9c\v\n" + + "\x1bComposeHTTPDNSBoardResponse\x12\x1c\n" + + "\tcountApps\x18\x01 \x01(\x03R\tcountApps\x12\"\n" + + "\fcountDomains\x18\x02 \x01(\x03R\fcountDomains\x12$\n" + + "\rcountClusters\x18\x03 \x01(\x03R\rcountClusters\x12\x1e\n" + + "\n" + + "countNodes\x18\x04 \x01(\x03R\n" + + "countNodes\x12,\n" + + "\x11countOfflineNodes\x18\x05 \x01(\x03R\x11countOfflineNodes\x12^\n" + + "\x11dailyTrafficStats\x18\x1e \x03(\v20.pb.ComposeHTTPDNSBoardResponse.DailyTrafficStatR\x11dailyTrafficStats\x12a\n" + + "\x12hourlyTrafficStats\x18\x1f \x03(\v21.pb.ComposeHTTPDNSBoardResponse.HourlyTrafficStatR\x12hourlyTrafficStats\x12L\n" + + "\vtopAppStats\x18 \x03(\v2*.pb.ComposeHTTPDNSBoardResponse.TopAppStatR\vtopAppStats\x12U\n" + + "\x0etopDomainStats\x18! \x03(\v2-.pb.ComposeHTTPDNSBoardResponse.TopDomainStatR\x0etopDomainStats\x12O\n" + + "\ftopNodeStats\x18\" \x03(\v2+.pb.ComposeHTTPDNSBoardResponse.TopNodeStatR\ftopNodeStats\x123\n" + + "\rcpuNodeValues\x18# \x03(\v2\r.pb.NodeValueR\rcpuNodeValues\x129\n" + + "\x10memoryNodeValues\x18$ \x03(\v2\r.pb.NodeValueR\x10memoryNodeValues\x125\n" + + "\x0eloadNodeValues\x18% \x03(\v2\r.pb.NodeValueR\x0eloadNodeValues\x1a`\n" + + "\x10DailyTrafficStat\x12\x10\n" + + "\x03day\x18\x01 \x01(\tR\x03day\x12\x14\n" + + "\x05bytes\x18\x02 \x01(\x03R\x05bytes\x12$\n" + + "\rcountRequests\x18\x03 \x01(\x03R\rcountRequests\x1ac\n" + + "\x11HourlyTrafficStat\x12\x12\n" + + "\x04hour\x18\x01 \x01(\tR\x04hour\x12\x14\n" + + "\x05bytes\x18\x02 \x01(\x03R\x05bytes\x12$\n" + + "\rcountRequests\x18\x03 \x01(\x03R\rcountRequests\x1ax\n" + + "\n" + + "TopAppStat\x12\x14\n" + + "\x05appId\x18\x01 \x01(\x03R\x05appId\x12\x18\n" + + "\aappName\x18\x02 \x01(\tR\aappName\x12$\n" + + "\rcountRequests\x18\x03 \x01(\x03R\rcountRequests\x12\x14\n" + + "\x05bytes\x18\x04 \x01(\x03R\x05bytes\x1a\x87\x01\n" + + "\rTopDomainStat\x12\x1a\n" + + "\bdomainId\x18\x01 \x01(\x03R\bdomainId\x12\x1e\n" + + "\n" + + "domainName\x18\x02 \x01(\tR\n" + + "domainName\x12$\n" + + "\rcountRequests\x18\x03 \x01(\x03R\rcountRequests\x12\x14\n" + + "\x05bytes\x18\x04 \x01(\x03R\x05bytes\x1a\x9b\x01\n" + + "\vTopNodeStat\x12\x1c\n" + + "\tclusterId\x18\x01 \x01(\x03R\tclusterId\x12\x16\n" + + "\x06nodeId\x18\x02 \x01(\x03R\x06nodeId\x12\x1a\n" + + "\bnodeName\x18\x03 \x01(\tR\bnodeName\x12$\n" + + "\rcountRequests\x18\x04 \x01(\x03R\rcountRequests\x12\x14\n" + + "\x05bytes\x18\x05 \x01(\x03R\x05bytes2m\n" + + "\x13HTTPDNSBoardService\x12V\n" + + "\x13composeHTTPDNSBoard\x12\x1e.pb.ComposeHTTPDNSBoardRequest\x1a\x1f.pb.ComposeHTTPDNSBoardResponseB\x06Z\x04./pbb\x06proto3" + +var ( + file_service_httpdns_board_proto_rawDescOnce sync.Once + file_service_httpdns_board_proto_rawDescData []byte +) + +func file_service_httpdns_board_proto_rawDescGZIP() []byte { + file_service_httpdns_board_proto_rawDescOnce.Do(func() { + file_service_httpdns_board_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_service_httpdns_board_proto_rawDesc), len(file_service_httpdns_board_proto_rawDesc))) + }) + return file_service_httpdns_board_proto_rawDescData +} + +var file_service_httpdns_board_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_service_httpdns_board_proto_goTypes = []any{ + (*ComposeHTTPDNSBoardRequest)(nil), // 0: pb.ComposeHTTPDNSBoardRequest + (*ComposeHTTPDNSBoardResponse)(nil), // 1: pb.ComposeHTTPDNSBoardResponse + (*ComposeHTTPDNSBoardResponse_DailyTrafficStat)(nil), // 2: pb.ComposeHTTPDNSBoardResponse.DailyTrafficStat + (*ComposeHTTPDNSBoardResponse_HourlyTrafficStat)(nil), // 3: pb.ComposeHTTPDNSBoardResponse.HourlyTrafficStat + (*ComposeHTTPDNSBoardResponse_TopAppStat)(nil), // 4: pb.ComposeHTTPDNSBoardResponse.TopAppStat + (*ComposeHTTPDNSBoardResponse_TopDomainStat)(nil), // 5: pb.ComposeHTTPDNSBoardResponse.TopDomainStat + (*ComposeHTTPDNSBoardResponse_TopNodeStat)(nil), // 6: pb.ComposeHTTPDNSBoardResponse.TopNodeStat + (*NodeValue)(nil), // 7: pb.NodeValue +} +var file_service_httpdns_board_proto_depIdxs = []int32{ + 2, // 0: pb.ComposeHTTPDNSBoardResponse.dailyTrafficStats:type_name -> pb.ComposeHTTPDNSBoardResponse.DailyTrafficStat + 3, // 1: pb.ComposeHTTPDNSBoardResponse.hourlyTrafficStats:type_name -> pb.ComposeHTTPDNSBoardResponse.HourlyTrafficStat + 4, // 2: pb.ComposeHTTPDNSBoardResponse.topAppStats:type_name -> pb.ComposeHTTPDNSBoardResponse.TopAppStat + 5, // 3: pb.ComposeHTTPDNSBoardResponse.topDomainStats:type_name -> pb.ComposeHTTPDNSBoardResponse.TopDomainStat + 6, // 4: pb.ComposeHTTPDNSBoardResponse.topNodeStats:type_name -> pb.ComposeHTTPDNSBoardResponse.TopNodeStat + 7, // 5: pb.ComposeHTTPDNSBoardResponse.cpuNodeValues:type_name -> pb.NodeValue + 7, // 6: pb.ComposeHTTPDNSBoardResponse.memoryNodeValues:type_name -> pb.NodeValue + 7, // 7: pb.ComposeHTTPDNSBoardResponse.loadNodeValues:type_name -> pb.NodeValue + 0, // 8: pb.HTTPDNSBoardService.composeHTTPDNSBoard:input_type -> pb.ComposeHTTPDNSBoardRequest + 1, // 9: pb.HTTPDNSBoardService.composeHTTPDNSBoard:output_type -> pb.ComposeHTTPDNSBoardResponse + 9, // [9:10] is the sub-list for method output_type + 8, // [8:9] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_service_httpdns_board_proto_init() } +func file_service_httpdns_board_proto_init() { + if File_service_httpdns_board_proto != nil { + return + } + file_models_model_node_value_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_service_httpdns_board_proto_rawDesc), len(file_service_httpdns_board_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_service_httpdns_board_proto_goTypes, + DependencyIndexes: file_service_httpdns_board_proto_depIdxs, + MessageInfos: file_service_httpdns_board_proto_msgTypes, + }.Build() + File_service_httpdns_board_proto = out.File + file_service_httpdns_board_proto_goTypes = nil + file_service_httpdns_board_proto_depIdxs = nil +} diff --git a/EdgeCommon/pkg/rpc/pb/service_httpdns_board_grpc.pb.go b/EdgeCommon/pkg/rpc/pb/service_httpdns_board_grpc.pb.go new file mode 100644 index 0000000..8083364 --- /dev/null +++ b/EdgeCommon/pkg/rpc/pb/service_httpdns_board_grpc.pb.go @@ -0,0 +1,125 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc v3.12.4 +// source: service_httpdns_board.proto + +package pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + HTTPDNSBoardService_ComposeHTTPDNSBoard_FullMethodName = "/pb.HTTPDNSBoardService/composeHTTPDNSBoard" +) + +// HTTPDNSBoardServiceClient is the client API for HTTPDNSBoardService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// HTTPDNS 看板服务 +type HTTPDNSBoardServiceClient interface { + // 组合看板数据 + ComposeHTTPDNSBoard(ctx context.Context, in *ComposeHTTPDNSBoardRequest, opts ...grpc.CallOption) (*ComposeHTTPDNSBoardResponse, error) +} + +type hTTPDNSBoardServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHTTPDNSBoardServiceClient(cc grpc.ClientConnInterface) HTTPDNSBoardServiceClient { + return &hTTPDNSBoardServiceClient{cc} +} + +func (c *hTTPDNSBoardServiceClient) ComposeHTTPDNSBoard(ctx context.Context, in *ComposeHTTPDNSBoardRequest, opts ...grpc.CallOption) (*ComposeHTTPDNSBoardResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ComposeHTTPDNSBoardResponse) + err := c.cc.Invoke(ctx, HTTPDNSBoardService_ComposeHTTPDNSBoard_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HTTPDNSBoardServiceServer is the server API for HTTPDNSBoardService service. +// All implementations should embed UnimplementedHTTPDNSBoardServiceServer +// for forward compatibility. +// +// HTTPDNS 看板服务 +type HTTPDNSBoardServiceServer interface { + // 组合看板数据 + ComposeHTTPDNSBoard(context.Context, *ComposeHTTPDNSBoardRequest) (*ComposeHTTPDNSBoardResponse, error) +} + +// UnimplementedHTTPDNSBoardServiceServer should be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedHTTPDNSBoardServiceServer struct{} + +func (UnimplementedHTTPDNSBoardServiceServer) ComposeHTTPDNSBoard(context.Context, *ComposeHTTPDNSBoardRequest) (*ComposeHTTPDNSBoardResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ComposeHTTPDNSBoard not implemented") +} +func (UnimplementedHTTPDNSBoardServiceServer) testEmbeddedByValue() {} + +// UnsafeHTTPDNSBoardServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HTTPDNSBoardServiceServer will +// result in compilation errors. +type UnsafeHTTPDNSBoardServiceServer interface { + mustEmbedUnimplementedHTTPDNSBoardServiceServer() +} + +func RegisterHTTPDNSBoardServiceServer(s grpc.ServiceRegistrar, srv HTTPDNSBoardServiceServer) { + // If the following call panics, it indicates UnimplementedHTTPDNSBoardServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&HTTPDNSBoardService_ServiceDesc, srv) +} + +func _HTTPDNSBoardService_ComposeHTTPDNSBoard_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ComposeHTTPDNSBoardRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HTTPDNSBoardServiceServer).ComposeHTTPDNSBoard(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: HTTPDNSBoardService_ComposeHTTPDNSBoard_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HTTPDNSBoardServiceServer).ComposeHTTPDNSBoard(ctx, req.(*ComposeHTTPDNSBoardRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// HTTPDNSBoardService_ServiceDesc is the grpc.ServiceDesc for HTTPDNSBoardService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HTTPDNSBoardService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "pb.HTTPDNSBoardService", + HandlerType: (*HTTPDNSBoardServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "composeHTTPDNSBoard", + Handler: _HTTPDNSBoardService_ComposeHTTPDNSBoard_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "service_httpdns_board.proto", +} diff --git a/EdgeCommon/pkg/serverconfigs/http_auth_method_base.go b/EdgeCommon/pkg/serverconfigs/http_auth_method_base.go index 1d3dc0a..c85f4cd 100644 --- a/EdgeCommon/pkg/serverconfigs/http_auth_method_base.go +++ b/EdgeCommon/pkg/serverconfigs/http_auth_method_base.go @@ -12,6 +12,7 @@ import ( ) var httpAuthTimestampRegexp = regexp.MustCompile(`^\d{10}$`) +var httpAuthHexTimestampRegexp = regexp.MustCompile(`^[0-9a-fA-F]{1,16}$`) type HTTPAuthBaseMethod struct { Exts []string `json:"exts"` diff --git a/EdgeCommon/pkg/serverconfigs/http_auth_methods_plus.go b/EdgeCommon/pkg/serverconfigs/http_auth_methods_plus.go index f63b541..1b61694 100644 --- a/EdgeCommon/pkg/serverconfigs/http_auth_methods_plus.go +++ b/EdgeCommon/pkg/serverconfigs/http_auth_methods_plus.go @@ -7,12 +7,12 @@ type HTTPAuthType = string const ( HTTPAuthTypeBasicAuth HTTPAuthType = "basicAuth" // BasicAuth - HTTPAuthTypeSubRequest HTTPAuthType = "subRequest" // 子请求 - - HTTPAuthTypeTypeA HTTPAuthType = "typeA" - HTTPAuthTypeTypeB HTTPAuthType = "typeB" - HTTPAuthTypeTypeC HTTPAuthType = "typeC" - HTTPAuthTypeTypeD HTTPAuthType = "typeD" + HTTPAuthTypeSubRequest HTTPAuthType = "subRequest" // SubRequest + HTTPAuthTypeTypeA HTTPAuthType = "typeA" + HTTPAuthTypeTypeB HTTPAuthType = "typeB" + HTTPAuthTypeTypeC HTTPAuthType = "typeC" + HTTPAuthTypeTypeD HTTPAuthType = "typeD" + HTTPAuthTypeTypeE HTTPAuthType = "typeE" ) type HTTPAuthTypeDefinition struct { @@ -23,10 +23,11 @@ type HTTPAuthTypeDefinition struct { } func FindAllHTTPAuthTypes(role string) []*HTTPAuthTypeDefinition { - var urlDocA = "" - var urlDocB = "" - var urlDocC = "" - var urlDocD = "" + urlDocA := "" + urlDocB := "" + urlDocC := "" + urlDocD := "" + urlDocE := "https://help.aliyun.com/zh/cdn/user-guide/type-c-signing" switch role { case "admin": @@ -66,15 +67,21 @@ func FindAllHTTPAuthTypes(role string) []*HTTPAuthTypeDefinition { Description: "示例URL:https://example.com/images/test.jpg?sign=f66af42f87cf63a64f4b86ec11c7797a&t=1661753717
[算法详解]", IsPlus: true, }, + { + Name: "URL鉴权E", + Code: HTTPAuthTypeTypeE, + Description: "严格兼容阿里云 Type-C 路径鉴权,示例URL:https://example.com/3a2c79f2d2f0df2f8f9e05ec9f482e5d/67cfdb9e/images/test.jpg
[阿里云文档]", + IsPlus: true, + }, { Name: "基本认证", Code: HTTPAuthTypeBasicAuth, - Description: "BasicAuth,最简单的HTTP请求认证方式,通过传递Authorization: Basic xxx Header认证。", + Description: "BasicAuth,最简单的 HTTP 请求认证方式,通过传递 Authorization: Basic xxx Header 认证。", }, { Name: "子请求", Code: HTTPAuthTypeSubRequest, - Description: "通过自定义的URL子请求来认证请求。", + Description: "通过自定义的 URL 子请求来认证请求。", }, } } diff --git a/EdgeCommon/pkg/serverconfigs/http_auth_policy_init_plus.go b/EdgeCommon/pkg/serverconfigs/http_auth_policy_init_plus.go index 2b45ca5..084554a 100644 --- a/EdgeCommon/pkg/serverconfigs/http_auth_policy_init_plus.go +++ b/EdgeCommon/pkg/serverconfigs/http_auth_policy_init_plus.go @@ -22,6 +22,8 @@ func (this *HTTPAuthPolicy) Init() error { this.method = NewHTTPAuthTypeCMethod() case HTTPAuthTypeTypeD: this.method = NewHTTPAuthTypeDMethod() + case HTTPAuthTypeTypeE: + this.method = NewHTTPAuthTypeEMethod() } if this.method == nil { diff --git a/EdgeDNS/build/build.sh b/EdgeDNS/build/build.sh index 6da3934..28d6cad 100644 --- a/EdgeDNS/build/build.sh +++ b/EdgeDNS/build/build.sh @@ -1,5 +1,138 @@ #!/usr/bin/env bash +function find-binary() { + local candidate + for candidate in "$@"; do + if [ -z "$candidate" ]; then + continue + fi + if [ -x "$candidate" ]; then + echo "$candidate" + return 0 + fi + if command -v "$candidate" >/dev/null 2>&1; then + command -v "$candidate" + return 0 + fi + done + return 1 +} + +function host-goarch() { + case "$(uname -m)" in + x86_64|amd64) + echo "amd64" + ;; + aarch64|arm64) + echo "arm64" + ;; + i386|i486|i586|i686) + echo "386" + ;; + mips64) + echo "mips64" + ;; + mips64el) + echo "mips64le" + ;; + *) + echo "" + ;; + esac +} + +function find-linux-static-toolchain() { + local arch=$1 + local cc_bin="" + local cxx_bin="" + local host_arch + + host_arch=$(host-goarch) + + case "$arch" in + amd64) + cc_bin=$(find-binary \ + "/usr/local/gcc/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-gcc" \ + "/usr/local/opt/musl-cross/bin/x86_64-linux-musl-gcc" \ + "x86_64-unknown-linux-gnu-gcc" \ + "x86_64-linux-musl-gcc" \ + "musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/gcc/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-g++" \ + "/usr/local/opt/musl-cross/bin/x86_64-linux-musl-g++" \ + "x86_64-unknown-linux-gnu-g++" \ + "x86_64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "amd64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "amd64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + 386) + cc_bin=$(find-binary "/usr/local/opt/musl-cross/bin/i486-linux-musl-gcc" "i486-linux-musl-gcc") + cxx_bin=$(find-binary "/usr/local/opt/musl-cross/bin/i486-linux-musl-g++" "i486-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "386" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "386" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + arm64) + cc_bin=$(find-binary \ + "/usr/local/gcc/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-gcc" \ + "/usr/local/opt/musl-cross/bin/aarch64-linux-musl-gcc" \ + "aarch64-unknown-linux-gnu-gcc" \ + "aarch64-linux-musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/gcc/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-g++" \ + "/usr/local/opt/musl-cross/bin/aarch64-linux-musl-g++" \ + "aarch64-unknown-linux-gnu-g++" \ + "aarch64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "arm64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "arm64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + mips64) + cc_bin=$(find-binary "/usr/local/opt/musl-cross/bin/mips64-linux-musl-gcc" "mips64-linux-musl-gcc") + cxx_bin=$(find-binary "/usr/local/opt/musl-cross/bin/mips64-linux-musl-g++" "mips64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "mips64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "mips64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + mips64le) + cc_bin=$(find-binary "/usr/local/opt/musl-cross/bin/mips64el-linux-musl-gcc" "mips64el-linux-musl-gcc") + cxx_bin=$(find-binary "/usr/local/opt/musl-cross/bin/mips64el-linux-musl-g++" "mips64el-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "mips64le" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "mips64le" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + *) + return 1 + ;; + esac + + if [ -z "$cc_bin" ]; then + return 1 + fi + if [ -z "$cxx_bin" ]; then + cxx_bin="$cc_bin" + fi + + echo "$cc_bin|$cxx_bin" + return 0 +} + function build() { ROOT=$(dirname "$0") NAME="edge-dns" @@ -18,10 +151,9 @@ function build() { fi echo "checking ..." - ZIP_PATH=$(which zip) - if [ -z "$ZIP_PATH" ]; then + if ! command -v zip >/dev/null 2>&1; then echo "we need 'zip' command to compress files" - exit + exit 1 fi echo "building v${VERSION}/${OS}/${ARCH} ..." @@ -37,38 +169,20 @@ function build() { fi cp "$ROOT"/configs/api_dns.template.yaml "$DIST"/configs - copy_fluent_bit_assets "$ROOT" "$DIST" "$OS" "$ARCH" || exit 1 echo "building ..." - MUSL_DIR="/usr/local/opt/musl-cross/bin" - CC_PATH="" - CXX_PATH="" - if [[ $(uname -a) == *"Darwin"* && "${OS}" == "linux" ]]; then - # /usr/local/opt/musl-cross/bin/ - if [ "${ARCH}" == "amd64" ]; then - CC_PATH="x86_64-linux-musl-gcc" - CXX_PATH="x86_64-linux-musl-g++" + if [ "$OS" == "linux" ]; then + TOOLCHAIN=$(find-linux-static-toolchain "$ARCH") + if [ -z "$TOOLCHAIN" ]; then + echo "could not find a static Linux toolchain for ${ARCH}" + echo "install a musl toolchain before building edge-dns" + exit 1 fi - if [ "${ARCH}" == "386" ]; then - CC_PATH="i486-linux-musl-gcc" - CXX_PATH="i486-linux-musl-g++" - fi - if [ "${ARCH}" == "arm64" ]; then - CC_PATH="aarch64-linux-musl-gcc" - CXX_PATH="aarch64-linux-musl-g++" - fi - if [ "${ARCH}" == "mips64" ]; then - CC_PATH="mips64-linux-musl-gcc" - CXX_PATH="mips64-linux-musl-g++" - fi - if [ "${ARCH}" == "mips64le" ]; then - CC_PATH="mips64el-linux-musl-gcc" - CXX_PATH="mips64el-linux-musl-g++" - fi - fi - if [ ! -z $CC_PATH ]; then - env CC=$MUSL_DIR/$CC_PATH CXX=$MUSL_DIR/$CXX_PATH GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags="plus" -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-dns/main.go + + CC_BIN=${TOOLCHAIN%|*} + CXX_BIN=${TOOLCHAIN#*|} + env CC="$CC_BIN" CXX="$CXX_BIN" GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags="plus" -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-dns/main.go else env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags="plus" -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-dns/main.go fi @@ -76,7 +190,7 @@ function build() { # check build result RESULT=$? if [ "${RESULT}" != "0" ]; then - exit + exit 1 fi # delete hidden files @@ -95,81 +209,6 @@ function build() { echo "OK" } -function copy_fluent_bit_assets() { - ROOT=$1 - DIST=$2 - OS=$3 - ARCH=$4 - FLUENT_ROOT="$ROOT/../../deploy/fluent-bit" - FLUENT_DIST="$DIST/deploy/fluent-bit" - - if [ ! -d "$FLUENT_ROOT" ]; then - echo "[error] fluent-bit source directory not found: $FLUENT_ROOT" - return 1 - fi - verify_fluent_bit_package_matrix "$FLUENT_ROOT" "$ARCH" || return 1 - - rm -rf "$FLUENT_DIST" - mkdir -p "$FLUENT_DIST" - - for file in fluent-bit.conf fluent-bit-dns.conf fluent-bit-https.conf fluent-bit-dns-https.conf fluent-bit-windows.conf fluent-bit-windows-https.conf parsers.conf clickhouse-upstream.conf clickhouse-upstream-windows.conf README.md; do - if [ -f "$FLUENT_ROOT/$file" ]; then - cp "$FLUENT_ROOT/$file" "$FLUENT_DIST/" - fi - done - - if [ "$OS" = "linux" ]; then - PACKAGE_SRC="$FLUENT_ROOT/packages/linux-$ARCH" - PACKAGE_DST="$FLUENT_DIST/packages/linux-$ARCH" - if [ -d "$PACKAGE_SRC" ]; then - mkdir -p "$PACKAGE_DST" - cp -R "$PACKAGE_SRC/." "$PACKAGE_DST/" - else - echo "[error] fluent-bit package directory not found: $PACKAGE_SRC" - return 1 - fi - fi - - rm -f "$FLUENT_DIST/.gitignore" - rm -f "$FLUENT_DIST"/logs.db* - rm -rf "$FLUENT_DIST/storage" - - return 0 -} - -function verify_fluent_bit_package_matrix() { - FLUENT_ROOT=$1 - ARCH=$2 - REQUIRED_FILES=() - if [ "$ARCH" = "amd64" ]; then - REQUIRED_FILES=( - "packages/linux-amd64/fluent-bit_4.2.2_amd64.deb" - "packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm" - ) - elif [ "$ARCH" = "arm64" ]; then - REQUIRED_FILES=( - "packages/linux-arm64/fluent-bit_4.2.2_arm64.deb" - "packages/linux-arm64/fluent-bit-4.2.2-1.aarch64.rpm" - ) - else - echo "[error] unsupported arch for fluent-bit package validation: $ARCH" - return 1 - fi - - MISSING=0 - for FILE in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$FLUENT_ROOT/$FILE" ]; then - echo "[error] fluent-bit matrix package missing: $FLUENT_ROOT/$FILE" - MISSING=1 - fi - done - - if [ "$MISSING" -ne 0 ]; then - return 1 - fi - return 0 -} - function lookup-version() { FILE=$1 VERSION_DATA=$(cat "$FILE") @@ -179,7 +218,7 @@ function lookup-version() { echo "$VERSION" else echo "could not match version" - exit + exit 1 fi } diff --git a/EdgeDNS/internal/const/const.go b/EdgeDNS/internal/const/const.go index 1770316..3d8175a 100644 --- a/EdgeDNS/internal/const/const.go +++ b/EdgeDNS/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "1.4.9" //1.3.8.2 + Version = "1.5.0" //1.3.8.2 ProductName = "Edge DNS" ProcessName = "edge-dns" diff --git a/EdgeHttpDNS/build/build.sh b/EdgeHttpDNS/build/build.sh index adc3efb..889b702 100644 --- a/EdgeHttpDNS/build/build.sh +++ b/EdgeHttpDNS/build/build.sh @@ -34,10 +34,14 @@ function build() { mkdir -p "$DIST"/data cp "$ROOT"/configs/api_httpdns.template.yaml "$DIST"/configs - copy_fluent_bit_assets "$ROOT" "$DIST" "$OS" "$ARCH" || exit 1 - env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 \ - go build -trimpath -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-httpdns/main.go + if [ "${OS}" = "linux" ]; then + env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=0 \ + go build -trimpath -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-httpdns/main.go + else + env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 \ + go build -trimpath -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-httpdns/main.go + fi if [ ! -f "$DIST"/bin/${NAME} ]; then echo "build failed!" @@ -60,81 +64,6 @@ function build() { echo "OK" } -function copy_fluent_bit_assets() { - ROOT=$1 - DIST=$2 - OS=$3 - ARCH=$4 - FLUENT_ROOT="$ROOT/../../deploy/fluent-bit" - FLUENT_DIST="$DIST/deploy/fluent-bit" - - if [ ! -d "$FLUENT_ROOT" ]; then - echo "[error] fluent-bit source directory not found: $FLUENT_ROOT" - return 1 - fi - verify_fluent_bit_package_matrix "$FLUENT_ROOT" "$ARCH" || return 1 - - rm -rf "$FLUENT_DIST" - mkdir -p "$FLUENT_DIST" - - for file in fluent-bit.conf fluent-bit-dns.conf fluent-bit-https.conf fluent-bit-dns-https.conf fluent-bit-windows.conf fluent-bit-windows-https.conf parsers.conf clickhouse-upstream.conf clickhouse-upstream-windows.conf README.md; do - if [ -f "$FLUENT_ROOT/$file" ]; then - cp "$FLUENT_ROOT/$file" "$FLUENT_DIST/" - fi - done - - if [ "$OS" = "linux" ]; then - PACKAGE_SRC="$FLUENT_ROOT/packages/linux-$ARCH" - PACKAGE_DST="$FLUENT_DIST/packages/linux-$ARCH" - if [ -d "$PACKAGE_SRC" ]; then - mkdir -p "$PACKAGE_DST" - cp -R "$PACKAGE_SRC/." "$PACKAGE_DST/" - else - echo "[error] fluent-bit package directory not found: $PACKAGE_SRC" - return 1 - fi - fi - - rm -f "$FLUENT_DIST/.gitignore" - rm -f "$FLUENT_DIST"/logs.db* - rm -rf "$FLUENT_DIST/storage" - - return 0 -} - -function verify_fluent_bit_package_matrix() { - FLUENT_ROOT=$1 - ARCH=$2 - REQUIRED_FILES=() - if [ "$ARCH" = "amd64" ]; then - REQUIRED_FILES=( - "packages/linux-amd64/fluent-bit_4.2.2_amd64.deb" - "packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm" - ) - elif [ "$ARCH" = "arm64" ]; then - REQUIRED_FILES=( - "packages/linux-arm64/fluent-bit_4.2.2_arm64.deb" - "packages/linux-arm64/fluent-bit-4.2.2-1.aarch64.rpm" - ) - else - echo "[error] unsupported arch for fluent-bit package validation: $ARCH" - return 1 - fi - - MISSING=0 - for FILE in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$FLUENT_ROOT/$FILE" ]; then - echo "[error] fluent-bit matrix package missing: $FLUENT_ROOT/$FILE" - MISSING=1 - fi - done - - if [ "$MISSING" -ne 0 ]; then - return 1 - fi - return 0 -} - function lookup-version() { FILE=$1 VERSION_DATA=$(cat "$FILE") diff --git a/EdgeHttpDNS/go.mod b/EdgeHttpDNS/go.mod index fec8371..7d7f412 100644 --- a/EdgeHttpDNS/go.mod +++ b/EdgeHttpDNS/go.mod @@ -8,21 +8,29 @@ require ( github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000 github.com/iwind/TeaGo v0.0.0-20240411075713-6c1fc9aca7b6 github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 + github.com/miekg/dns v1.1.72 + github.com/shirou/gopsutil/v3 v3.24.5 + golang.org/x/sys v0.39.0 google.golang.org/grpc v1.78.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/miekg/dns v1.1.72 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/oschwald/geoip2-golang v1.13.0 // indirect github.com/oschwald/maxminddb-golang v1.13.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/mod v0.31.0 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect golang.org/x/text v0.32.0 // indirect golang.org/x/tools v0.40.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) diff --git a/EdgeHttpDNS/go.sum b/EdgeHttpDNS/go.sum index fe5cf68..b43bee8 100644 --- a/EdgeHttpDNS/go.sum +++ b/EdgeHttpDNS/go.sum @@ -1,9 +1,14 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -16,12 +21,32 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI= github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU= github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -36,22 +61,19 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0= diff --git a/EdgeHttpDNS/internal/const/const.go b/EdgeHttpDNS/internal/const/const.go index f254982..46cf142 100644 --- a/EdgeHttpDNS/internal/const/const.go +++ b/EdgeHttpDNS/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "1.4.9" + Version = "1.5.0" ProductName = "Edge HTTPDNS" ProcessName = "edge-httpdns" diff --git a/EdgeHttpDNS/internal/nodes/status_manager.go b/EdgeHttpDNS/internal/nodes/status_manager.go index 2a3c159..3f487f3 100644 --- a/EdgeHttpDNS/internal/nodes/status_manager.go +++ b/EdgeHttpDNS/internal/nodes/status_manager.go @@ -15,18 +15,28 @@ import ( teaconst "github.com/TeaOSLab/EdgeHttpDNS/internal/const" "github.com/TeaOSLab/EdgeHttpDNS/internal/rpc" "github.com/TeaOSLab/EdgeHttpDNS/internal/utils" + "github.com/iwind/TeaGo/maps" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/mem" ) - type StatusManager struct { quitCh <-chan struct{} ticker *time.Ticker + + isFirstTime bool + cpuUpdatedTime time.Time + cpuLogicalCount int + cpuPhysicalCount int } func NewStatusManager(quitCh <-chan struct{}) *StatusManager { return &StatusManager{ - quitCh: quitCh, - ticker: time.NewTicker(30 * time.Second), + quitCh: quitCh, + ticker: time.NewTicker(30 * time.Second), + isFirstTime: true, + cpuUpdatedTime: time.Now(), + cpuLogicalCount: runtime.NumCPU(), } } @@ -72,10 +82,12 @@ func (m *StatusManager) update() { IsActive: true, StatusJSON: statusJSON, }) - if err != nil { log.Println("[HTTPDNS_NODE][status]update status failed:", err.Error()) } + + m.reportNodeValues(rpcClient, status) + m.isFirstTime = false } func (m *StatusManager) collectStatus() *nodeconfigs.NodeStatus { @@ -87,8 +99,8 @@ func (m *StatusManager) collectStatus() *nodeconfigs.NodeStatus { ConfigVersion: 0, OS: runtime.GOOS, Arch: runtime.GOARCH, - CPULogicalCount: runtime.NumCPU(), - CPUPhysicalCount: runtime.NumCPU(), + CPULogicalCount: m.cpuLogicalCount, + CPUPhysicalCount: m.cpuPhysicalCount, IsActive: true, ConnectionCount: 0, UpdatedAt: now, @@ -104,26 +116,104 @@ func (m *StatusManager) collectStatus() *nodeconfigs.NodeStatus { } } - hostname, _ := os.Hostname() status.Hostname = hostname exePath, _ := os.Executable() status.ExePath = exePath - var memStats runtime.MemStats - runtime.ReadMemStats(&memStats) - status.MemoryTotal = memStats.Sys - if status.MemoryTotal > 0 { - status.MemoryUsage = float64(memStats.Alloc) / float64(status.MemoryTotal) + m.updateCPU(status) + m.updateMemory(status) + m.updateLoad(status) + + return status +} + +func (m *StatusManager) updateCPU(status *nodeconfigs.NodeStatus) { + duration := time.Duration(0) + if m.isFirstTime { + duration = 100 * time.Millisecond } + percents, err := cpu.Percent(duration, false) + if err == nil && len(percents) > 0 { + status.CPUUsage = percents[0] / 100 + } + + if time.Since(m.cpuUpdatedTime) >= 5*time.Minute || m.cpuLogicalCount <= 0 { + m.cpuUpdatedTime = time.Now() + + if logicalCount, countErr := cpu.Counts(true); countErr == nil && logicalCount > 0 { + m.cpuLogicalCount = logicalCount + } + if physicalCount, countErr := cpu.Counts(false); countErr == nil && physicalCount > 0 { + m.cpuPhysicalCount = physicalCount + } + } + + status.CPULogicalCount = m.cpuLogicalCount + if m.cpuPhysicalCount > 0 { + status.CPUPhysicalCount = m.cpuPhysicalCount + } +} + +func (m *StatusManager) updateMemory(status *nodeconfigs.NodeStatus) { + stat, err := mem.VirtualMemory() + if err != nil || stat == nil || stat.Total == 0 { + return + } + + usedBytes := stat.Used + if stat.Total > stat.Free+stat.Buffers+stat.Cached { + usedBytes = stat.Total - stat.Free - stat.Buffers - stat.Cached + } + + status.MemoryTotal = stat.Total + status.MemoryUsage = float64(usedBytes) / float64(stat.Total) +} + +func (m *StatusManager) updateLoad(status *nodeconfigs.NodeStatus) { load1m, load5m, load15m := readLoadAvg() status.Load1m = load1m status.Load5m = load5m status.Load15m = load15m +} - return status +func (m *StatusManager) reportNodeValues(rpcClient *rpc.RPCClient, status *nodeconfigs.NodeStatus) { + if rpcClient == nil || status == nil { + return + } + + m.createNodeValue(rpcClient, nodeconfigs.NodeValueItemCPU, maps.Map{ + "usage": status.CPUUsage, + "cores": status.CPULogicalCount, + }) + m.createNodeValue(rpcClient, nodeconfigs.NodeValueItemMemory, maps.Map{ + "usage": status.MemoryUsage, + "total": status.MemoryTotal, + }) + m.createNodeValue(rpcClient, nodeconfigs.NodeValueItemLoad, maps.Map{ + "load1m": status.Load1m, + "load5m": status.Load5m, + "load15m": status.Load15m, + }) +} + +func (m *StatusManager) createNodeValue(rpcClient *rpc.RPCClient, item string, value maps.Map) { + valueJSON, err := json.Marshal(value) + if err != nil { + log.Println("[HTTPDNS_NODE][status]marshal node value failed:", err.Error()) + return + } + + _, err = rpcClient.NodeValueRPC.CreateNodeValue(rpcClient.Context(), &pb.CreateNodeValueRequest{ + Item: item, + ValueJSON: valueJSON, + CreatedAt: time.Now().Unix(), + }) + if err != nil { + log.Println("[HTTPDNS_NODE][status]create node value failed:", item, err.Error()) + } } func readLoadAvg() (float64, float64, float64) { diff --git a/EdgeHttpDNS/internal/rpc/rpc_client.go b/EdgeHttpDNS/internal/rpc/rpc_client.go index 52d76c1..3fdcd40 100644 --- a/EdgeHttpDNS/internal/rpc/rpc_client.go +++ b/EdgeHttpDNS/internal/rpc/rpc_client.go @@ -26,13 +26,13 @@ import ( "sync/atomic" ) - type RPCClient struct { apiConfig *configs.APIConfig conns []*grpc.ClientConn locker sync.RWMutex NodeTaskRPC pb.NodeTaskServiceClient + NodeValueRPC pb.NodeValueServiceClient HTTPDNSNodeRPC pb.HTTPDNSNodeServiceClient HTTPDNSClusterRPC pb.HTTPDNSClusterServiceClient HTTPDNSAppRPC pb.HTTPDNSAppServiceClient @@ -47,7 +47,6 @@ type RPCClient struct { totalCostMs int64 } - func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { if apiConfig == nil { return nil, errors.New("api config should not be nil") @@ -55,6 +54,7 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { client := &RPCClient{apiConfig: apiConfig} client.NodeTaskRPC = pb.NewNodeTaskServiceClient(client) + client.NodeValueRPC = pb.NewNodeValueServiceClient(client) client.HTTPDNSNodeRPC = pb.NewHTTPDNSNodeServiceClient(client) client.HTTPDNSClusterRPC = pb.NewHTTPDNSClusterServiceClient(client) client.HTTPDNSAppRPC = pb.NewHTTPDNSAppServiceClient(client) @@ -212,7 +212,6 @@ func (c *RPCClient) GetAndResetMetrics() (total int64, failed int64, avgCostSeco return } - func (c *RPCClient) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { conn := c.pickConn() if conn == nil { diff --git a/EdgeNode/.gitignore b/EdgeNode/.gitignore index e3ed1cd..877a92d 100644 --- a/EdgeNode/.gitignore +++ b/EdgeNode/.gitignore @@ -8,6 +8,8 @@ configs/api_node.yaml # Build binaries bin/ +libs/ +.third_party_build/ # Runtime Data data/ diff --git a/EdgeNode/build/build-libs-ubuntu2204.sh b/EdgeNode/build/build-libs-ubuntu2204.sh new file mode 100755 index 0000000..35b0b1f --- /dev/null +++ b/EdgeNode/build/build-libs-ubuntu2204.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash +set -euo pipefail + +function host-goarch() { + case "$(uname -m)" in + x86_64|amd64) + echo "amd64" + ;; + aarch64|arm64) + echo "arm64" + ;; + *) + echo "" + ;; + esac +} + +function require-command() { + local command_name=$1 + if ! command -v "$command_name" >/dev/null 2>&1; then + echo "missing required command: $command_name" + return 1 + fi +} + +function cpu_count() { + if command -v nproc >/dev/null 2>&1; then + nproc + else + getconf _NPROCESSORS_ONLN + fi +} + +function download() { + local url=$1 + local output=$2 + if [ ! -f "$output" ]; then + curl -fsSL "$url" -o "$output" + fi +} + +function prepare-dir() { + local dir=$1 + rm -rf "$dir" + mkdir -p "$dir" +} + +function copy-tree() { + local from_dir=$1 + local to_dir=$2 + rm -rf "$to_dir" + mkdir -p "$to_dir" + cp -a "$from_dir"/. "$to_dir"/ +} + +function copy-static-lib() { + local pattern=$1 + local destination=$2 + local source_path="" + + source_path=$(find "$(dirname "$pattern")" -type f -name "$(basename "$pattern")" | head -n 1) + if [ -z "$source_path" ]; then + echo "missing static library: $pattern" + return 1 + fi + + cp "$source_path" "$destination" +} + +ROOT=$(cd "$(dirname "$0")/.." && pwd) +ARCH=${1:-$(host-goarch)} +HOST_ARCH=$(host-goarch) +LIBPCAP_VERSION=${LIBPCAP_VERSION:-1.10.5} +BROTLI_VERSION=${BROTLI_VERSION:-1.1.0} +WORKDIR=${WORKDIR:-"$ROOT/.third_party_build"} +DOWNLOAD_DIR="$WORKDIR/downloads" +SOURCE_DIR="$WORKDIR/sources" +BUILD_DIR="$WORKDIR/build" +LIBPCAP_URL="https://www.tcpdump.org/release/libpcap-${LIBPCAP_VERSION}.tar.gz" +BROTLI_URL="https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz" + +if [ -z "$ARCH" ]; then + echo "unsupported host architecture: $(uname -m)" + echo "usage: $0 [amd64|arm64]" + exit 1 +fi + +if [ "$ARCH" != "amd64" ] && [ "$ARCH" != "arm64" ]; then + echo "unsupported architecture: $ARCH" + echo "supported architectures: amd64 arm64" + exit 1 +fi + +if [ -n "$HOST_ARCH" ] && [ "$ARCH" != "$HOST_ARCH" ]; then + echo "this helper only builds native Ubuntu 22.04 static libraries" + echo "host arch: ${HOST_ARCH}, requested arch: ${ARCH}" + exit 1 +fi + +for tool in curl tar make cmake gcc g++ ar ranlib; do + require-command "$tool" +done + +mkdir -p "$DOWNLOAD_DIR" "$SOURCE_DIR" "$BUILD_DIR" + +echo "building third-party static libraries for ${ARCH} ..." +echo "workspace: $WORKDIR" + +LIBPCAP_ARCHIVE="$DOWNLOAD_DIR/libpcap-${LIBPCAP_VERSION}.tar.gz" +BROTLI_ARCHIVE="$DOWNLOAD_DIR/brotli-${BROTLI_VERSION}.tar.gz" + +download "$LIBPCAP_URL" "$LIBPCAP_ARCHIVE" +download "$BROTLI_URL" "$BROTLI_ARCHIVE" + +LIBPCAP_SOURCE="$SOURCE_DIR/libpcap-${LIBPCAP_VERSION}" +BROTLI_SOURCE="$SOURCE_DIR/brotli-${BROTLI_VERSION}" +prepare-dir "$LIBPCAP_SOURCE" +prepare-dir "$BROTLI_SOURCE" + +tar -xzf "$LIBPCAP_ARCHIVE" -C "$LIBPCAP_SOURCE" --strip-components=1 +tar -xzf "$BROTLI_ARCHIVE" -C "$BROTLI_SOURCE" --strip-components=1 + +LIBPCAP_BUILD="$BUILD_DIR/libpcap-${ARCH}" +BROTLI_BUILD_SOURCE="$BUILD_DIR/brotli-source-${ARCH}" +BROTLI_BUILD_DIR="$BUILD_DIR/brotli-build-${ARCH}" +prepare-dir "$LIBPCAP_BUILD" +prepare-dir "$BROTLI_BUILD_SOURCE" +prepare-dir "$BROTLI_BUILD_DIR" + +cp -a "$LIBPCAP_SOURCE"/. "$LIBPCAP_BUILD"/ +cp -a "$BROTLI_SOURCE"/. "$BROTLI_BUILD_SOURCE"/ + +pushd "$LIBPCAP_BUILD" >/dev/null +./configure \ + --disable-shared \ + --enable-static \ + --without-dbus \ + --without-libnl \ + --without-bluetooth \ + --without-dag \ + --without-septel \ + --without-snf \ + --without-turbocap \ + --without-rdma \ + --without-netmap \ + CFLAGS="-O2 -fPIC" +make -j"$(cpu_count)" +popd >/dev/null + +cmake -S "$BROTLI_BUILD_SOURCE" -B "$BROTLI_BUILD_DIR" \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DBROTLI_DISABLE_TESTS=ON \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON +cmake --build "$BROTLI_BUILD_DIR" --parallel "$(cpu_count)" + +mkdir -p "$ROOT/libs/libpcap/${ARCH}" +mkdir -p "$ROOT/libs/libbrotli/${ARCH}" +mkdir -p "$ROOT/libs/libpcap/src" +mkdir -p "$ROOT/libs/libbrotli/src" + +cp "$LIBPCAP_BUILD/libpcap.a" "$ROOT/libs/libpcap/${ARCH}/libpcap.a" +copy-tree "$LIBPCAP_BUILD" "$ROOT/libs/libpcap/src/libpcap" + +copy-static-lib "$BROTLI_BUILD_DIR/libbrotlicommon*.a" "$ROOT/libs/libbrotli/${ARCH}/libbrotlicommon.a" +copy-static-lib "$BROTLI_BUILD_DIR/libbrotlidec*.a" "$ROOT/libs/libbrotli/${ARCH}/libbrotlidec.a" +copy-static-lib "$BROTLI_BUILD_DIR/libbrotlienc*.a" "$ROOT/libs/libbrotli/${ARCH}/libbrotlienc.a" +copy-tree "$BROTLI_SOURCE" "$ROOT/libs/libbrotli/src/brotli" + +echo "done" +echo "generated:" +echo " $ROOT/libs/libpcap/${ARCH}/libpcap.a" +echo " $ROOT/libs/libbrotli/${ARCH}/libbrotlicommon.a" +echo " $ROOT/libs/libbrotli/${ARCH}/libbrotlidec.a" +echo " $ROOT/libs/libbrotli/${ARCH}/libbrotlienc.a" +echo "" +echo "next:" +echo " cd \"$ROOT/build\" && ./build.sh linux ${ARCH} plus" diff --git a/EdgeNode/build/build.sh b/EdgeNode/build/build.sh index bf7991f..fb9a0f8 100644 --- a/EdgeNode/build/build.sh +++ b/EdgeNode/build/build.sh @@ -1,42 +1,217 @@ #!/usr/bin/env bash +function find-binary() { + local candidate + for candidate in "$@"; do + if [ -z "$candidate" ]; then + continue + fi + if [ -x "$candidate" ]; then + echo "$candidate" + return 0 + fi + if command -v "$candidate" >/dev/null 2>&1; then + command -v "$candidate" + return 0 + fi + done + return 1 +} + +function host-goarch() { + case "$(uname -m)" in + x86_64|amd64) + echo "amd64" + ;; + aarch64|arm64) + echo "arm64" + ;; + i386|i486|i586|i686) + echo "386" + ;; + mips64) + echo "mips64" + ;; + mips64el) + echo "mips64le" + ;; + *) + echo "" + ;; + esac +} + +function find-linux-static-toolchain() { + local arch=$1 + local cc_bin="" + local cxx_bin="" + local host_arch + + host_arch=$(host-goarch) + + case "$arch" in + amd64) + cc_bin=$(find-binary \ + "/usr/local/gcc/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-gcc" \ + "/usr/local/opt/musl-cross/bin/x86_64-linux-musl-gcc" \ + "x86_64-unknown-linux-gnu-gcc" \ + "x86_64-linux-musl-gcc" \ + "musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/gcc/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-g++" \ + "/usr/local/opt/musl-cross/bin/x86_64-linux-musl-g++" \ + "x86_64-unknown-linux-gnu-g++" \ + "x86_64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "amd64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "amd64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + 386) + cc_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/i486-linux-musl-gcc" \ + "i486-linux-musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/i486-linux-musl-g++" \ + "i486-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "386" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "386" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + arm64) + cc_bin=$(find-binary \ + "/usr/local/gcc/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-gcc" \ + "/usr/local/opt/musl-cross/bin/aarch64-linux-musl-gcc" \ + "aarch64-unknown-linux-gnu-gcc" \ + "aarch64-linux-musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/gcc/aarch64-unknown-linux-gnu/bin/aarch64-unknown-linux-gnu-g++" \ + "/usr/local/opt/musl-cross/bin/aarch64-linux-musl-g++" \ + "aarch64-unknown-linux-gnu-g++" \ + "aarch64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "arm64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "arm64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + arm) + cc_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/arm-linux-musleabi-gcc" \ + "arm-linux-musleabi-gcc") + cxx_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/arm-linux-musleabi-g++" \ + "arm-linux-musleabi-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "arm" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "arm" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + mips64) + cc_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/mips64-linux-musl-gcc" \ + "mips64-linux-musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/mips64-linux-musl-g++" \ + "mips64-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "mips64" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "mips64" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + mips64le) + cc_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/mips64el-linux-musl-gcc" \ + "mips64el-linux-musl-gcc") + cxx_bin=$(find-binary \ + "/usr/local/opt/musl-cross/bin/mips64el-linux-musl-g++" \ + "mips64el-linux-musl-g++") + if [ -z "$cc_bin" ] && [ "$host_arch" = "mips64le" ]; then + cc_bin=$(find-binary "gcc" "cc" "clang") + fi + if [ -z "$cxx_bin" ] && [ "$host_arch" = "mips64le" ]; then + cxx_bin=$(find-binary "g++" "c++" "clang++") + fi + ;; + *) + return 1 + ;; + esac + + if [ -z "$cc_bin" ]; then + return 1 + fi + if [ -z "$cxx_bin" ]; then + cxx_bin="$cc_bin" + fi + + echo "$cc_bin|$cxx_bin" + return 0 +} + +function require-packet-static-libs() { + local srcdir=$1 + local arch=$2 + local missing=0 + local file + + for file in \ + "${srcdir}/libs/libpcap/${arch}/libpcap.a" \ + "${srcdir}/libs/libbrotli/${arch}/libbrotlienc.a" \ + "${srcdir}/libs/libbrotli/${arch}/libbrotlidec.a" \ + "${srcdir}/libs/libbrotli/${arch}/libbrotlicommon.a"; do + if [ ! -f "$file" ]; then + echo "missing required plus packet library: $file" + missing=1 + fi + done + + if [ "$missing" -ne 0 ]; then + return 1 + fi + + return 0 +} + function build() { - ROOT=$(dirname $0) + ROOT=$(dirname "$0") NAME="edge-node" VERSION=$(lookup-version "$ROOT"/../internal/const/const.go) DIST=$ROOT/"../dist/${NAME}" - MUSL_DIR="/usr/local/opt/musl-cross/bin" SRCDIR=$(realpath "$ROOT/..") - - # for macOS users: precompiled gcc can be downloaded from https://github.com/messense/homebrew-macos-cross-toolchains - GCC_X86_64_DIR="/usr/local/gcc/x86_64-unknown-linux-gnu/bin" - GCC_ARM64_DIR="/usr/local/gcc/aarch64-unknown-linux-gnu/bin" - OS=${1} ARCH=${2} TAG=${3} if [ -z "$OS" ]; then echo "usage: build.sh OS ARCH" - exit + exit 1 fi if [ -z "$ARCH" ]; then echo "usage: build.sh OS ARCH" - exit + exit 1 fi if [ -z "$TAG" ]; then TAG="community" fi echo "checking ..." - ZIP_PATH=$(which zip) - if [ -z "$ZIP_PATH" ]; then + if ! command -v zip >/dev/null 2>&1; then echo "we need 'zip' command to compress files" - exit + exit 1 fi echo "building v${VERSION}/${OS}/${ARCH}/${TAG} ..." - # 生成 zip 文件名时不包含 plus 标记 if [ "${TAG}" = "plus" ]; then ZIP="${NAME}-${OS}-${ARCH}-v${VERSION}.zip" else @@ -63,11 +238,8 @@ function build() { cp -R "$ROOT"/pages "$DIST"/ copy_fluent_bit_assets "$ROOT" "$DIST" "$OS" "$ARCH" || exit 1 - # we support TOA on linux only - if [ "$OS" == "linux" ] && [ -f "${ROOT}/edge-toa/edge-toa-${ARCH}" ] - then - if [ ! -d "$DIST/edge-toa" ] - then + if [ "$OS" == "linux" ] && [ -f "${ROOT}/edge-toa/edge-toa-${ARCH}" ]; then + if [ ! -d "$DIST/edge-toa" ]; then mkdir "$DIST/edge-toa" fi cp "${ROOT}/edge-toa/edge-toa-${ARCH}" "$DIST/edge-toa/edge-toa" @@ -75,96 +247,59 @@ function build() { echo "building ..." - CC_PATH="" - CXX_PATH="" + CC_BIN="" + CXX_BIN="" CGO_LDFLAGS="" CGO_CFLAGS="" BUILD_TAG=$TAG - if [[ `uname -a` == *"Darwin"* && "${OS}" == "linux" ]]; then - if [ "${ARCH}" == "amd64" ]; then - # build with script support - if [ -d $GCC_X86_64_DIR ]; then - MUSL_DIR=$GCC_X86_64_DIR - CC_PATH="x86_64-unknown-linux-gnu-gcc" - CXX_PATH="x86_64-unknown-linux-gnu-g++" - if [ "$TAG" = "plus" ]; then - BUILD_TAG="plus,script,packet" - fi - else - CC_PATH="x86_64-linux-musl-gcc" - CXX_PATH="x86_64-linux-musl-g++" - fi - fi - if [ "${ARCH}" == "386" ]; then - CC_PATH="i486-linux-musl-gcc" - CXX_PATH="i486-linux-musl-g++" - fi - if [ "${ARCH}" == "arm64" ]; then - # build with script support - if [ -d $GCC_ARM64_DIR ]; then - MUSL_DIR=$GCC_ARM64_DIR - CC_PATH="aarch64-unknown-linux-gnu-gcc" - CXX_PATH="aarch64-unknown-linux-gnu-g++" - if [ "$TAG" = "plus" ]; then - BUILD_TAG="plus,script,packet" - fi - else - CC_PATH="aarch64-linux-musl-gcc" - CXX_PATH="aarch64-linux-musl-g++" - fi - fi - if [ "${ARCH}" == "arm" ]; then - CC_PATH="arm-linux-musleabi-gcc" - CXX_PATH="arm-linux-musleabi-g++" - fi - if [ "${ARCH}" == "mips64" ]; then - CC_PATH="mips64-linux-musl-gcc" - CXX_PATH="mips64-linux-musl-g++" - fi - if [ "${ARCH}" == "mips64le" ]; then - CC_PATH="mips64el-linux-musl-gcc" - CXX_PATH="mips64el-linux-musl-g++" - fi - fi - # libpcap - if [ "$OS" == "linux" ] && [[ "$ARCH" == "amd64" || "$ARCH" == "arm64" ]] && [ "$TAG" == "plus" ]; then + if [ "$OS" == "linux" ] && [[ "$ARCH" == "amd64" || "$ARCH" == "arm64" ]] && [ "$TAG" == "plus" ]; then + require-packet-static-libs "$SRCDIR" "$ARCH" || exit 1 + BUILD_TAG="plus,script,packet" CGO_LDFLAGS="-L${SRCDIR}/libs/libpcap/${ARCH} -lpcap -L${SRCDIR}/libs/libbrotli/${ARCH} -lbrotlienc -lbrotlidec -lbrotlicommon" CGO_CFLAGS="-I${SRCDIR}/libs/libpcap/src/libpcap -I${SRCDIR}/libs/libpcap/src/libpcap/pcap -I${SRCDIR}/libs/libbrotli/src/brotli/c/include -I${SRCDIR}/libs/libbrotli/src/brotli/c/include/brotli" fi - if [ ! -z $CC_PATH ]; then - env CC=$MUSL_DIR/$CC_PATH \ - CXX=$MUSL_DIR/$CXX_PATH GOOS="${OS}" \ - GOARCH="${ARCH}" CGO_ENABLED=1 \ - CGO_LDFLAGS="${CGO_LDFLAGS}" \ - CGO_CFLAGS="${CGO_CFLAGS}" \ - go build -trimpath -tags $BUILD_TAG -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-node/main.go - else - if [[ `uname` == *"Linux"* ]] && [ "$OS" == "linux" ] && [[ "$ARCH" == "amd64" || "$ARCH" == "arm64" ]] && [ "$TAG" == "plus" ]; then - BUILD_TAG="plus,script,packet" + if [ "$OS" == "linux" ]; then + TOOLCHAIN=$(find-linux-static-toolchain "$ARCH") + if [ -z "$TOOLCHAIN" ]; then + echo "could not find a static Linux toolchain for ${ARCH}" + echo "install a musl cross compiler or provide /usr/local/gcc toolchains before building" + exit 1 fi - env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 CGO_LDFLAGS="${CGO_LDFLAGS}" CGO_CFLAGS="${CGO_CFLAGS}" go build -trimpath -tags $BUILD_TAG -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-node/main.go + CC_BIN=${TOOLCHAIN%|*} + CXX_BIN=${TOOLCHAIN#*|} + + env CC="$CC_BIN" \ + CXX="$CXX_BIN" \ + GOOS="${OS}" \ + GOARCH="${ARCH}" \ + CGO_ENABLED=1 \ + CGO_LDFLAGS="${CGO_LDFLAGS}" \ + CGO_CFLAGS="${CGO_CFLAGS}" \ + go build -trimpath -tags "$BUILD_TAG" -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-node/main.go + else + env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 CGO_LDFLAGS="${CGO_LDFLAGS}" CGO_CFLAGS="${CGO_CFLAGS}" \ + go build -trimpath -tags "$BUILD_TAG" -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-node/main.go fi if [ ! -f "${DIST}/bin/${NAME}" ]; then echo "build failed!" - exit + exit 1 fi - # delete hidden files find "$DIST" -name ".DS_Store" -delete find "$DIST" -name ".gitignore" -delete echo "zip files" - cd "${DIST}/../" || exit + cd "${DIST}/../" || exit 1 if [ -f "${ZIP}" ]; then rm -f "${ZIP}" fi zip -r -X -q "${ZIP}" ${NAME}/ rm -rf ${NAME} - cd - || exit + cd - || exit 1 echo "OK" } @@ -253,7 +388,7 @@ function lookup-version() { echo "$VERSION" else echo "could not match version" - exit + exit 1 fi } diff --git a/EdgeNode/build/data/disk.speed.json b/EdgeNode/build/data/disk.speed.json index 8ed61c3..30eda56 100644 --- a/EdgeNode/build/data/disk.speed.json +++ b/EdgeNode/build/data/disk.speed.json @@ -1 +1 @@ -{"speed":1,"speedMB":1400,"countTests":3} \ No newline at end of file +{"speed":1,"speedMB":1510,"countTests":10} \ No newline at end of file diff --git a/EdgeNode/build/sudo-run-plus.sh b/EdgeNode/build/sudo-run-plus.sh index 504f632..c928833 100644 --- a/EdgeNode/build/sudo-run-plus.sh +++ b/EdgeNode/build/sudo-run-plus.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -sudo go run -tags="plus script packet" ../cmd/edge-node/main.go \ No newline at end of file +sudo go run -tags="plus script" ../cmd/edge-node/main.go diff --git a/EdgeNode/go.mod b/EdgeNode/go.mod index 797b2d3..9c23502 100644 --- a/EdgeNode/go.mod +++ b/EdgeNode/go.mod @@ -20,7 +20,6 @@ require ( github.com/dchest/captcha v0.0.0-00010101000000-000000000000 github.com/fsnotify/fsnotify v1.7.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/google/gopacket v1.1.19 github.com/google/nftables v0.2.0 github.com/huaweicloud/huaweicloud-sdk-go-obs v3.24.9+incompatible github.com/iwind/TeaGo v0.0.0-20240411075713-6c1fc9aca7b6 diff --git a/EdgeNode/go.sum b/EdgeNode/go.sum index ba857d7..bd6df05 100644 --- a/EdgeNode/go.sum +++ b/EdgeNode/go.sum @@ -67,8 +67,6 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8= github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= diff --git a/EdgeNode/internal/const/const.go b/EdgeNode/internal/const/const.go index ae07326..da970cc 100644 --- a/EdgeNode/internal/const/const.go +++ b/EdgeNode/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "1.4.9" //1.3.8.2 + Version = "1.5.0" //1.3.8.2 ProductName = "Edge Node" ProcessName = "edge-node" diff --git a/EdgeNode/internal/network-security/manager.go b/EdgeNode/internal/network-security/manager.go deleted file mode 100644 index c43b06e..0000000 --- a/EdgeNode/internal/network-security/manager.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package networksecurity - -import ( - "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - teaconst "github.com/TeaOSLab/EdgeNode/internal/const" - "github.com/TeaOSLab/EdgeNode/internal/events" - "github.com/TeaOSLab/EdgeNode/internal/monitor" - "github.com/TeaOSLab/EdgeNode/internal/remotelogs" - "github.com/TeaOSLab/EdgeNode/internal/utils" - "github.com/TeaOSLab/EdgeNode/internal/utils/goman" - "github.com/TeaOSLab/EdgeNode/internal/utils/netpackets" - "github.com/iwind/TeaGo/Tea" - "github.com/iwind/TeaGo/maps" - "runtime" - "time" -) - -var SharedManager = NewManager() - -func init() { - if !teaconst.IsMain { - return - } - - events.On(events.EventLoaded, func() { - nodeConfig, _ := nodeconfigs.SharedNodeConfig() - if nodeConfig != nil { - go SharedManager.Apply(nodeConfig.NetworkSecurityPolicy) - } - }) - - events.On(events.EventQuit, func() { - go SharedManager.Apply(nil) - }) - - goman.New(func() { - var ticker = time.NewTicker(1 * time.Minute) - for range ticker.C { - SharedManager.Upload() - } - }) -} - -type Manager struct { - listener *netpackets.Listener - isRunning bool - - policy *nodeconfigs.NetworkSecurityPolicy - - totalTCPPacketsMinutely uint64 - totalUDPPacketsMinutely uint64 - totalICMPPacketsMinutely uint64 -} - -func NewManager() *Manager { - return &Manager{} -} - -// Apply 应用配置 -// 非线程安全 -func (this *Manager) Apply(policy *nodeconfigs.NetworkSecurityPolicy) { - if this.policy != nil && this.policy.IsSame(policy) { - return - } - - this.policy = policy - - if policy == nil || - policy.Status == nodeconfigs.NetworkSecurityStatusOff || - (policy.Status == nodeconfigs.NetworkSecurityStatusAuto && runtime.NumCPU() < 8) { - if this.listener != nil { - remotelogs.Println("NETWORK_SECURITY_MANAGER", "stop") - this.listener.Stop() - } - this.isRunning = false - return - } - - if this.listener == nil { - this.listener = netpackets.NewListener() - - // References: - // - https://biot.com/capstats/bpf.html - // - https://www.ibm.com/docs/en/qsip/7.4?topic=queries-berkeley-packet-filters - // - https://www.tcpdump.org/manpages/tcpdump.1.html - - if Tea.IsTesting() || utils.IsDebugEnv() { // dev environment - this.listener.SetBPF("(tcp or udp or icmp) and not net 127 and not net ::1") - } else { - this.listener.SetBPF("(tcp or udp or icmp) and not src net 127 and not src net 192.168 and not src net 172.16 and not src net ::1 and not src net 10") - } - this.listener.AddFilter(this) - } - - if !this.isRunning { - this.isRunning = true - remotelogs.Println("NETWORK_SECURITY_MANAGER", "start") - err := this.listener.Start() // long run function - if err != nil { - remotelogs.Error("NETWORK_SECURITY_MANAGER", "start listener failed: "+err.Error()) - } - this.isRunning = false - } -} - -func (this *Manager) FilterMeta(meta *netpackets.PacketMeta) { - switch meta.LayerType { - case netpackets.LayerTypeTCP: - // 这里不需要试用atomic,因为数据不需要那么精确 - this.totalTCPPacketsMinutely++ - case netpackets.LayerTypeUDP: - this.totalUDPPacketsMinutely++ - case netpackets.LayerTypeICMPv4, netpackets.LayerTypeICMPv6: - this.totalICMPPacketsMinutely++ - } -} - -func (this *Manager) Upload() { - if !this.isRunning { - return - } - - monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemNetworkPackets, maps.Map{ - "tcpInPPS": this.totalTCPPacketsMinutely / 60, - "udpInPPS": this.totalUDPPacketsMinutely / 60, - "icmpInPPS": this.totalICMPPacketsMinutely / 60, - }) - - this.totalTCPPacketsMinutely = 0 - this.totalUDPPacketsMinutely = 0 - this.totalICMPPacketsMinutely = 0 -} diff --git a/EdgeNode/internal/network-security/manager_test.go b/EdgeNode/internal/network-security/manager_test.go deleted file mode 100644 index f8238ca..0000000 --- a/EdgeNode/internal/network-security/manager_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package networksecurity_test - -import ( - "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - networksecurity "github.com/TeaOSLab/EdgeNode/internal/network-security" - "github.com/TeaOSLab/EdgeNode/internal/utils/testutils" - "os" - "testing" -) - -func TestManager_Apply(t *testing.T) { - if !testutils.IsSingleTesting() { - if os.Getgid() > 0 { - return - } - } - - var manager = networksecurity.NewManager() - var policy = nodeconfigs.NewNetworkSecurityPolicy() - manager.Apply(policy) -} diff --git a/EdgeNode/internal/network-security/manager_test.sh b/EdgeNode/internal/network-security/manager_test.sh deleted file mode 100644 index 827b691..0000000 --- a/EdgeNode/internal/network-security/manager_test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -sudo go test -v -tags="plus packet" -run '^TestManager_Apply' \ No newline at end of file diff --git a/EdgeNode/internal/nodes/http_request_auth.go b/EdgeNode/internal/nodes/http_request_auth.go index a8ac153..595de03 100644 --- a/EdgeNode/internal/nodes/http_request_auth.go +++ b/EdgeNode/internal/nodes/http_request_auth.go @@ -9,14 +9,20 @@ import ( "net/http" ) -// 执行认证 +// 鎵ц璁よ瘉 func (this *HTTPRequest) doAuth() (shouldStop bool) { if this.web.Auth == nil || !this.web.Auth.IsOn { return } for _, ref := range this.web.Auth.PolicyRefs { - if !ref.IsOn || ref.AuthPolicy == nil || !ref.AuthPolicy.IsOn { + if !ref.IsOn { + continue + } + if ref.AuthPolicy == nil { + continue + } + if !ref.AuthPolicy.IsOn { continue } if !ref.AuthPolicy.MatchRequest(this.RawReq) { @@ -36,7 +42,7 @@ func (this *HTTPRequest) doAuth() (shouldStop bool) { return writer.StatusCode(), nil }, this.Format) if err != nil { - this.write50x(err, http.StatusInternalServerError, "Failed to execute the AuthPolicy", "认证策略执行失败", false) + this.write50x(err, http.StatusInternalServerError, "Failed to execute the AuthPolicy", "璁よ瘉绛栫暐鎵ц澶辫触", false) return } if ok { @@ -45,28 +51,28 @@ func (this *HTTPRequest) doAuth() (shouldStop bool) { } this.tags = append(this.tags, "auth:"+ref.AuthPolicy.Type) return - } else { - // Basic Auth比较特殊 - if ref.AuthPolicy.Type == serverconfigs.HTTPAuthTypeBasicAuth { - method, ok := ref.AuthPolicy.Method().(*serverconfigs.HTTPAuthBasicMethod) - if ok { - var headerValue = "Basic realm=\"" - if len(method.Realm) > 0 { - headerValue += method.Realm - } else { - headerValue += this.ReqHost - } - headerValue += "\"" - if len(method.Charset) > 0 { - headerValue += ", charset=\"" + method.Charset + "\"" - } - this.writer.Header()["WWW-Authenticate"] = []string{headerValue} - } - } - this.writer.WriteHeader(http.StatusUnauthorized) - this.tags = append(this.tags, "auth:"+ref.AuthPolicy.Type) - return true } + + // Basic Auth 姣旇緝鐗规畩 + if ref.AuthPolicy.Type == serverconfigs.HTTPAuthTypeBasicAuth { + method, ok := ref.AuthPolicy.Method().(*serverconfigs.HTTPAuthBasicMethod) + if ok { + var headerValue = "Basic realm=\"" + if len(method.Realm) > 0 { + headerValue += method.Realm + } else { + headerValue += this.ReqHost + } + headerValue += "\"" + if len(method.Charset) > 0 { + headerValue += ", charset=\"" + method.Charset + "\"" + } + this.writer.Header()["WWW-Authenticate"] = []string{headerValue} + } + } + this.writer.WriteHeader(http.StatusUnauthorized) + this.tags = append(this.tags, "auth:"+ref.AuthPolicy.Type) + return true } return } diff --git a/EdgeNode/internal/nodes/node_tasks_packet_plus.go b/EdgeNode/internal/nodes/node_tasks_packet_plus.go deleted file mode 100644 index 867d4df..0000000 --- a/EdgeNode/internal/nodes/node_tasks_packet_plus.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package nodes - -import ( - "encoding/json" - "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" - networksecurity "github.com/TeaOSLab/EdgeNode/internal/network-security" - "github.com/TeaOSLab/EdgeNode/internal/remotelogs" - "github.com/TeaOSLab/EdgeNode/internal/rpc" -) - -func (this *Node) execNetworkSecurityPolicyChangedTask(rpcClient *rpc.RPCClient) error { - remotelogs.Println("NODE", "updating network security policy ...") - resp, err := rpcClient.NodeRPC.FindNodeNetworkSecurityPolicy(rpcClient.Context(), &pb.FindNodeNetworkSecurityPolicyRequest{}) - if err != nil { - return err - } - - var policy = nodeconfigs.NewNetworkSecurityPolicy() - if len(resp.NetworkSecurityPolicyJSON) > 0 { - err = json.Unmarshal(resp.NetworkSecurityPolicyJSON, policy) - if err != nil { - return err - } - } - - sharedNodeConfig.NetworkSecurityPolicy = policy - - go networksecurity.SharedManager.Apply(policy) - - return nil -} diff --git a/EdgeNode/internal/nodes/node_tasks_packet_stub_plus.go b/EdgeNode/internal/nodes/node_tasks_packet_stub_plus.go index edd1f73..0795cc1 100644 --- a/EdgeNode/internal/nodes/node_tasks_packet_stub_plus.go +++ b/EdgeNode/internal/nodes/node_tasks_packet_stub_plus.go @@ -1,5 +1,5 @@ // Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && !packet +//go:build plus package nodes diff --git a/EdgeNode/internal/utils/netpackets/filter_interface.go b/EdgeNode/internal/utils/netpackets/filter_interface.go deleted file mode 100644 index cc3e18e..0000000 --- a/EdgeNode/internal/utils/netpackets/filter_interface.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package netpackets - -type FilterInterface interface { - FilterMeta(meta *PacketMeta) -} diff --git a/EdgeNode/internal/utils/netpackets/ignored_ip_list.go b/EdgeNode/internal/utils/netpackets/ignored_ip_list.go deleted file mode 100644 index 89ce7e6..0000000 --- a/EdgeNode/internal/utils/netpackets/ignored_ip_list.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus - -package netpackets - -import ( - "github.com/TeaOSLab/EdgeNode/internal/utils/linkedlist" - "sync" -) - -type IgnoredIPList struct { - mu sync.RWMutex - - itemMap map[string]*linkedlist.Item[string] // linked => item - list *linkedlist.List[string] - - capacity int - lastIP string -} - -func NewIgnoredIPList(capacity int) *IgnoredIPList { - return &IgnoredIPList{ - itemMap: map[string]*linkedlist.Item[string]{}, - list: linkedlist.NewList[string](), - capacity: capacity, - } -} - -func (this *IgnoredIPList) Add(ip string) { - this.mu.Lock() - defer this.mu.Unlock() - - if this.lastIP == ip { - return - } - this.lastIP = ip - - item, ok := this.itemMap[ip] - if !ok { - if this.capacity > 0 && len(this.itemMap) == this.capacity { - var firstItem = this.list.Shift() - if firstItem != nil { - delete(this.itemMap, firstItem.Value) - } - } - - item = linkedlist.NewItem[string](ip) - this.itemMap[ip] = item - } - this.list.Push(item) -} - -func (this *IgnoredIPList) Remove(ip string) { - this.mu.Lock() - defer this.mu.Unlock() - - item, ok := this.itemMap[ip] - if ok { - delete(this.itemMap, ip) - this.list.Remove(item) - } -} - -func (this *IgnoredIPList) Contains(ip string) bool { - this.mu.RLock() - defer this.mu.RUnlock() - _, ok := this.itemMap[ip] - return ok -} - -func (this *IgnoredIPList) List(size int) (ipList []string) { - if size <= 0 { - return - } - - this.mu.RLock() - defer this.mu.RUnlock() - - this.list.RangeReverse(func(item *linkedlist.Item[string]) (goNext bool) { - ipList = append(ipList, item.Value) - size-- - return size > 0 - }) - - return -} - -func (this *IgnoredIPList) Len() int { - this.mu.RLock() - defer this.mu.RUnlock() - return len(this.itemMap) -} diff --git a/EdgeNode/internal/utils/netpackets/ignored_ip_list_test.go b/EdgeNode/internal/utils/netpackets/ignored_ip_list_test.go deleted file mode 100644 index ee0f23b..0000000 --- a/EdgeNode/internal/utils/netpackets/ignored_ip_list_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus - -package netpackets_test - -import ( - "fmt" - "github.com/TeaOSLab/EdgeNode/internal/utils/netpackets" - "github.com/iwind/TeaGo/assert" - "github.com/iwind/TeaGo/rands" - "runtime" - "testing" -) - -func TestIgnoredIPList_Add(t *testing.T) { - var a = assert.NewAssertion(t) - - var list = netpackets.NewIgnoredIPList(10) - list.Add("192.168.2.1") - list.Add("192.168.2.2") - list.Add("192.168.2.3") - - a.IsTrue(list.Contains("192.168.2.1")) - a.IsFalse(list.Contains("192.168.2.0")) - - t.Log(list.List(0)) - t.Log(list.List(2)) - t.Log(list.List(4)) -} - -func TestIgnoredIPList_Add_Capacity(t *testing.T) { - var list = netpackets.NewIgnoredIPList(4) - list.Add("192.168.2.1") - list.Add("192.168.2.2") - list.Add("192.168.2.3") - list.Add("192.168.2.4") - list.Add("192.168.2.5") - list.Add("192.168.2.6") - list.Add("192.168.2.7") - t.Log(list.List(10)) - t.Log(list.Len(), "items") -} - -func TestIgnoredIPList_Remove(t *testing.T) { - var list = netpackets.NewIgnoredIPList(10) - list.Add("192.168.2.1") - list.Add("192.168.2.2") - list.Add("192.168.2.3") - list.Remove("192.168.2.2") - t.Log(list.List(4)) -} - -func BenchmarkIgnoredIPList_Add(b *testing.B) { - runtime.GOMAXPROCS(1) - - var genIPFunc = func() string { - return fmt.Sprintf("%d.%d.%d.%d", rands.Int(0, 255), rands.Int(0, 255), rands.Int(0, 255), rands.Int(0, 255)) - } - - var list = netpackets.NewIgnoredIPList(65535) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - list.Add(genIPFunc()) - list.Remove(genIPFunc()) - list.Contains(genIPFunc()) - if rands.Int(0, 100) == 0 { - list.List(1000) - } - } - }) -} diff --git a/EdgeNode/internal/utils/netpackets/layer_type.go b/EdgeNode/internal/utils/netpackets/layer_type.go deleted file mode 100644 index 44f95bd..0000000 --- a/EdgeNode/internal/utils/netpackets/layer_type.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package netpackets - -import ( - "github.com/google/gopacket" - "github.com/google/gopacket/layers" -) - -type LayerType = gopacket.LayerType - -var ( - LayerTypeTCP = layers.LayerTypeTCP - LayerTypeUDP = layers.LayerTypeUDP - LayerTypeICMPv4 = layers.LayerTypeICMPv4 - LayerTypeICMPv6 = layers.LayerTypeICMPv6 -) diff --git a/EdgeNode/internal/utils/netpackets/listener.go b/EdgeNode/internal/utils/netpackets/listener.go deleted file mode 100644 index d6c0d88..0000000 --- a/EdgeNode/internal/utils/netpackets/listener.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package netpackets - -import ( - "encoding/binary" - "fmt" - "github.com/TeaOSLab/EdgeNode/internal/remotelogs" - "github.com/TeaOSLab/EdgeNode/internal/utils" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/google/gopacket/pcap" - "sort" - "strings" - "time" -) - -const defaultBPFFilter = "(tcp or udp or icmp) and not net 127.0.0.1" - -type Listener struct { - filters []FilterInterface - incomingHandle *pcap.Handle - bpfFilter string - - decodeDstIP bool - - isClosed bool - - outgoingIPList *IgnoredIPList - outgoingHandle *pcap.Handle - - filterTicker *time.Ticker -} - -func NewListener() *Listener { - return &Listener{ - isClosed: true, - outgoingIPList: NewIgnoredIPList(65535), - } -} - -func (this *Listener) Start() error { - if !this.isClosed { - return nil - } - - this.isClosed = false - - go func() { - startErr := this.loopOutgoing() - if startErr != nil { - remotelogs.Error("NET_PACKET", "start outgoing packet listener failed: "+startErr.Error()) - } - }() - - go func() { - this.loopUpdateFilter() - }() - - for { // 无限 for 是为了防止意外退出 - err := this.loopIncoming() - if err != nil { - if this.isClosed { - return nil - } - - return fmt.Errorf("start packet listener failed: %w", err) - } - - if this.isClosed { - return nil - } - } -} - -func (this *Listener) AddFilter(filter FilterInterface) { - this.filters = append(this.filters, filter) -} - -func (this *Listener) SetBPF(bpfFilter string) { - this.bpfFilter = bpfFilter -} - -func (this *Listener) DecodeDstIP() { - this.decodeDstIP = true -} - -func (this *Listener) Stop() { - this.isClosed = true - this.incomingHandle.Close() - this.outgoingHandle.Close() -} - -func (this *Listener) IsRunning() bool { - return this.incomingHandle != nil && !this.isClosed -} - -func (this *Listener) loopIncoming() error { - const device = "any" - var err error - this.incomingHandle, err = pcap.OpenLive(device, 128, false /** ignore collision domain **/, pcap.BlockForever) - if err != nil { - return err - } - - defer func() { - this.incomingHandle.Close() - }() - - err = this.incomingHandle.SetDirection(pcap.DirectionIn) - if err != nil { - return err - } - - if len(this.bpfFilter) > 0 { - err = this.incomingHandle.SetBPFFilter(this.bpfFilter) - } else { - this.bpfFilter = defaultBPFFilter - err = this.incomingHandle.SetBPFFilter(defaultBPFFilter) - } - if err != nil { - return err - } - - var meta = &PacketMeta{} - - var packetSource = gopacket.NewPacketSource(this.incomingHandle, this.incomingHandle.LinkType()) - packetSource.NoCopy = true - packetSource.Lazy = true - - var filters = this.filters - var countFilters = len(filters) - - for packet := range packetSource.Packets() { - var networkLayer = packet.NetworkLayer() - if networkLayer == nil { - continue - } - - var networkFlow = networkLayer.NetworkFlow() - - var src = networkFlow.Src() - - meta.SrcIP = src.String() - - // ignore outgoing ip - if this.outgoingIPList.Contains(meta.SrcIP) { - continue - } - - if this.decodeDstIP { - meta.DstIP = networkFlow.Dst().String() - } - meta.Length = packet.Metadata().Length - - var transportLayer = packet.TransportLayer() - if transportLayer == nil { - meta.SrcPort = 0 - meta.DstPort = 0 - - switch x := networkLayer.(type) { - case *layers.IPv4: - meta.LayerType = x.NextLayerType() - case *layers.IPv6: - meta.LayerType = x.NextLayerType() - } - - // call filters - if countFilters == 1 { - filters[0].FilterMeta(meta) - } else { - for _, filter := range filters { - filter.FilterMeta(meta) - } - } - - continue - } - - var transportFlow = transportLayer.TransportFlow() - meta.SrcPort = int(binary.BigEndian.Uint16(transportFlow.Src().Raw())) - meta.LayerType = transportLayer.LayerType() - meta.DstPort = int(binary.BigEndian.Uint16(transportFlow.Dst().Raw())) - - // call filters - if countFilters == 1 { - filters[0].FilterMeta(meta) - } else { - for _, filter := range filters { - filter.FilterMeta(meta) - } - } - } - - return nil -} - -func (this *Listener) loopOutgoing() error { - const device = "any" - var err error - this.outgoingHandle, err = pcap.OpenLive(device, 128, true /** ignore collision domain **/, pcap.BlockForever) - - if err != nil { - return err - } - - defer func() { - this.outgoingHandle.Close() - }() - - err = this.outgoingHandle.SetDirection(pcap.DirectionOut) - if err != nil { - return err - } - - err = this.outgoingHandle.SetBPFFilter("tcp and tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) = 0") - if err != nil { - return err - } - - var packetSource = gopacket.NewPacketSource(this.outgoingHandle, this.outgoingHandle.LinkType()) - packetSource.NoCopy = true - packetSource.Lazy = true - - for packet := range packetSource.Packets() { - var networkLayer = packet.NetworkLayer() - if networkLayer == nil { - continue - } - - var networkFlow = networkLayer.NetworkFlow() - var dstIP = networkFlow.Dst().String() - this.outgoingIPList.Add(dstIP) - } - - return nil -} - -func (this *Listener) loopUpdateFilter() { - if this.filterTicker != nil { - return - } - - this.filterTicker = time.NewTicker(1 * time.Second) - var lastIPList []string - for range this.filterTicker.C { - if this.isClosed { - continue - } - - var ipList = this.outgoingIPList.List(512) // 基于bfp长度的限制,这里数量不能太多 - sort.Strings(ipList) - if this.equalStrings(lastIPList, ipList) { - continue - } - - lastIPList = ipList - - // apply - var incomingHandle = this.incomingHandle - if incomingHandle != nil { - var rules = []string{} - for _, ip := range ipList { - rules = append(rules, "not src host "+ip) - } - var newBPFFilter = this.bpfFilter + " and " + strings.Join(rules, " and ") - if utils.IsDebugEnv() { - remotelogs.Debug("NET_PACKET", "set new BPF filter: "+newBPFFilter) - } - err := incomingHandle.SetBPFFilter(newBPFFilter) - if err != nil { - remotelogs.Error("NET_PACKET", "set new BPF filter failed: "+err.Error()) - } - } - } -} - -func (this *Listener) equalStrings(s1 []string, s2 []string) bool { - var l = len(s1) - if len(s2) != l { - return false - } - if l == 0 { - return true - } - for i := 0; i < l; i++ { - if s1[i] != s2[i] { - return false - } - } - return true -} diff --git a/EdgeNode/internal/utils/netpackets/listener_test.go b/EdgeNode/internal/utils/netpackets/listener_test.go deleted file mode 100644 index 2717398..0000000 --- a/EdgeNode/internal/utils/netpackets/listener_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package netpackets_test - -import ( - "encoding/binary" - "github.com/TeaOSLab/EdgeNode/internal/utils/netpackets" - "github.com/TeaOSLab/EdgeNode/internal/utils/testutils" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/iwind/TeaGo/types" - "log" - "os" - "testing" - "time" -) - -type testFilter struct { -} - -func (this *testFilter) FilterMeta(meta *netpackets.PacketMeta) { - log.Println(meta.LayerType.String() + " " + meta.SrcIP + ":" + types.String(meta.SrcPort) + " => " + meta.DstIP + ":" + types.String(meta.DstPort) + " " + types.String(meta.Length) + "bytes") -} - -func TestListener_Start(t *testing.T) { - if !testutils.IsSingleTesting() { - if os.Getgid() > 0 { - return - } - } - - var listener = netpackets.NewListener() - listener.AddFilter(&testFilter{}) - - go func() { - time.Sleep(10 * time.Second) - t.Log("stopping ...") - listener.Stop() - }() - - t.Log("starting ...") - err := listener.Start() - if err != nil { - t.Fatal(err) - } -} - -func TestListener_DecodePacket_UDP(t *testing.T) { - var packetData = []byte{69, 0, 0, 134, 140, 133, 0, 0, 118, 17, 16, 79, 223, 5, 5, 5, 192, 168, 2, 224, 0, 53, 232, 163, 0, 114, 0, 0, 69, 42, 129, 128, 0, 1, 0, 3, 0, 0, 0, 0, 6, 115, 116, 97, 116, 105, 99, 7, 111, 115, 99, 104, 105, 110, 97, 3, 110, 101, 116, 0, 0, 1, 0, 1, 192, 12, 0, 5, 0, 1, 0, 0, 0, 1, 0, 25, 10, 115, 116, 97, 116, 105, 99, 45, 111, 115, 99, 2, 98, 48, 5, 97, 105, 99, 100, 110, 3, 99, 111, 109, 0, 192, 48, 0, 5, 0, 1, 0, 0, 0, 1, 0, 5, 2, 118, 109, 192, 62, 192, 85, 0, 1, 0, 1, 0, 0, 0, 1, 0, 4, 218, 28, 104, 157} - - var packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv4, gopacket.DecodeOptions{}) - var networkFlow = packet.NetworkLayer().NetworkFlow() - - t.Log(networkFlow) - - t.Log(packet.Metadata().Length) - t.Log(packet.TransportLayer().TransportFlow()) -} - -func TestListener_DecodePacket_TCP(t *testing.T) { - var packetData = []byte{69, 8, 0, 64, 6, 51, 64, 0, 52, 6, 188, 222, 74, 91, 117, 187, 192, 168, 2, 224, 1, 187, 225, 226, 137, 198, 251, 25, 221, 137, 133, 93, 176, 16, 1, 245, 224, 6, 0, 0, 1, 1, 8, 10, 30, 187, 162, 175, 35, 215, 100, 174, 1, 1, 5, 10, 221, 137, 133, 68, 221, 137, 133, 93} - - var packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv4, gopacket.DecodeOptions{}) - var networkFlow = packet.NetworkLayer().NetworkFlow() - t.Log(networkFlow.Src().Raw(), len(networkFlow.Src().Raw())) - - t.Log(networkFlow) - - t.Log(packet.Metadata().Length) - t.Log(packet.TransportLayer().TransportFlow()) -} - -func BenchmarkListener_DecodePacket(b *testing.B) { - var packetData = []byte{69, 0, 0, 134, 140, 133, 0, 0, 118, 17, 16, 79, 223, 5, 5, 5, 192, 168, 2, 224, 0, 53, 232, 163, 0, 114, 0, 0, 69, 42, 129, 128, 0, 1, 0, 3, 0, 0, 0, 0, 6, 115, 116, 97, 116, 105, 99, 7, 111, 115, 99, 104, 105, 110, 97, 3, 110, 101, 116, 0, 0, 1, 0, 1, 192, 12, 0, 5, 0, 1, 0, 0, 0, 1, 0, 25, 10, 115, 116, 97, 116, 105, 99, 45, 111, 115, 99, 2, 98, 48, 5, 97, 105, 99, 100, 110, 3, 99, 111, 109, 0, 192, 48, 0, 5, 0, 1, 0, 0, 0, 1, 0, 5, 2, 118, 109, 192, 62, 192, 85, 0, 1, 0, 1, 0, 0, 0, 1, 0, 4, 218, 28, 104, 157} - - var decodeOptions = gopacket.DecodeOptions{ - Lazy: true, - NoCopy: true, - //SkipDecodeRecovery: true, - } - - for i := 0; i < b.N; i++ { - var packet = gopacket.NewPacket(packetData, layers.LayerTypeIPv4, decodeOptions) - - var networkFlow = packet.NetworkLayer().NetworkFlow() - var src = networkFlow.Src() - var dest = networkFlow.Dst() - - _ = netpackets.IsLocalRawIPv4(src.Raw()) - _ = netpackets.IsLocalRawIPv4(dest.Raw()) - - _ = src.String() - _ = dest.String() - - _ = packet.Metadata().Length - - var transportFlow = packet.TransportLayer().TransportFlow() - //_ = transportFlow.Src().String() - //_ = transportFlow.Dst().String() - - _ = int(binary.BigEndian.Uint16(transportFlow.Src().Raw())) - _ = int(binary.BigEndian.Uint16(transportFlow.Dst().Raw())) - } -} diff --git a/EdgeNode/internal/utils/netpackets/packet_meta.go b/EdgeNode/internal/utils/netpackets/packet_meta.go deleted file mode 100644 index 27856cf..0000000 --- a/EdgeNode/internal/utils/netpackets/packet_meta.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . -//go:build plus && packet - -package netpackets - -type PacketMeta struct { - LayerType LayerType - SrcIP string - SrcPort int - DstIP string - DstPort int - Length int -} diff --git a/EdgeNode/internal/utils/netpackets/utils.go b/EdgeNode/internal/utils/netpackets/utils.go deleted file mode 100644 index 6e25c3a..0000000 --- a/EdgeNode/internal/utils/netpackets/utils.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . - -package netpackets - -// IsLocalRawIPv4 使用原始IP数据判断是否为本地IPv4 -func IsLocalRawIPv4(ip []byte) bool { - if len(ip) != 4 { - return false - } - if ip[0] == 127 || - ip[0] == 10 || - (ip[0] == 172 && ip[1]&0xf0 == 16) || - (ip[0] == 192 && ip[1] == 168) { - return true - } - - return false -} diff --git a/EdgeNode/internal/utils/netpackets/utils_test.go b/EdgeNode/internal/utils/netpackets/utils_test.go deleted file mode 100644 index 21b819a..0000000 --- a/EdgeNode/internal/utils/netpackets/utils_test.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . - -package netpackets_test - -import ( - "github.com/TeaOSLab/EdgeNode/internal/utils/netpackets" - "github.com/iwind/TeaGo/assert" - "net" - "testing" -) - -func TestIsLocalRawIPv4(t *testing.T) { - var a = assert.NewAssertion(t) - - a.IsTrue(netpackets.IsLocalRawIPv4(net.ParseIP("192.168.2.100").To4())) - a.IsTrue(netpackets.IsLocalRawIPv4(net.ParseIP("127.0.0.1").To4())) - a.IsTrue(netpackets.IsLocalRawIPv4(net.ParseIP("172.16.0.1").To4())) - a.IsTrue(netpackets.IsLocalRawIPv4(net.ParseIP("10.0.0.1").To4())) - - a.IsFalse(netpackets.IsLocalRawIPv4(net.ParseIP("1.2.3.4").To4())) -} diff --git a/EdgeReporter/internal/const/const.go b/EdgeReporter/internal/const/const.go index 5ca4e51..c2185c4 100644 --- a/EdgeReporter/internal/const/const.go +++ b/EdgeReporter/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "0.1.5" + Version = "1.5.0" ProductName = "Edge Reporter" ProcessName = "edge-reporter" diff --git a/EdgeUser/internal/const/const.go b/EdgeUser/internal/const/const.go index d085702..8ab7851 100644 --- a/EdgeUser/internal/const/const.go +++ b/EdgeUser/internal/const/const.go @@ -1,7 +1,7 @@ package teaconst const ( - Version = "1.4.9" //1.3.8.2 + Version = "1.5.0" //1.3.8.2 ProductName = "Edge User" ProcessName = "edge-user" diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 1b55a81..7e209f4 100644 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -174,6 +174,8 @@ replace_files() { # 替换 EdgeAdmin bin if [ -d "$TEMP_DIR/edge-admin/bin" ]; then log_info "替换 EdgeAdmin 可执行文件..." + rm -rf "$TARGET_DIR/bin" + mkdir -p "$TARGET_DIR/bin" cp -r "$TEMP_DIR/edge-admin/bin"/* "$TARGET_DIR/bin/" log_info "✅ EdgeAdmin bin 已更新" fi @@ -181,15 +183,9 @@ replace_files() { # 替换 EdgeAdmin web(排除 tmp) if [ -d "$TEMP_DIR/edge-admin/web" ]; then log_info "替换 EdgeAdmin 前端文件..." - if command -v rsync > /dev/null; then - rsync -av --exclude='tmp' \ - "$TEMP_DIR/edge-admin/web/" "$TARGET_DIR/web/" - else - # 如果没有 rsync,使用 cp - cp -r "$TEMP_DIR/edge-admin/web"/* "$TARGET_DIR/web/" 2>/dev/null || true - rm -rf "$TARGET_DIR/web/tmp"/* 2>/dev/null || true - fi - # 清空 tmp 目录 + rm -rf "$TARGET_DIR/web" + cp -r "$TEMP_DIR/edge-admin/web" "$TARGET_DIR/" + mkdir -p "$TARGET_DIR/web/tmp" rm -rf "$TARGET_DIR/web/tmp"/* 2>/dev/null || true log_info "✅ EdgeAdmin web 已更新" fi @@ -203,6 +199,7 @@ replace_files() { # 替换 bin if [ -d "$TEMP_DIR/edge-admin/edge-api/bin" ]; then + rm -rf "$TARGET_DIR/edge-api/bin" mkdir -p "$TARGET_DIR/edge-api/bin" cp -r "$TEMP_DIR/edge-admin/edge-api/bin"/* \ "$TARGET_DIR/edge-api/bin/" 2>/dev/null || true @@ -211,6 +208,7 @@ replace_files() { # 替换 deploy(节点安装包) if [ -d "$TEMP_DIR/edge-admin/edge-api/deploy" ]; then + rm -rf "$TARGET_DIR/edge-api/deploy" mkdir -p "$TARGET_DIR/edge-api/deploy" cp -r "$TEMP_DIR/edge-admin/edge-api/deploy"/* \ "$TARGET_DIR/edge-api/deploy/" 2>/dev/null || true @@ -219,6 +217,7 @@ replace_files() { # 替换 installers(安装工具) if [ -d "$TEMP_DIR/edge-admin/edge-api/installers" ]; then + rm -rf "$TARGET_DIR/edge-api/installers" mkdir -p "$TARGET_DIR/edge-api/installers" cp -r "$TEMP_DIR/edge-admin/edge-api/installers"/* \ "$TARGET_DIR/edge-api/installers/" 2>/dev/null || true @@ -345,4 +344,3 @@ main() { # 执行主函数 main - diff --git a/deploy/fluent-bit/packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm b/deploy/fluent-bit/packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm deleted file mode 100644 index 6a2f7a4..0000000 Binary files a/deploy/fluent-bit/packages/linux-amd64/fluent-bit-4.2.2-1.x86_64.rpm and /dev/null differ diff --git a/deploy/fluent-bit/packages/linux-amd64/fluent-bit_4.2.2_amd64.deb b/deploy/fluent-bit/packages/linux-amd64/fluent-bit_4.2.2_amd64.deb deleted file mode 100644 index 9ef01a5..0000000 Binary files a/deploy/fluent-bit/packages/linux-amd64/fluent-bit_4.2.2_amd64.deb and /dev/null differ