带阿里标识的版本

This commit is contained in:
robin
2026-02-28 18:55:33 +08:00
parent 150799f41d
commit 5d0b7c7e91
477 changed files with 10813 additions and 4044 deletions

View File

@@ -6,8 +6,10 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type AppSettingsAction struct {
@@ -52,30 +54,83 @@ func (this *AppSettingsAction) RunGet(params struct {
},
}
clusterResp, err := this.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(this.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
clusters := make([]maps.Map, 0, len(clusterResp.GetClusters()))
clusterDomainMap := map[int64]string{}
clusterNameMap := map[int64]string{}
defaultPrimaryClusterId := int64(0)
for _, cluster := range clusterResp.GetClusters() {
clusterId := cluster.GetId()
clusterName := cluster.GetName()
clusters = append(clusters, maps.Map{
"id": clusterId,
"name": clusterName,
"serviceDomain": cluster.GetServiceDomain(),
"isDefault": cluster.GetIsDefault(),
})
clusterDomainMap[clusterId] = cluster.GetServiceDomain()
clusterNameMap[clusterId] = clusterName
if defaultPrimaryClusterId <= 0 && cluster.GetIsDefault() {
defaultPrimaryClusterId = clusterId
}
}
defaultBackupClusterId := int64(0)
defaultBackupResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
}
if defaultBackupResp != nil && len(defaultBackupResp.GetValueJSON()) > 0 {
defaultBackupClusterId = types.Int64(string(defaultBackupResp.GetValueJSON()))
}
primaryClusterId := app.GetInt64("primaryClusterId")
backupClusterId := app.GetInt64("backupClusterId")
settings := maps.Map{
"appId": app.GetString("appId"),
"appStatus": app.GetBool("isOn"),
"primaryClusterId": app.GetInt64("primaryClusterId"),
"backupClusterId": app.GetInt64("backupClusterId"),
"signEnabled": app.GetBool("signEnabled"),
"signSecretPlain": app.GetString("signSecretPlain"),
"signSecretMasked": app.GetString("signSecretMasked"),
"signSecretUpdatedAt": app.GetString("signSecretUpdated"),
"appId": app.GetString("appId"),
"appStatus": app.GetBool("isOn"),
"primaryClusterId": primaryClusterId,
"backupClusterId": backupClusterId,
"defaultPrimaryClusterId": defaultPrimaryClusterId,
"defaultPrimaryClusterName": clusterNameMap[defaultPrimaryClusterId],
"defaultBackupClusterId": defaultBackupClusterId,
"defaultBackupClusterName": clusterNameMap[defaultBackupClusterId],
"primaryServiceDomain": clusterDomainMap[primaryClusterId],
"backupServiceDomain": clusterDomainMap[backupClusterId],
"signEnabled": app.GetBool("signEnabled"),
"signSecretPlain": app.GetString("signSecretPlain"),
"signSecretMasked": app.GetString("signSecretMasked"),
"signSecretUpdatedAt": app.GetString("signSecretUpdated"),
}
this.Data["app"] = app
this.Data["settings"] = settings
this.Data["clusters"] = clusters
this.Show()
}
func (this *AppSettingsAction) RunPost(params struct {
AppId int64
AppStatus bool
AppStatus bool
PrimaryClusterId int64
BackupClusterId int64
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.Field("appId", params.AppId).Gt(0, "请选择应用")
if params.PrimaryClusterId > 0 && params.BackupClusterId > 0 && params.PrimaryClusterId == params.BackupClusterId {
this.FailField("backupClusterId", "备用集群不能与主集群相同")
return
}
appResp, err := this.RPC().HTTPDNSAppRPC().FindHTTPDNSApp(this.AdminContext(), &pb.FindHTTPDNSAppRequest{
AppDbId: params.AppId,
@@ -92,8 +147,8 @@ func (this *AppSettingsAction) RunPost(params struct {
_, err = this.RPC().HTTPDNSAppRPC().UpdateHTTPDNSApp(this.AdminContext(), &pb.UpdateHTTPDNSAppRequest{
AppDbId: params.AppId,
Name: appResp.GetApp().GetName(),
PrimaryClusterId: appResp.GetApp().GetPrimaryClusterId(),
BackupClusterId: appResp.GetApp().GetBackupClusterId(),
PrimaryClusterId: params.PrimaryClusterId,
BackupClusterId: params.BackupClusterId,
IsOn: params.AppStatus,
UserId: appResp.GetApp().GetUserId(),
})

View File

@@ -55,6 +55,24 @@ func (this *CreateAction) RunGet(params struct{}) {
}
this.Data["defaultBackupClusterId"] = defaultBackupClusterId
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
Offset: 0,
Size: 10_000,
})
if err != nil {
this.ErrorPage(err)
return
}
users := make([]maps.Map, 0, len(usersResp.GetUsers()))
for _, user := range usersResp.GetUsers() {
users = append(users, maps.Map{
"id": user.GetId(),
"fullname": user.GetFullname(),
"username": user.GetUsername(),
})
}
this.Data["users"] = users
this.Show()
}

View File

@@ -18,6 +18,7 @@ func init() {
Get("/sdk", new(SdkAction)).
GetPost("/sdk/upload", new(SdkUploadAction)).
Post("/sdk/upload/delete", new(SdkUploadDeleteAction)).
Get("/sdk/check", new(SdkCheckAction)).
Get("/sdk/download", new(SdkDownloadAction)).
Get("/sdk/doc", new(SdkDocAction)).
GetPost("/app/settings", new(AppSettingsAction)).

View File

@@ -7,11 +7,20 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
timeutil "github.com/iwind/TeaGo/utils/time"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
func listAppMaps(parent *actionutils.ParentAction, keyword string) ([]maps.Map, error) {
clusterNameMap, err := loadHTTPDNSClusterNameMap(parent)
if err != nil {
return nil, err
}
userMapByID, err := loadHTTPDNSUserMap(parent)
if err != nil {
return nil, err
}
resp, err := parent.RPC().HTTPDNSAppRPC().ListHTTPDNSApps(parent.AdminContext(), &pb.ListHTTPDNSAppsRequest{
Offset: 0,
Size: 10_000,
@@ -30,13 +39,22 @@ func listAppMaps(parent *actionutils.ParentAction, keyword string) ([]maps.Map,
return nil, err
}
result = append(result, appPBToMap(app, int64(len(domainResp.GetDomains()))))
result = append(result, appPBToMap(app, int64(len(domainResp.GetDomains())), clusterNameMap, userMapByID))
}
return result, nil
}
func findAppMap(parent *actionutils.ParentAction, appDbId int64) (maps.Map, error) {
clusterNameMap, err := loadHTTPDNSClusterNameMap(parent)
if err != nil {
return nil, err
}
userMapByID, err := loadHTTPDNSUserMap(parent)
if err != nil {
return nil, err
}
if appDbId > 0 {
resp, err := parent.RPC().HTTPDNSAppRPC().FindHTTPDNSApp(parent.AdminContext(), &pb.FindHTTPDNSAppRequest{
AppDbId: appDbId,
@@ -51,7 +69,7 @@ func findAppMap(parent *actionutils.ParentAction, appDbId int64) (maps.Map, erro
if err != nil {
return nil, err
}
return appPBToMap(resp.GetApp(), int64(len(domainResp.GetDomains()))), nil
return appPBToMap(resp.GetApp(), int64(len(domainResp.GetDomains())), clusterNameMap, userMapByID), nil
}
}
@@ -259,16 +277,37 @@ func toggleCustomRule(parent *actionutils.ParentAction, ruleId int64, isOn bool)
return err
}
func appPBToMap(app *pb.HTTPDNSApp, domainCount int64) maps.Map {
func appPBToMap(app *pb.HTTPDNSApp, domainCount int64, clusterNameMap map[int64]string, userMapByID map[int64]maps.Map) maps.Map {
signSecret := app.GetSignSecret()
primaryClusterID := app.GetPrimaryClusterId()
backupClusterID := app.GetBackupClusterId()
primaryClusterMap := maps.Map{"id": primaryClusterID, "name": clusterNameMap[primaryClusterID]}
backupClusterMap := maps.Map{"id": backupClusterID, "name": clusterNameMap[backupClusterID]}
var userMap maps.Map
if app.GetUserId() > 0 {
userMap = userMapByID[app.GetUserId()]
if userMap == nil {
userMap = maps.Map{
"id": app.GetUserId(),
"fullname": "用户#" + strconv.FormatInt(app.GetUserId(), 10),
"username": "-",
}
}
}
return maps.Map{
"id": app.GetId(),
"name": app.GetName(),
"appId": app.GetAppId(),
"clusterId": app.GetPrimaryClusterId(),
"primaryClusterId": app.GetPrimaryClusterId(),
"backupClusterId": app.GetBackupClusterId(),
"clusterId": primaryClusterID,
"primaryClusterId": primaryClusterID,
"backupClusterId": backupClusterID,
"primaryCluster": primaryClusterMap,
"backupCluster": backupClusterMap,
"userId": app.GetUserId(),
"user": userMap,
"isOn": app.GetIsOn(),
"domainCount": domainCount,
"sniPolicyText": "隐匿 SNI",
@@ -279,6 +318,39 @@ func appPBToMap(app *pb.HTTPDNSApp, domainCount int64) maps.Map {
}
}
func loadHTTPDNSClusterNameMap(parent *actionutils.ParentAction) (map[int64]string, error) {
resp, err := parent.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(parent.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err != nil {
return nil, err
}
result := map[int64]string{}
for _, cluster := range resp.GetClusters() {
result[cluster.GetId()] = cluster.GetName()
}
return result, nil
}
func loadHTTPDNSUserMap(parent *actionutils.ParentAction) (map[int64]maps.Map, error) {
resp, err := parent.RPC().UserRPC().ListEnabledUsers(parent.AdminContext(), &pb.ListEnabledUsersRequest{
Offset: 0,
Size: 10_000,
})
if err != nil {
return nil, err
}
result := map[int64]maps.Map{}
for _, user := range resp.GetUsers() {
result[user.GetId()] = maps.Map{
"id": user.GetId(),
"fullname": user.GetFullname(),
"username": user.GetUsername(),
}
}
return result, nil
}
func defaultLineField(value string) string {
value = strings.TrimSpace(value)
if len(value) == 0 {

View File

@@ -0,0 +1,67 @@
package apps
import (
"net/url"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
)
type SdkCheckAction struct {
actionutils.ParentAction
}
func (this *SdkCheckAction) Init() {
this.Nav("", "", "")
}
func (this *SdkCheckAction) RunGet(params struct {
Platform string
Version string
Type string
}) {
platform, _, _, filename, err := resolveSDKPlatform(params.Platform)
if err != nil {
this.Data["exists"] = false
this.Data["message"] = err.Error()
this.Success()
return
}
t := strings.ToLower(strings.TrimSpace(params.Type))
if t == "doc" {
docPath := findUploadedSDKDocPath(platform, params.Version)
if len(docPath) == 0 {
this.Data["exists"] = false
this.Data["message"] = "Documentation is unavailable, please upload first"
this.Success()
return
}
downloadURL := "/httpdns/apps/sdk/doc?platform=" + url.QueryEscape(platform)
if len(strings.TrimSpace(params.Version)) > 0 {
downloadURL += "&version=" + url.QueryEscape(strings.TrimSpace(params.Version))
}
this.Data["exists"] = true
this.Data["url"] = downloadURL
this.Success()
return
}
archivePath := findSDKArchivePath(filename, params.Version)
if len(archivePath) == 0 {
this.Data["exists"] = false
this.Data["message"] = "SDK package is unavailable, please upload first"
this.Success()
return
}
downloadURL := "/httpdns/apps/sdk/download?platform=" + url.QueryEscape(platform)
if len(strings.TrimSpace(params.Version)) > 0 {
downloadURL += "&version=" + url.QueryEscape(strings.TrimSpace(params.Version))
}
downloadURL += "&raw=1"
this.Data["exists"] = true
this.Data["url"] = downloadURL
this.Success()
}

View File

@@ -1,10 +1,11 @@
package apps
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"os"
"path/filepath"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
)
type SdkDocAction struct {
@@ -17,15 +18,18 @@ func (this *SdkDocAction) Init() {
func (this *SdkDocAction) RunGet(params struct {
Platform string
Version string
}) {
platform, _, readmeRelativePath, _, err := resolveSDKPlatform(params.Platform)
if err != nil {
this.Fail(err.Error())
this.Data["exists"] = false
this.Data["message"] = err.Error()
this.Success()
return
}
var data []byte
uploadedDocPath := findUploadedSDKDocPath(platform)
uploadedDocPath := findUploadedSDKDocPath(platform, params.Version)
if len(uploadedDocPath) > 0 {
data, err = os.ReadFile(uploadedDocPath)
}
@@ -44,11 +48,18 @@ func (this *SdkDocAction) RunGet(params struct {
}
if len(data) == 0 || err != nil {
this.Fail("当前服务器未找到 SDK 集成文档请先在“SDK 集成”页面上传对应平台文档")
this.Data["exists"] = false
this.Data["message"] = "SDK documentation is not found on server, please upload first"
this.Success()
return
}
downloadName := filepath.Base(uploadedDocPath)
if len(downloadName) == 0 || downloadName == "." || downloadName == string(filepath.Separator) {
downloadName = "httpdns-sdk-" + strings.ToLower(platform) + ".md"
}
this.AddHeader("Content-Type", "text/markdown; charset=utf-8")
this.AddHeader("Content-Disposition", "attachment; filename=\"httpdns-sdk-"+strings.ToLower(platform)+"-README.md\";")
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
_, _ = this.ResponseWriter.Write(data)
}

View File

@@ -1,9 +1,11 @@
package apps
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"io"
"os"
"path/filepath"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
)
type SdkDownloadAction struct {
@@ -16,30 +18,48 @@ func (this *SdkDownloadAction) Init() {
func (this *SdkDownloadAction) RunGet(params struct {
Platform string
Version string
Raw int
}) {
_, _, _, filename, err := resolveSDKPlatform(params.Platform)
if err != nil {
this.Fail(err.Error())
this.Data["exists"] = false
this.Data["message"] = err.Error()
this.Success()
return
}
archivePath := findSDKArchivePath(filename)
archivePath := findSDKArchivePath(filename, params.Version)
if len(archivePath) == 0 {
this.Fail("当前服务器未找到 SDK 包请先在“SDK 集成”页面上传对应平台包: " + filename)
this.Data["exists"] = false
this.Data["message"] = "SDK archive not found on server, please upload first: " + filename
this.Success()
return
}
fp, err := os.Open(archivePath)
if err != nil {
this.Fail("打开 SDK 包失败: " + err.Error())
this.Data["exists"] = false
this.Data["message"] = "failed to open SDK archive: " + err.Error()
this.Success()
return
}
defer func() {
_ = fp.Close()
}()
this.AddHeader("Content-Type", "application/zip")
this.AddHeader("Content-Disposition", "attachment; filename=\""+filename+"\";")
downloadName := filepath.Base(archivePath)
if len(downloadName) == 0 || downloadName == "." || downloadName == string(filepath.Separator) {
downloadName = filename
}
if params.Raw == 1 {
this.AddHeader("Content-Type", "application/octet-stream")
this.AddHeader("X-SDK-Filename", downloadName)
} else {
this.AddHeader("Content-Type", "application/zip")
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
}
this.AddHeader("X-Accel-Buffering", "no")
_, _ = io.Copy(this.ResponseWriter, fp)
}

View File

@@ -2,18 +2,58 @@ package apps
import (
"errors"
"github.com/iwind/TeaGo/Tea"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/iwind/TeaGo/Tea"
)
func sdkUploadDir() string {
dirs := sdkUploadDirs()
if len(dirs) > 0 {
return dirs[0]
}
return filepath.Clean(Tea.Root + "/data/httpdns/sdk")
}
func sdkUploadDirs() []string {
candidates := []string{
filepath.Clean(Tea.Root + "/../data/httpdns/sdk"),
filepath.Clean(Tea.Root + "/data/httpdns/sdk"),
filepath.Clean(Tea.Root + "/../edge-admin/data/httpdns/sdk"),
filepath.Clean(Tea.Root + "/../edge-user/data/httpdns/sdk"),
filepath.Clean(Tea.Root + "/../../data/httpdns/sdk"),
}
results := make([]string, 0, len(candidates))
seen := map[string]bool{}
for _, dir := range candidates {
if len(dir) == 0 || seen[dir] {
continue
}
seen[dir] = true
results = append(results, dir)
}
return results
}
func sdkUploadSearchDirs() []string {
dirs := sdkUploadDirs()
results := make([]string, 0, len(dirs))
for _, dir := range dirs {
stat, err := os.Stat(dir)
if err == nil && stat.IsDir() {
results = append(results, dir)
}
}
if len(results) == 0 {
results = append(results, sdkUploadDir())
}
return results
}
func findFirstExistingDir(paths []string) string {
for _, path := range paths {
stat, err := os.Stat(path)
@@ -27,7 +67,7 @@ func findFirstExistingDir(paths []string) string {
func findFirstExistingFile(paths []string) string {
for _, path := range paths {
stat, err := os.Stat(path)
if err == nil && !stat.IsDir() {
if err == nil && !stat.IsDir() && stat.Size() > 0 {
return path
}
}
@@ -45,6 +85,9 @@ func findNewestExistingFile(paths []string) string {
if err != nil || stat.IsDir() {
continue
}
if stat.Size() <= 0 {
continue
}
if len(result.path) == 0 || stat.ModTime().After(result.modTime) || (stat.ModTime().Equal(result.modTime) && path > result.path) {
result.path = path
result.modTime = stat.ModTime()
@@ -85,22 +128,23 @@ func resolveSDKPlatform(platform string) (key string, relativeDir string, readme
}
}
func findSDKArchivePath(downloadFilename string) string {
searchDirs := []string{sdkUploadDir()}
func findSDKArchivePath(downloadFilename string, version string) string {
searchDirs := sdkUploadSearchDirs()
// 1) Exact filename first.
exactFiles := []string{}
for _, dir := range searchDirs {
exactFiles = append(exactFiles, filepath.Join(dir, downloadFilename))
}
path := findFirstExistingFile(exactFiles)
if len(path) > 0 {
return path
}
// 2) Version-suffixed archives, e.g. httpdns-sdk-android-v1.4.8.zip
normalizedVersion := strings.TrimSpace(version)
base := strings.TrimSuffix(downloadFilename, ".zip")
patternName := base + "-*.zip"
if len(normalizedVersion) > 0 {
versionFiles := []string{}
for _, dir := range searchDirs {
versionFiles = append(versionFiles, filepath.Join(dir, base+"-v"+normalizedVersion+".zip"))
}
if path := findFirstExistingFile(versionFiles); len(path) > 0 {
return path
}
return ""
}
patternName := base + "-v*.zip"
matches := []string{}
for _, dir := range searchDirs {
found, _ := filepath.Glob(filepath.Join(dir, patternName))
@@ -115,28 +159,52 @@ func findSDKArchivePath(downloadFilename string) string {
return findNewestExistingFile(matches)
}
exactFiles := []string{}
for _, dir := range searchDirs {
exactFiles = append(exactFiles, filepath.Join(dir, downloadFilename))
}
if path := findFirstExistingFile(exactFiles); len(path) > 0 {
return path
}
return ""
}
func findUploadedSDKDocPath(platform string) string {
func findUploadedSDKDocPath(platform string, version string) string {
platform = strings.ToLower(strings.TrimSpace(platform))
if len(platform) == 0 {
return ""
}
searchDir := sdkUploadDir()
exact := filepath.Join(searchDir, "httpdns-sdk-"+platform+".md")
if file := findFirstExistingFile([]string{exact}); len(file) > 0 {
return file
}
pattern := filepath.Join(searchDir, "httpdns-sdk-"+platform+"-*.md")
matches, _ := filepath.Glob(pattern)
if len(matches) == 0 {
searchDirs := sdkUploadSearchDirs()
normalizedVersion := strings.TrimSpace(version)
if len(normalizedVersion) > 0 {
exactVersion := []string{}
for _, dir := range searchDirs {
exactVersion = append(exactVersion, filepath.Join(dir, "httpdns-sdk-"+platform+"-v"+normalizedVersion+".md"))
}
if file := findFirstExistingFile(exactVersion); len(file) > 0 {
return file
}
return ""
}
sort.Strings(matches)
return findNewestExistingFile(matches)
matches := []string{}
for _, dir := range searchDirs {
pattern := filepath.Join(dir, "httpdns-sdk-"+platform+"-v*.md")
found, _ := filepath.Glob(pattern)
matches = append(matches, found...)
}
if len(matches) > 0 {
sort.Strings(matches)
return findNewestExistingFile(matches)
}
exact := []string{}
for _, dir := range searchDirs {
exact = append(exact, filepath.Join(dir, "httpdns-sdk-"+platform+".md"))
}
return findFirstExistingFile(exact)
}
func findLocalSDKDocPath(platform string) string {

View File

@@ -2,15 +2,16 @@ package apps
import (
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/iwind/TeaGo/actions"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/iwind/TeaGo/actions"
)
type SdkUploadAction struct {
@@ -44,7 +45,7 @@ func (this *SdkUploadAction) RunPost(params struct {
AppId int64
Platform string
Version string
SDKFile *actions.File
SdkFile *actions.File
DocFile *actions.File
Must *actions.Must
@@ -63,7 +64,7 @@ func (this *SdkUploadAction) RunPost(params struct {
return
}
if params.SDKFile == nil && params.DocFile == nil {
if params.SdkFile == nil && params.DocFile == nil {
this.Fail("请至少上传一个文件")
return
}
@@ -75,24 +76,25 @@ func (this *SdkUploadAction) RunPost(params struct {
return
}
if params.SDKFile != nil {
filename := strings.ToLower(strings.TrimSpace(params.SDKFile.Filename))
if params.SdkFile != nil {
filename := strings.ToLower(strings.TrimSpace(params.SdkFile.Filename))
if !strings.HasSuffix(filename, ".zip") {
this.Fail("SDK 包仅支持 .zip 文件")
return
}
sdkData, readErr := params.SDKFile.Read()
sdkData, readErr := params.SdkFile.Read()
if readErr != nil {
this.Fail("读取 SDK 包失败: " + readErr.Error())
return
}
if len(sdkData) == 0 {
this.Fail("SDK 包文件为空,请重新上传")
return
}
baseName := strings.TrimSuffix(downloadFilename, ".zip")
err = saveSDKUploadFile(uploadDir, downloadFilename, sdkData)
if err == nil {
err = saveSDKUploadFile(uploadDir, baseName+"-v"+version+".zip", sdkData)
}
err = saveSDKUploadFile(uploadDir, baseName+"-v"+version+".zip", sdkData)
if err != nil {
this.Fail("保存 SDK 包失败: " + err.Error())
return
@@ -111,12 +113,12 @@ func (this *SdkUploadAction) RunPost(params struct {
this.Fail("读取集成文档失败: " + readErr.Error())
return
}
filename := "httpdns-sdk-" + platform + ".md"
err = saveSDKUploadFile(uploadDir, filename, docData)
if err == nil {
err = saveSDKUploadFile(uploadDir, "httpdns-sdk-"+platform+"-v"+version+".md", docData)
if len(docData) == 0 {
this.Fail("集成文档文件为空,请重新上传")
return
}
err = saveSDKUploadFile(uploadDir, "httpdns-sdk-"+platform+"-v"+version+".md", docData)
if err != nil {
this.Fail("保存集成文档失败: " + err.Error())
return
@@ -151,12 +153,6 @@ func saveSDKUploadFile(baseDir string, filename string, data []byte) error {
}
func listUploadedSDKFiles() []map[string]interface{} {
dir := sdkUploadDir()
entries, err := os.ReadDir(dir)
if err != nil {
return []map[string]interface{}{}
}
type item struct {
Name string
Platform string
@@ -166,30 +162,45 @@ func listUploadedSDKFiles() []map[string]interface{} {
UpdatedAt int64
}
items := make([]item, 0)
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
platform, version, fileType, ok := parseSDKUploadFilename(name)
if !ok {
byName := map[string]item{}
for _, dir := range sdkUploadSearchDirs() {
entries, err := os.ReadDir(dir)
if err != nil {
continue
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
platform, version, fileType, ok := parseSDKUploadFilename(name)
if !ok {
continue
}
info, statErr := entry.Info()
if statErr != nil {
continue
}
info, statErr := entry.Info()
if statErr != nil {
continue
}
items = append(items, item{
Name: name,
Platform: platform,
FileType: fileType,
Version: version,
SizeBytes: info.Size(),
UpdatedAt: info.ModTime().Unix(),
})
current := item{
Name: name,
Platform: platform,
FileType: fileType,
Version: version,
SizeBytes: info.Size(),
UpdatedAt: info.ModTime().Unix(),
}
old, exists := byName[name]
if !exists || current.UpdatedAt >= old.UpdatedAt {
byName[name] = current
}
}
}
items := make([]item, 0, len(byName))
for _, it := range byName {
items = append(items, it)
}
sort.Slice(items, func(i, j int) bool {
@@ -200,14 +211,14 @@ func listUploadedSDKFiles() []map[string]interface{} {
})
result := make([]map[string]interface{}, 0, len(items))
for _, item := range items {
for _, it := range items {
result = append(result, map[string]interface{}{
"name": item.Name,
"platform": item.Platform,
"fileType": item.FileType,
"version": item.Version,
"sizeText": formatSDKFileSize(item.SizeBytes),
"updatedAt": time.Unix(item.UpdatedAt, 0).Format("2006-01-02 15:04:05"),
"name": it.Name,
"platform": it.Platform,
"fileType": it.FileType,
"version": it.Version,
"sizeText": formatSDKFileSize(it.SizeBytes),
"updatedAt": time.Unix(it.UpdatedAt, 0).Format("2006-01-02 15:04:05"),
})
}
return result
@@ -231,7 +242,7 @@ func parseSDKUploadFilename(filename string) (platform string, version string, f
}
main := strings.TrimSuffix(strings.TrimPrefix(filename, "httpdns-sdk-"), ext)
version = "latest"
version = ""
if idx := strings.Index(main, "-v"); idx > 0 && idx+2 < len(main) {
version = main[idx+2:]
main = main[:idx]
@@ -241,6 +252,9 @@ func parseSDKUploadFilename(filename string) (platform string, version string, f
switch main {
case "android", "ios", "flutter":
platform = main
if len(version) == 0 {
version = "-"
}
return platform, version, fileType, true
default:
return "", "", "", false

View File

@@ -1,10 +1,11 @@
package apps
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"os"
"path/filepath"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
)
type SdkUploadDeleteAction struct {
@@ -42,15 +43,16 @@ func (this *SdkUploadDeleteAction) RunPost(params struct {
return
}
fullPath := filepath.Join(sdkUploadDir(), filename)
_, err := os.Stat(fullPath)
if err != nil {
this.Success()
return
}
if err = os.Remove(fullPath); err != nil {
this.Fail("删除失败: " + err.Error())
return
for _, dir := range sdkUploadDirs() {
fullPath := filepath.Join(dir, filename)
_, err := os.Stat(fullPath)
if err != nil {
continue
}
if err = os.Remove(fullPath); err != nil {
this.Fail("删除失败: " + err.Error())
return
}
}
this.Success()

View File

@@ -10,8 +10,10 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type ClusterSettingsAction struct {
@@ -41,13 +43,14 @@ func (this *ClusterSettingsAction) RunGet(params struct {
}
settings := maps.Map{
"name": cluster.GetString("name"),
"gatewayDomain": cluster.GetString("gatewayDomain"),
"cacheTtl": cluster.GetInt("defaultTTL"),
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
"installDir": cluster.GetString("installDir"),
"isOn": cluster.GetBool("isOn"),
"isDefaultCluster": cluster.GetBool("isDefault"),
"name": cluster.GetString("name"),
"gatewayDomain": cluster.GetString("gatewayDomain"),
"cacheTtl": cluster.GetInt("defaultTTL"),
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
"installDir": cluster.GetString("installDir"),
"isOn": cluster.GetBool("isOn"),
"isDefaultCluster": cluster.GetBool("isDefault"),
"isDefaultBackupCluster": false,
}
if settings.GetInt("cacheTtl") <= 0 {
settings["cacheTtl"] = 30
@@ -59,6 +62,19 @@ func (this *ClusterSettingsAction) RunGet(params struct {
settings["installDir"] = "/opt/edge-httpdns"
}
defaultBackupResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
}
defaultBackupClusterId := int64(0)
if defaultBackupResp != nil && len(defaultBackupResp.GetValueJSON()) > 0 {
defaultBackupClusterId = types.Int64(string(defaultBackupResp.GetValueJSON()))
}
settings["isDefaultBackupCluster"] = defaultBackupClusterId == params.ClusterId
listenAddresses := []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolHTTPS,
@@ -104,14 +120,15 @@ func (this *ClusterSettingsAction) RunGet(params struct {
}
func (this *ClusterSettingsAction) RunPost(params struct {
ClusterId int64
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefaultCluster bool
ClusterId int64
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefaultCluster bool
IsDefaultBackupCluster bool
Addresses []byte
SslPolicyJSON []byte
@@ -137,7 +154,15 @@ func (this *ClusterSettingsAction) RunPost(params struct {
params.InstallDir = "/opt/edge-httpdns"
}
if params.IsDefaultCluster && !params.IsOn {
this.Fail("默认集群必须保持启用状态")
this.Fail("默认集群必须保持启用状态")
return
}
if params.IsDefaultBackupCluster && !params.IsOn {
this.Fail("默认备用集群必须保持启用状态")
return
}
if params.IsDefaultCluster && params.IsDefaultBackupCluster {
this.Fail("默认主集群和默认备用集群不能是同一个集群")
return
}
@@ -195,5 +220,33 @@ func (this *ClusterSettingsAction) RunPost(params struct {
return
}
backupClusterValue := int64(0)
if params.IsDefaultBackupCluster {
backupClusterValue = params.ClusterId
} else {
readResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
}
if readResp != nil && len(readResp.GetValueJSON()) > 0 {
oldBackupClusterId := types.Int64(string(readResp.GetValueJSON()))
if oldBackupClusterId != params.ClusterId {
backupClusterValue = oldBackupClusterId
}
}
}
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
ValueJSON: []byte(strconv.FormatInt(backupClusterValue, 10)),
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,11 +1,13 @@
package clusters
import (
"strconv"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
)
@@ -23,13 +25,14 @@ func (this *CreateAction) RunGet(params struct{}) {
}
func (this *CreateAction) RunPost(params struct {
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefault bool
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefaultPrimary bool
IsDefaultBackup bool
Must *actions.Must
}) {
@@ -49,6 +52,19 @@ func (this *CreateAction) RunPost(params struct {
params.Must.Field("name", params.Name).Require("请输入集群名称")
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("请输入服务域名")
if params.IsDefaultPrimary && !params.IsOn {
this.Fail("默认主集群必须保持启用状态")
return
}
if params.IsDefaultBackup && !params.IsOn {
this.Fail("默认备用集群必须保持启用状态")
return
}
if params.IsDefaultPrimary && params.IsDefaultBackup {
this.Fail("默认主集群和默认备用集群不能是同一个集群")
return
}
resp, err := this.RPC().HTTPDNSClusterRPC().CreateHTTPDNSCluster(this.AdminContext(), &pb.CreateHTTPDNSClusterRequest{
Name: params.Name,
ServiceDomain: params.GatewayDomain,
@@ -56,13 +72,24 @@ func (this *CreateAction) RunPost(params struct {
FallbackTimeoutMs: params.FallbackTimeout,
InstallDir: params.InstallDir,
IsOn: params.IsOn,
IsDefault: params.IsDefault,
IsDefault: params.IsDefaultPrimary,
})
if err != nil {
this.ErrorPage(err)
return
}
if params.IsDefaultBackup {
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
ValueJSON: []byte(strconv.FormatInt(resp.GetClusterId(), 10)),
})
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["clusterId"] = resp.GetClusterId()
this.Success()
}

View File

@@ -102,6 +102,8 @@ func (this *IndexAction) RunPost(params struct {
NsIsOn bool
HttpdnsIsOn bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -112,6 +114,15 @@ func (this *IndexAction) RunPost(params struct {
Gt(0, "请选择一个集群")
var config = userconfigs.DefaultUserRegisterConfig()
{
// 先读取现有配置,避免保存时把未出现在当前表单里的字段重置为默认值
resp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: systemconfigs.SettingCodeUserRegisterConfig,
})
if err == nil && len(resp.ValueJSON) > 0 {
_ = json.Unmarshal(resp.ValueJSON, config)
}
}
config.IsOn = params.IsOn
config.ComplexPassword = params.ComplexPassword
config.RequireVerification = params.RequireVerification
@@ -142,6 +153,7 @@ func (this *IndexAction) RunPost(params struct {
config.ADIsOn = params.AdIsOn
config.NSIsOn = params.NsIsOn
config.HTTPDNSIsOn = params.HttpdnsIsOn
configJSON, err := json.Marshal(config)
if err != nil {
@@ -157,10 +169,15 @@ func (this *IndexAction) RunPost(params struct {
return
}
if params.FeatureOp != "keep" {
featureOp := params.FeatureOp
if featureOp != "overwrite" && featureOp != "append" && featureOp != "keep" {
featureOp = "keep"
}
if featureOp != "keep" {
_, err = this.RPC().UserRPC().UpdateAllUsersFeatures(this.AdminContext(), &pb.UpdateAllUsersFeaturesRequest{
FeatureCodes: params.Features,
Overwrite: params.FeatureOp == "overwrite",
Overwrite: featureOp == "overwrite",
})
if err != nil {
this.ErrorPage(err)