前端页面
This commit is contained in:
123
EdgeAdmin/internal/web/actions/default/httpdns/addPortPopup.go
Normal file
123
EdgeAdmin/internal/web/actions/default/httpdns/addPortPopup.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package httpdns
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddPortPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) RunGet(params struct {
|
||||
Protocol string
|
||||
From string
|
||||
SupportRange bool
|
||||
}) {
|
||||
this.Data["from"] = params.From
|
||||
|
||||
var protocols = serverconfigs.FindAllServerProtocols()
|
||||
if len(params.Protocol) > 0 {
|
||||
result := []maps.Map{}
|
||||
for _, p := range protocols {
|
||||
if p.GetString("code") == params.Protocol {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
protocols = result
|
||||
}
|
||||
this.Data["protocols"] = protocols
|
||||
|
||||
this.Data["supportRange"] = params.SupportRange
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) RunPost(params struct {
|
||||
SupportRange bool
|
||||
|
||||
Protocol string
|
||||
Address string
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
// 校验地址
|
||||
var addr = maps.Map{
|
||||
"protocol": params.Protocol,
|
||||
"host": "",
|
||||
"portRange": "",
|
||||
"minPort": 0,
|
||||
"maxPort": 0,
|
||||
}
|
||||
|
||||
var portRegexp = regexp.MustCompile(`^\d+$`)
|
||||
if portRegexp.MatchString(params.Address) { // 单个端口
|
||||
addr["portRange"] = this.checkPort(params.Address)
|
||||
} else if params.SupportRange && regexp.MustCompile(`^\d+\s*-\s*\d+$`).MatchString(params.Address) { // Port1-Port2
|
||||
addr["portRange"], addr["minPort"], addr["maxPort"] = this.checkPortRange(params.Address)
|
||||
} else if strings.Contains(params.Address, ":") { // IP:Port
|
||||
index := strings.LastIndex(params.Address, ":")
|
||||
addr["host"] = strings.TrimSpace(params.Address[:index])
|
||||
port := strings.TrimSpace(params.Address[index+1:])
|
||||
if portRegexp.MatchString(port) {
|
||||
addr["portRange"] = this.checkPort(port)
|
||||
} else if params.SupportRange && regexp.MustCompile(`^\d+\s*-\s*\d+$`).MatchString(port) { // Port1-Port2
|
||||
addr["portRange"], addr["minPort"], addr["maxPort"] = this.checkPortRange(port)
|
||||
} else {
|
||||
this.FailField("address", "请输入正确的端口或者网络地址")
|
||||
}
|
||||
} else {
|
||||
this.FailField("address", "请输入正确的端口或者网络地址")
|
||||
}
|
||||
|
||||
this.Data["address"] = addr
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) checkPort(port string) (portRange string) {
|
||||
var intPort = types.Int(port)
|
||||
if intPort < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if intPort > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func (this *AddPortPopupAction) checkPortRange(port string) (portRange string, minPort int, maxPort int) {
|
||||
var pieces = strings.Split(port, "-")
|
||||
var piece1 = strings.TrimSpace(pieces[0])
|
||||
var piece2 = strings.TrimSpace(pieces[1])
|
||||
var port1 = types.Int(piece1)
|
||||
var port2 = types.Int(piece2)
|
||||
|
||||
if port1 < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if port1 > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
|
||||
if port2 < 1 {
|
||||
this.FailField("address", "端口号不能小于1")
|
||||
}
|
||||
if port2 > 65535 {
|
||||
this.FailField("address", "端口号不能大于65535")
|
||||
}
|
||||
|
||||
if port1 > port2 {
|
||||
port1, port2 = port2, port1
|
||||
}
|
||||
|
||||
return types.String(port1) + "-" + types.String(port2), port1, port2
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
)
|
||||
|
||||
@@ -11,15 +14,41 @@ type AppSettingsAction struct {
|
||||
}
|
||||
|
||||
func (this *AppSettingsAction) Init() {
|
||||
this.Nav("httpdns", "app", "")
|
||||
this.Nav("httpdns", "app", "settings")
|
||||
}
|
||||
|
||||
func (this *AppSettingsAction) RunGet(params struct {
|
||||
AppId int64
|
||||
AppId int64
|
||||
Section string
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
app := pickApp(params.AppId)
|
||||
|
||||
// 顶部 tabbar
|
||||
httpdnsutils.AddAppTabbar(this.Parent(), app.GetString("name"), params.AppId, "settings")
|
||||
|
||||
// 当前选中的 section
|
||||
section := params.Section
|
||||
if len(section) == 0 {
|
||||
section = "basic"
|
||||
}
|
||||
this.Data["activeSection"] = section
|
||||
appIdStr := strconv.FormatInt(params.AppId, 10)
|
||||
this.Data["leftMenuItems"] = []map[string]interface{}{
|
||||
{
|
||||
"name": "基础配置",
|
||||
"url": "/httpdns/apps/app/settings?appId=" + appIdStr + "§ion=basic",
|
||||
"isActive": section == "basic",
|
||||
},
|
||||
{
|
||||
"name": "认证与密钥",
|
||||
"url": "/httpdns/apps/app/settings?appId=" + appIdStr + "§ion=auth",
|
||||
"isActive": section == "auth",
|
||||
},
|
||||
}
|
||||
|
||||
settings := loadAppSettings(app)
|
||||
this.Data["clusters"] = policies.LoadAvailableDeployClusters()
|
||||
this.Data["app"] = app
|
||||
this.Data["settings"] = settings
|
||||
this.Show()
|
||||
@@ -28,16 +57,24 @@ func (this *AppSettingsAction) RunGet(params struct {
|
||||
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, "please select app")
|
||||
params.Must.Field("primaryClusterId", params.PrimaryClusterId).Gt(0, "please select primary cluster")
|
||||
if params.BackupClusterId > 0 && params.BackupClusterId == params.PrimaryClusterId {
|
||||
this.FailField("backupClusterId", "backup cluster must be different from primary cluster")
|
||||
}
|
||||
|
||||
app := pickApp(params.AppId)
|
||||
settings := loadAppSettings(app)
|
||||
settings["appStatus"] = params.AppStatus
|
||||
settings["primaryClusterId"] = params.PrimaryClusterId
|
||||
settings["backupClusterId"] = params.BackupClusterId
|
||||
|
||||
// SNI strategy is fixed to level2 empty.
|
||||
settings["sniPolicy"] = "level2"
|
||||
|
||||
@@ -20,6 +20,8 @@ func defaultAppSettings(app maps.Map) maps.Map {
|
||||
aesSecretPlain := randomPlainSecret("as")
|
||||
return maps.Map{
|
||||
"appId": app.GetString("appId"),
|
||||
"primaryClusterId": app.GetInt64("clusterId"),
|
||||
"backupClusterId": int64(0),
|
||||
"signSecretPlain": signSecretPlain,
|
||||
"signSecretMasked": maskSecret(signSecretPlain),
|
||||
"signSecretUpdatedAt": "2026-02-20 12:30:00",
|
||||
@@ -45,6 +47,8 @@ func defaultAppSettings(app maps.Map) maps.Map {
|
||||
func cloneSettings(settings maps.Map) maps.Map {
|
||||
return maps.Map{
|
||||
"appId": settings.GetString("appId"),
|
||||
"primaryClusterId": settings.GetInt64("primaryClusterId"),
|
||||
"backupClusterId": settings.GetInt64("backupClusterId"),
|
||||
"signSecretPlain": settings.GetString("signSecretPlain"),
|
||||
"signSecretMasked": settings.GetString("signSecretMasked"),
|
||||
"signSecretUpdatedAt": settings.GetString("signSecretUpdatedAt"),
|
||||
@@ -90,6 +94,12 @@ func saveAppSettings(appId int64, settings maps.Map) {
|
||||
appSettingsStore.Unlock()
|
||||
}
|
||||
|
||||
func deleteAppSettings(appId int64) {
|
||||
appSettingsStore.Lock()
|
||||
delete(appSettingsStore.data, appId)
|
||||
appSettingsStore.Unlock()
|
||||
}
|
||||
|
||||
func resetSignSecret(app maps.Map) maps.Map {
|
||||
settings := loadAppSettings(app)
|
||||
signSecretPlain := randomPlainSecret("ss")
|
||||
@@ -144,6 +154,19 @@ func maskSecret(secret string) string {
|
||||
func ensureSettingsFields(settings maps.Map) bool {
|
||||
changed := false
|
||||
|
||||
if settings.GetInt64("primaryClusterId") <= 0 {
|
||||
settings["primaryClusterId"] = int64(1)
|
||||
changed = true
|
||||
}
|
||||
if settings.GetInt64("backupClusterId") < 0 {
|
||||
settings["backupClusterId"] = int64(0)
|
||||
changed = true
|
||||
}
|
||||
if settings.GetInt64("backupClusterId") > 0 && settings.GetInt64("backupClusterId") == settings.GetInt64("primaryClusterId") {
|
||||
settings["backupClusterId"] = int64(0)
|
||||
changed = true
|
||||
}
|
||||
|
||||
signSecretPlain := settings.GetString("signSecretPlain")
|
||||
if len(signSecretPlain) == 0 {
|
||||
signSecretPlain = randomPlainSecret("ss")
|
||||
|
||||
@@ -19,31 +19,45 @@ func (this *CreatePopupAction) RunGet(params struct{}) {
|
||||
clusters := policies.LoadAvailableDeployClusters()
|
||||
this.Data["clusters"] = clusters
|
||||
|
||||
defaultClusterID := policies.LoadDefaultClusterID()
|
||||
if defaultClusterID <= 0 && len(clusters) > 0 {
|
||||
defaultClusterID = clusters[0].GetInt64("id")
|
||||
defaultPrimaryClusterId := policies.LoadDefaultClusterID()
|
||||
if defaultPrimaryClusterId <= 0 && len(clusters) > 0 {
|
||||
defaultPrimaryClusterId = clusters[0].GetInt64("id")
|
||||
}
|
||||
this.Data["defaultClusterId"] = defaultClusterID
|
||||
this.Data["defaultPrimaryClusterId"] = defaultPrimaryClusterId
|
||||
|
||||
defaultBackupClusterId := int64(0)
|
||||
for _, cluster := range clusters {
|
||||
clusterId := cluster.GetInt64("id")
|
||||
if clusterId > 0 && clusterId != defaultPrimaryClusterId {
|
||||
defaultBackupClusterId = clusterId
|
||||
break
|
||||
}
|
||||
}
|
||||
this.Data["defaultBackupClusterId"] = defaultBackupClusterId
|
||||
|
||||
// Mock users for dropdown
|
||||
this.Data["users"] = []maps.Map{
|
||||
{"id": int64(1), "name": "张三", "username": "zhangsan"},
|
||||
{"id": int64(2), "name": "李四", "username": "lisi"},
|
||||
{"id": int64(3), "name": "王五", "username": "wangwu"},
|
||||
{"id": int64(1), "name": "User A", "username": "zhangsan"},
|
||||
{"id": int64(2), "name": "User B", "username": "lisi"},
|
||||
{"id": int64(3), "name": "User C", "username": "wangwu"},
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *CreatePopupAction) RunPost(params struct {
|
||||
Name string
|
||||
ClusterId int64
|
||||
UserId int64
|
||||
Name string
|
||||
PrimaryClusterId int64
|
||||
BackupClusterId int64
|
||||
UserId int64
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.Field("name", params.Name).Require("请输入应用名称")
|
||||
params.Must.Field("clusterId", params.ClusterId).Gt(0, "请选择所属集群")
|
||||
params.Must.Field("name", params.Name).Require("please input app name")
|
||||
params.Must.Field("primaryClusterId", params.PrimaryClusterId).Gt(0, "please select primary cluster")
|
||||
if params.BackupClusterId > 0 && params.BackupClusterId == params.PrimaryClusterId {
|
||||
this.FailField("backupClusterId", "backup cluster must be different from primary cluster")
|
||||
}
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ func (this *CustomRecordsAction) RunGet(params struct {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
|
||||
app := pickApp(params.AppId)
|
||||
// 自定义解析属于域名管理子页,顶部沿用应用 tabbar(高亮域名列表)
|
||||
httpdnsutils.AddAppTabbar(this.Parent(), app.GetString("name"), params.AppId, "domains")
|
||||
|
||||
domains := mockDomains(app.GetInt64("id"))
|
||||
domain := pickDomainFromDomains(domains, params.DomainId)
|
||||
domainName := domain.GetString("name")
|
||||
@@ -35,7 +38,6 @@ func (this *CustomRecordsAction) RunGet(params struct {
|
||||
|
||||
for _, record := range records {
|
||||
record["lineText"] = buildLineText(record)
|
||||
record["paramsText"] = buildParamsText(record)
|
||||
record["recordValueText"] = buildRecordValueText(record)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ func (this *CustomRecordsCreatePopupAction) RunGet(params struct {
|
||||
"weightEnabled": false,
|
||||
"ttl": 30,
|
||||
"isOn": true,
|
||||
"sdnsParamsJson": "[]",
|
||||
"recordItemsJson": `[{"type":"A","value":"","weight":100}]`,
|
||||
}
|
||||
|
||||
@@ -65,9 +64,6 @@ func (this *CustomRecordsCreatePopupAction) RunGet(params struct {
|
||||
record["ttl"] = existing.GetInt("ttl")
|
||||
record["isOn"] = existing.GetBool("isOn")
|
||||
|
||||
sdnsParams, _ := existing["sdnsParams"].([]maps.Map)
|
||||
record["sdnsParamsJson"] = marshalJSON(sdnsParams, "[]")
|
||||
|
||||
recordItems := make([]maps.Map, 0)
|
||||
recordType := strings.ToUpper(strings.TrimSpace(existing.GetString("recordType")))
|
||||
values, _ := existing["recordValues"].([]maps.Map)
|
||||
@@ -140,7 +136,6 @@ func (this *CustomRecordsCreatePopupAction) RunPost(params struct {
|
||||
LineCountry string
|
||||
|
||||
RuleName string
|
||||
SDNSParamsJSON string
|
||||
RecordItemsJSON string
|
||||
WeightEnabled bool
|
||||
TTL int
|
||||
@@ -154,7 +149,6 @@ func (this *CustomRecordsCreatePopupAction) RunPost(params struct {
|
||||
params.Domain = strings.TrimSpace(params.Domain)
|
||||
params.LineScope = strings.ToLower(strings.TrimSpace(params.LineScope))
|
||||
params.RuleName = strings.TrimSpace(params.RuleName)
|
||||
params.SDNSParamsJSON = strings.TrimSpace(params.SDNSParamsJSON)
|
||||
params.RecordItemsJSON = strings.TrimSpace(params.RecordItemsJSON)
|
||||
|
||||
domain := maps.Map{}
|
||||
@@ -181,16 +175,6 @@ func (this *CustomRecordsCreatePopupAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
sdnsParams, err := parseSDNSParamsJSON(params.SDNSParamsJSON)
|
||||
if err != nil {
|
||||
this.Fail(err.Error())
|
||||
return
|
||||
}
|
||||
if len(sdnsParams) > 10 {
|
||||
this.Fail("sdns params should be <= 10")
|
||||
return
|
||||
}
|
||||
|
||||
recordValues, err := parseRecordItemsJSON(params.RecordItemsJSON, params.WeightEnabled)
|
||||
if err != nil {
|
||||
this.Fail(err.Error())
|
||||
@@ -250,7 +234,7 @@ func (this *CustomRecordsCreatePopupAction) RunPost(params struct {
|
||||
"lineContinent": lineContinent,
|
||||
"lineCountry": lineCountry,
|
||||
"ruleName": params.RuleName,
|
||||
"sdnsParams": sdnsParams,
|
||||
"sdnsParams": []maps.Map{},
|
||||
"recordType": recordType,
|
||||
"recordValues": recordValues,
|
||||
"weightEnabled": params.WeightEnabled,
|
||||
@@ -261,38 +245,6 @@ func (this *CustomRecordsCreatePopupAction) RunPost(params struct {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func parseSDNSParamsJSON(raw string) ([]maps.Map, error) {
|
||||
if len(raw) == 0 {
|
||||
return []maps.Map{}, nil
|
||||
}
|
||||
|
||||
list := []maps.Map{}
|
||||
if err := json.Unmarshal([]byte(raw), &list); err != nil {
|
||||
return nil, fmt.Errorf("sdns params json is invalid")
|
||||
}
|
||||
|
||||
result := make([]maps.Map, 0, len(list))
|
||||
for _, item := range list {
|
||||
name := strings.TrimSpace(item.GetString("name"))
|
||||
value := strings.TrimSpace(item.GetString("value"))
|
||||
if len(name) == 0 && len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(name) < 2 || len(name) > 64 {
|
||||
return nil, fmt.Errorf("sdns param name length should be in 2-64")
|
||||
}
|
||||
if len(value) < 1 || len(value) > 64 {
|
||||
return nil, fmt.Errorf("sdns param value length should be in 1-64")
|
||||
}
|
||||
result = append(result, maps.Map{
|
||||
"name": name,
|
||||
"value": value,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseRecordItemsJSON(raw string, weightEnabled bool) ([]maps.Map, error) {
|
||||
if len(raw) == 0 {
|
||||
return []maps.Map{}, nil
|
||||
|
||||
@@ -18,19 +18,14 @@ var customRecordStore = struct {
|
||||
data: map[int64][]maps.Map{
|
||||
1: {
|
||||
{
|
||||
"id": int64(1001),
|
||||
"domain": "api.business.com",
|
||||
"lineScope": "china",
|
||||
"lineCarrier": "电信",
|
||||
"lineRegion": "华东",
|
||||
"lineProvince": "上海",
|
||||
"ruleName": "上海电信灰度-v2",
|
||||
"sdnsParams": []maps.Map{
|
||||
{
|
||||
"name": "app_ver",
|
||||
"value": "2.3.1",
|
||||
},
|
||||
},
|
||||
"id": int64(1001),
|
||||
"domain": "api.business.com",
|
||||
"lineScope": "china",
|
||||
"lineCarrier": "电信",
|
||||
"lineRegion": "华东",
|
||||
"lineProvince": "上海",
|
||||
"ruleName": "上海电信灰度-v2",
|
||||
"sdnsParams": []maps.Map{},
|
||||
"recordType": "A",
|
||||
"recordValues": []maps.Map{{"type": "A", "value": "1.1.1.10", "weight": 100}},
|
||||
"weightEnabled": false,
|
||||
@@ -134,6 +129,12 @@ func deleteCustomRecord(appID int64, recordID int64) {
|
||||
customRecordStore.data[appID] = filtered
|
||||
}
|
||||
|
||||
func deleteCustomRecordsByApp(appID int64) {
|
||||
customRecordStore.Lock()
|
||||
defer customRecordStore.Unlock()
|
||||
delete(customRecordStore.data, appID)
|
||||
}
|
||||
|
||||
func toggleCustomRecord(appID int64, recordID int64, isOn bool) {
|
||||
customRecordStore.Lock()
|
||||
defer customRecordStore.Unlock()
|
||||
@@ -207,27 +208,6 @@ func buildLineText(record maps.Map) string {
|
||||
return strings.Join(finalParts, " / ")
|
||||
}
|
||||
|
||||
func buildParamsText(record maps.Map) string {
|
||||
params, ok := record["sdnsParams"].([]maps.Map)
|
||||
if !ok || len(params) == 0 {
|
||||
return "-"
|
||||
}
|
||||
|
||||
parts := make([]string, 0, len(params))
|
||||
for _, param := range params {
|
||||
name := strings.TrimSpace(param.GetString("name"))
|
||||
value := strings.TrimSpace(param.GetString("value"))
|
||||
if len(name) == 0 || len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, name+"="+value)
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return "-"
|
||||
}
|
||||
return strings.Join(parts, "; ")
|
||||
}
|
||||
|
||||
func buildRecordValueText(record maps.Map) string {
|
||||
values, ok := record["recordValues"].([]maps.Map)
|
||||
if !ok || len(values) == 0 {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
)
|
||||
|
||||
type DeleteAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *DeleteAction) Init() {
|
||||
this.Nav("httpdns", "app", "delete")
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunGet(params struct {
|
||||
AppId int64
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
app := pickApp(params.AppId)
|
||||
httpdnsutils.AddAppTabbar(this.Parent(), app.GetString("name"), app.GetInt64("id"), "delete")
|
||||
this.Data["app"] = app
|
||||
this.Data["domainCount"] = len(mockDomains(app.GetInt64("id")))
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
AppId int64
|
||||
}) {
|
||||
if params.AppId > 0 {
|
||||
if deleteApp(params.AppId) {
|
||||
deleteAppSettings(params.AppId)
|
||||
deleteCustomRecordsByApp(params.AppId)
|
||||
}
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -10,7 +10,7 @@ type DomainsAction struct {
|
||||
}
|
||||
|
||||
func (this *DomainsAction) Init() {
|
||||
this.Nav("httpdns", "app", "")
|
||||
this.Nav("httpdns", "app", "domains")
|
||||
}
|
||||
|
||||
func (this *DomainsAction) RunGet(params struct {
|
||||
@@ -19,6 +19,9 @@ func (this *DomainsAction) RunGet(params struct {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
app := pickApp(params.AppId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddAppTabbar(this.Parent(), app.GetString("name"), params.AppId, "domains")
|
||||
|
||||
domains := mockDomains(app.GetInt64("id"))
|
||||
for _, domain := range domains {
|
||||
domainName := domain.GetString("name")
|
||||
|
||||
@@ -15,6 +15,7 @@ func init() {
|
||||
Prefix("/httpdns/apps").
|
||||
Get("", new(IndexAction)).
|
||||
Get("/app", new(AppAction)).
|
||||
Get("/sdk", new(SDKAction)).
|
||||
GetPost("/app/settings", new(AppSettingsAction)).
|
||||
Post("/app/settings/toggleSignEnabled", new(AppSettingsToggleSignEnabledAction)).
|
||||
Post("/app/settings/resetSignSecret", new(AppSettingsResetSignSecretAction)).
|
||||
@@ -22,6 +23,7 @@ func init() {
|
||||
Get("/domains", new(DomainsAction)).
|
||||
Get("/customRecords", new(CustomRecordsAction)).
|
||||
GetPost("/createPopup", new(CreatePopupAction)).
|
||||
GetPost("/delete", new(DeleteAction)).
|
||||
GetPost("/domains/createPopup", new(DomainsCreatePopupAction)).
|
||||
Post("/domains/delete", new(DomainsDeleteAction)).
|
||||
GetPost("/customRecords/createPopup", new(CustomRecordsCreatePopupAction)).
|
||||
|
||||
@@ -2,15 +2,23 @@ package apps
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
func mockApps() []maps.Map {
|
||||
var appStore = struct {
|
||||
sync.RWMutex
|
||||
data []maps.Map
|
||||
}{
|
||||
data: defaultMockApps(),
|
||||
}
|
||||
|
||||
func defaultMockApps() []maps.Map {
|
||||
return []maps.Map{
|
||||
{
|
||||
"id": int64(1),
|
||||
"name": "主站移动业务",
|
||||
"name": "\u4e3b\u7ad9\u79fb\u52a8\u4e1a\u52a1",
|
||||
"appId": "ab12xc34s2",
|
||||
"clusterId": int64(1),
|
||||
"domainCount": 3,
|
||||
@@ -20,12 +28,12 @@ func mockApps() []maps.Map {
|
||||
"pinningMode": "report",
|
||||
"sanMode": "strict",
|
||||
"riskLevel": "medium",
|
||||
"riskSummary": "Pinning 处于观察模式",
|
||||
"riskSummary": "Pinning \u5904\u4e8e\u89c2\u5bdf\u6a21\u5f0f",
|
||||
"secretVersion": "v2026.02.20",
|
||||
},
|
||||
{
|
||||
"id": int64(2),
|
||||
"name": "视频网关业务",
|
||||
"name": "\u89c6\u9891\u7f51\u5173\u4e1a\u52a1",
|
||||
"appId": "vd8992ksm1",
|
||||
"clusterId": int64(2),
|
||||
"domainCount": 1,
|
||||
@@ -35,12 +43,12 @@ func mockApps() []maps.Map {
|
||||
"pinningMode": "enforce",
|
||||
"sanMode": "strict",
|
||||
"riskLevel": "low",
|
||||
"riskSummary": "已启用强校验",
|
||||
"riskSummary": "\u5df2\u542f\u7528\u5f3a\u6821\u9a8c",
|
||||
"secretVersion": "v2026.02.18",
|
||||
},
|
||||
{
|
||||
"id": int64(3),
|
||||
"name": "海外灰度测试",
|
||||
"name": "\u6d77\u5916\u7070\u5ea6\u6d4b\u8bd5",
|
||||
"appId": "ov7711hkq9",
|
||||
"clusterId": int64(1),
|
||||
"domainCount": 2,
|
||||
@@ -50,12 +58,57 @@ func mockApps() []maps.Map {
|
||||
"pinningMode": "off",
|
||||
"sanMode": "report",
|
||||
"riskLevel": "high",
|
||||
"riskSummary": "应用关闭且证书策略偏弱",
|
||||
"riskSummary": "\u5e94\u7528\u5173\u95ed\u4e14\u8bc1\u4e66\u7b56\u7565\u504f\u5f31",
|
||||
"secretVersion": "v2026.01.30",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func cloneMap(src maps.Map) maps.Map {
|
||||
dst := maps.Map{}
|
||||
for k, v := range src {
|
||||
dst[k] = v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func cloneApps(apps []maps.Map) []maps.Map {
|
||||
result := make([]maps.Map, 0, len(apps))
|
||||
for _, app := range apps {
|
||||
result = append(result, cloneMap(app))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mockApps() []maps.Map {
|
||||
appStore.RLock()
|
||||
defer appStore.RUnlock()
|
||||
return cloneApps(appStore.data)
|
||||
}
|
||||
|
||||
func deleteApp(appID int64) bool {
|
||||
if appID <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
appStore.Lock()
|
||||
defer appStore.Unlock()
|
||||
|
||||
found := false
|
||||
filtered := make([]maps.Map, 0, len(appStore.data))
|
||||
for _, app := range appStore.data {
|
||||
if app.GetInt64("id") == appID {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, app)
|
||||
}
|
||||
if found {
|
||||
appStore.data = filtered
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
func filterApps(keyword string, riskLevel string, ecsMode string, pinningMode string) []maps.Map {
|
||||
all := mockApps()
|
||||
if len(keyword) == 0 && len(riskLevel) == 0 && len(ecsMode) == 0 && len(pinningMode) == 0 {
|
||||
@@ -89,6 +142,15 @@ func filterApps(keyword string, riskLevel string, ecsMode string, pinningMode st
|
||||
|
||||
func pickApp(appID int64) maps.Map {
|
||||
apps := mockApps()
|
||||
if len(apps) == 0 {
|
||||
return maps.Map{
|
||||
"id": int64(0),
|
||||
"name": "",
|
||||
"appId": "",
|
||||
"clusterId": int64(0),
|
||||
}
|
||||
}
|
||||
|
||||
if appID <= 0 {
|
||||
return apps[0]
|
||||
}
|
||||
|
||||
27
EdgeAdmin/internal/web/actions/default/httpdns/apps/sdk.go
Normal file
27
EdgeAdmin/internal/web/actions/default/httpdns/apps/sdk.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
)
|
||||
|
||||
type SDKAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SDKAction) Init() {
|
||||
this.Nav("httpdns", "app", "sdk")
|
||||
}
|
||||
|
||||
func (this *SDKAction) RunGet(params struct {
|
||||
AppId int64
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
app := pickApp(params.AppId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddAppTabbar(this.Parent(), app.GetString("name"), params.AppId, "sdk")
|
||||
|
||||
this.Data["app"] = app
|
||||
this.Show()
|
||||
}
|
||||
@@ -21,6 +21,10 @@ func (this *ClusterAction) RunGet(params struct {
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "node")
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["cluster"] = cluster
|
||||
this.Data["installState"] = params.InstalledState
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type ClusterSettingsAction struct {
|
||||
@@ -15,35 +24,184 @@ func (this *ClusterSettingsAction) Init() {
|
||||
|
||||
func (this *ClusterSettingsAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
Section string
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
installDir := cluster.GetString("installDir")
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
settings := loadClusterSettings(cluster)
|
||||
cluster["name"] = settings.GetString("name")
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "setting")
|
||||
|
||||
// 当前选中的 section
|
||||
section := params.Section
|
||||
if len(section) == 0 {
|
||||
section = "basic"
|
||||
}
|
||||
this.Data["activeSection"] = section
|
||||
|
||||
// 左侧菜单
|
||||
cid := strconv.FormatInt(params.ClusterId, 10)
|
||||
this.Data["leftMenuItems"] = []map[string]interface{}{
|
||||
{"name": "基础设置", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=basic", "isActive": section == "basic"},
|
||||
{"name": "TLS", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=tls", "isActive": section == "tls"},
|
||||
}
|
||||
|
||||
settings["isDefaultCluster"] = (policies.LoadDefaultClusterID() == cluster.GetInt64("id"))
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
this.Data["settings"] = map[string]interface{}{
|
||||
"region": cluster.GetString("region"),
|
||||
"gatewayDomain": cluster.GetString("gatewayDomain"),
|
||||
"cacheTtl": cluster.GetInt("cacheTtl"),
|
||||
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
|
||||
"installDir": installDir,
|
||||
"isOn": cluster.GetBool("isOn"),
|
||||
// 构造前端需要的 tlsConfig 格式
|
||||
var listenAddresses []*serverconfigs.NetworkAddressConfig
|
||||
listenAddrsRaw := settings.GetString("listenAddrsJSON")
|
||||
if len(listenAddrsRaw) > 0 {
|
||||
_ = json.Unmarshal([]byte(listenAddrsRaw), &listenAddresses)
|
||||
} else {
|
||||
// 默认 443 端口
|
||||
listenAddresses = []*serverconfigs.NetworkAddressConfig{
|
||||
{
|
||||
Protocol: serverconfigs.ProtocolHTTPS,
|
||||
Host: "",
|
||||
PortRange: "443",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 构造前端需要的 SSLPolicy
|
||||
var sslPolicy *sslconfigs.SSLPolicy
|
||||
originCertPem := settings.GetString("originCertPem")
|
||||
originKeyPem := settings.GetString("originKeyPem")
|
||||
if len(originCertPem) > 0 && len(originKeyPem) > 0 {
|
||||
sslPolicy = &sslconfigs.SSLPolicy{
|
||||
IsOn: true,
|
||||
MinVersion: settings.GetString("tlsMinVersion"),
|
||||
CipherSuitesIsOn: settings.GetBool("tlsCipherSuitesOn"),
|
||||
OCSPIsOn: settings.GetBool("tlsOcspOn"),
|
||||
ClientAuthType: int(settings.GetInt32("tlsClientAuthType")),
|
||||
Certs: []*sslconfigs.SSLCertConfig{
|
||||
{
|
||||
IsOn: true,
|
||||
CertData: []byte(originCertPem),
|
||||
KeyData: []byte(originKeyPem),
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
sslPolicy = &sslconfigs.SSLPolicy{
|
||||
IsOn: true,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["tlsConfig"] = maps.Map{
|
||||
"isOn": true,
|
||||
"listen": listenAddresses,
|
||||
"sslPolicy": sslPolicy,
|
||||
}
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
this.Data["settings"] = settings
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *ClusterSettingsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
Name string
|
||||
Region string
|
||||
GatewayDomain string
|
||||
CacheTtl int32
|
||||
FallbackTimeout int32
|
||||
InstallDir string
|
||||
IsOn bool
|
||||
ClusterId int64
|
||||
Name string
|
||||
GatewayDomain string
|
||||
CacheTtl int32
|
||||
FallbackTimeout int32
|
||||
InstallDir string
|
||||
IsOn bool
|
||||
IsDefaultCluster bool
|
||||
|
||||
Addresses []byte
|
||||
SslPolicyJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
// Mock successful save
|
||||
params.Must.Field("clusterId", params.ClusterId).Gt(0, "please select cluster")
|
||||
params.Must.Field("name", params.Name).Require("please input cluster name")
|
||||
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("please input service domain")
|
||||
params.Must.Field("cacheTtl", params.CacheTtl).Gt(0, "cache ttl should be greater than 0")
|
||||
params.Must.Field("fallbackTimeout", params.FallbackTimeout).Gt(0, "fallback timeout should be greater than 0")
|
||||
params.Must.Field("installDir", params.InstallDir).Require("please input install dir")
|
||||
|
||||
|
||||
if params.IsDefaultCluster && !params.IsOn {
|
||||
this.Fail("默认集群必须保持启用状态")
|
||||
return
|
||||
}
|
||||
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
settings := loadClusterSettings(cluster)
|
||||
settings["name"] = strings.TrimSpace(params.Name)
|
||||
settings["gatewayDomain"] = strings.TrimSpace(params.GatewayDomain)
|
||||
settings["cacheTtl"] = int(params.CacheTtl)
|
||||
settings["fallbackTimeout"] = int(params.FallbackTimeout)
|
||||
settings["installDir"] = strings.TrimSpace(params.InstallDir)
|
||||
settings["isOn"] = params.IsOn
|
||||
// 处理地址
|
||||
var addresses = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(params.Addresses) > 0 {
|
||||
err := json.Unmarshal(params.Addresses, &addresses)
|
||||
if err != nil {
|
||||
this.Fail("端口地址解析失败:" + err.Error())
|
||||
}
|
||||
|
||||
addressesJSON, _ := json.Marshal(addresses)
|
||||
settings["listenAddrsJSON"] = string(addressesJSON)
|
||||
}
|
||||
|
||||
// 处理 SSL 配置
|
||||
var originCertPem = ""
|
||||
var originKeyPem = ""
|
||||
var tlsMinVersion = "TLS 1.1"
|
||||
var tlsCipherSuitesOn = false
|
||||
var tlsOcspOn = false
|
||||
var tlsClientAuthType = sslconfigs.SSLClientAuthType(0)
|
||||
|
||||
if len(params.SslPolicyJSON) > 0 {
|
||||
sslPolicy := &sslconfigs.SSLPolicy{}
|
||||
err := json.Unmarshal(params.SslPolicyJSON, sslPolicy)
|
||||
if err == nil {
|
||||
tlsMinVersion = sslPolicy.MinVersion
|
||||
tlsCipherSuitesOn = sslPolicy.CipherSuitesIsOn
|
||||
tlsOcspOn = sslPolicy.OCSPIsOn
|
||||
tlsClientAuthType = sslconfigs.SSLClientAuthType(sslPolicy.ClientAuthType)
|
||||
|
||||
if len(sslPolicy.Certs) > 0 {
|
||||
cert := sslPolicy.Certs[0]
|
||||
originCertPem = string(cert.CertData)
|
||||
originKeyPem = string(cert.KeyData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(originCertPem) == 0 || len(originKeyPem) == 0 {
|
||||
this.Fail("请上传或选择证书")
|
||||
}
|
||||
|
||||
settings["originHttps"] = true
|
||||
settings["originCertPem"] = originCertPem
|
||||
settings["originKeyPem"] = originKeyPem
|
||||
if len(tlsMinVersion) == 0 {
|
||||
tlsMinVersion = "TLS 1.1"
|
||||
}
|
||||
settings["tlsMinVersion"] = tlsMinVersion
|
||||
settings["tlsCipherSuitesOn"] = tlsCipherSuitesOn
|
||||
settings["tlsOcspOn"] = tlsOcspOn
|
||||
settings["tlsClientAuthType"] = int(tlsClientAuthType)
|
||||
settings["lastModifiedAt"] = nowDateTime()
|
||||
settings["certUpdatedAt"] = nowDateTime()
|
||||
|
||||
saveClusterSettings(params.ClusterId, settings)
|
||||
|
||||
currentDefaultClusterId := policies.LoadDefaultClusterID()
|
||||
if params.IsDefaultCluster {
|
||||
policies.SaveDefaultClusterID(params.ClusterId)
|
||||
} else if currentDefaultClusterId == params.ClusterId {
|
||||
policies.SaveDefaultClusterID(0)
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
var clusterSettingsStore = struct {
|
||||
sync.RWMutex
|
||||
data map[int64]maps.Map
|
||||
}{
|
||||
data: map[int64]maps.Map{},
|
||||
}
|
||||
|
||||
func defaultClusterSettings(cluster maps.Map) maps.Map {
|
||||
installDir := strings.TrimSpace(cluster.GetString("installDir"))
|
||||
if len(installDir) == 0 {
|
||||
installDir = "/opt/edge-httpdns"
|
||||
}
|
||||
|
||||
return maps.Map{
|
||||
"name": cluster.GetString("name"),
|
||||
"gatewayDomain": strings.TrimSpace(cluster.GetString("gatewayDomain")),
|
||||
"cacheTtl": cluster.GetInt("cacheTtl"),
|
||||
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
|
||||
"installDir": installDir,
|
||||
"isOn": cluster.GetBool("isOn"),
|
||||
"originHttps": true,
|
||||
"originCertPem": "",
|
||||
"originKeyPem": "",
|
||||
"tlsMinVersion": "TLS 1.1",
|
||||
"tlsCipherSuitesOn": false,
|
||||
"tlsOcspOn": false,
|
||||
"tlsClientAuthType": 0,
|
||||
"certUpdatedAt": "",
|
||||
"lastModifiedAt": "",
|
||||
}
|
||||
}
|
||||
|
||||
func cloneClusterSettings(settings maps.Map) maps.Map {
|
||||
return maps.Map{
|
||||
"name": settings.GetString("name"),
|
||||
"gatewayDomain": settings.GetString("gatewayDomain"),
|
||||
"cacheTtl": settings.GetInt("cacheTtl"),
|
||||
"fallbackTimeout": settings.GetInt("fallbackTimeout"),
|
||||
"installDir": settings.GetString("installDir"),
|
||||
"isOn": settings.GetBool("isOn"),
|
||||
"originHttps": true,
|
||||
"originCertPem": settings.GetString("originCertPem"),
|
||||
"originKeyPem": settings.GetString("originKeyPem"),
|
||||
"tlsMinVersion": settings.GetString("tlsMinVersion"),
|
||||
"tlsCipherSuitesOn": settings.GetBool("tlsCipherSuitesOn"),
|
||||
"tlsOcspOn": settings.GetBool("tlsOcspOn"),
|
||||
"tlsClientAuthType": settings.GetInt("tlsClientAuthType"),
|
||||
"certUpdatedAt": settings.GetString("certUpdatedAt"),
|
||||
"lastModifiedAt": settings.GetString("lastModifiedAt"),
|
||||
}
|
||||
}
|
||||
|
||||
func loadClusterSettings(cluster maps.Map) maps.Map {
|
||||
clusterId := cluster.GetInt64("id")
|
||||
|
||||
clusterSettingsStore.RLock()
|
||||
settings, ok := clusterSettingsStore.data[clusterId]
|
||||
clusterSettingsStore.RUnlock()
|
||||
if ok {
|
||||
if len(settings.GetString("tlsMinVersion")) == 0 {
|
||||
settings["tlsMinVersion"] = "TLS 1.1"
|
||||
}
|
||||
return cloneClusterSettings(settings)
|
||||
}
|
||||
|
||||
settings = defaultClusterSettings(cluster)
|
||||
saveClusterSettings(clusterId, settings)
|
||||
return cloneClusterSettings(settings)
|
||||
}
|
||||
|
||||
func saveClusterSettings(clusterId int64, settings maps.Map) {
|
||||
clusterSettingsStore.Lock()
|
||||
clusterSettingsStore.data[clusterId] = cloneClusterSettings(settings)
|
||||
clusterSettingsStore.Unlock()
|
||||
}
|
||||
|
||||
func applyClusterSettingsOverrides(cluster maps.Map) {
|
||||
clusterId := cluster.GetInt64("id")
|
||||
if clusterId <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
clusterSettingsStore.RLock()
|
||||
settings, ok := clusterSettingsStore.data[clusterId]
|
||||
clusterSettingsStore.RUnlock()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
cluster["name"] = settings.GetString("name")
|
||||
cluster["gatewayDomain"] = settings.GetString("gatewayDomain")
|
||||
cluster["cacheTtl"] = settings.GetInt("cacheTtl")
|
||||
cluster["fallbackTimeout"] = settings.GetInt("fallbackTimeout")
|
||||
cluster["installDir"] = settings.GetString("installDir")
|
||||
cluster["isOn"] = settings.GetBool("isOn")
|
||||
}
|
||||
|
||||
func nowDateTime() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package clusters
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreateNodeAction struct {
|
||||
@@ -11,14 +10,18 @@ type CreateNodeAction struct {
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) Init() {
|
||||
this.Nav("", "node", "createNode")
|
||||
this.SecondMenu("nodes")
|
||||
this.Nav("httpdns", "cluster", "createNode")
|
||||
}
|
||||
|
||||
func (this *CreateNodeAction) RunGet(params struct{ ClusterId int64 }) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "node")
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["cluster"] = maps.Map{"id": params.ClusterId, "name": "Mock Cluster"}
|
||||
this.Data["cluster"] = cluster
|
||||
this.Show()
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ func (this *DeleteAction) RunGet(params struct {
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
cluster := pickCluster(params.ClusterId)
|
||||
|
||||
// 构建顶部 tabbar
|
||||
httpdnsutils.AddClusterTabbar(this.Parent(), cluster.GetString("name"), params.ClusterId, "delete")
|
||||
|
||||
this.Data["cluster"] = cluster
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package clusters
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
func mockClusters() []maps.Map {
|
||||
return []maps.Map{
|
||||
clusters := []maps.Map{
|
||||
{
|
||||
"id": int64(1),
|
||||
"name": "gateway-cn-hz",
|
||||
@@ -31,6 +31,12 @@ func mockClusters() []maps.Map {
|
||||
"isOn": true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, cluster := range clusters {
|
||||
applyClusterSettingsOverrides(cluster)
|
||||
}
|
||||
|
||||
return clusters
|
||||
}
|
||||
|
||||
func pickCluster(clusterId int64) maps.Map {
|
||||
|
||||
@@ -1,66 +1,15 @@
|
||||
package guide
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
httpdnsApps "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/apps"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
|
||||
httpdnsPolicies "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("httpdns", "guide", "")
|
||||
this.Nav("httpdns", "app", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
|
||||
apps := []maps.Map{
|
||||
{
|
||||
"id": int64(1),
|
||||
"name": "主站移动业务",
|
||||
"appId": "ab12xc34s2",
|
||||
"clusterId": int64(1),
|
||||
},
|
||||
{
|
||||
"id": int64(2),
|
||||
"name": "视频网关业务",
|
||||
"appId": "vd8992ksm1",
|
||||
"clusterId": int64(2),
|
||||
},
|
||||
{
|
||||
"id": int64(3),
|
||||
"name": "海外灰度测试",
|
||||
"appId": "ov7711hkq9",
|
||||
"clusterId": int64(1),
|
||||
},
|
||||
}
|
||||
|
||||
for _, app := range apps {
|
||||
clusterID := app.GetInt64("clusterId")
|
||||
app["gatewayDomain"] = httpdnsPolicies.LoadClusterGatewayByID(clusterID)
|
||||
|
||||
settings := httpdnsApps.LoadAppSettingsByAppID(app.GetString("appId"))
|
||||
if settings == nil {
|
||||
app["signSecret"] = ""
|
||||
app["signSecretMasked"] = ""
|
||||
app["aesSecret"] = ""
|
||||
app["aesSecretMasked"] = ""
|
||||
app["signEnabled"] = false
|
||||
continue
|
||||
}
|
||||
|
||||
app["signSecret"] = settings.GetString("signSecretPlain")
|
||||
app["signSecretMasked"] = settings.GetString("signSecretMasked")
|
||||
app["aesSecret"] = settings.GetString("aesSecretPlain")
|
||||
app["aesSecretMasked"] = settings.GetString("aesSecretMasked")
|
||||
app["signEnabled"] = settings.GetBool("signEnabled")
|
||||
}
|
||||
|
||||
this.Data["apps"] = apps
|
||||
this.Show()
|
||||
this.RedirectURL("/httpdns/apps")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package httpdnsutils
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -11,39 +13,55 @@ func AddLeftMenu(action *actionutils.ParentAction) {
|
||||
action.Data["teaSubMenu"] = tab
|
||||
action.Data["leftMenuItems"] = []maps.Map{
|
||||
{
|
||||
"name": "集群管理",
|
||||
"name": "\u96c6\u7fa4\u7ba1\u7406",
|
||||
"url": "/httpdns/clusters",
|
||||
"isActive": tab == "cluster",
|
||||
},
|
||||
{
|
||||
"name": "全局配置",
|
||||
"url": "/httpdns/policies",
|
||||
"isActive": tab == "policy",
|
||||
},
|
||||
{
|
||||
"name": "应用管理",
|
||||
"name": "\u5e94\u7528\u7ba1\u7406",
|
||||
"url": "/httpdns/apps",
|
||||
"isActive": tab == "app",
|
||||
},
|
||||
{
|
||||
"name": "SDK接入引导",
|
||||
"url": "/httpdns/guide",
|
||||
"isActive": tab == "guide",
|
||||
},
|
||||
{
|
||||
"name": "解析日志",
|
||||
"name": "\u8bbf\u95ee\u65e5\u5fd7",
|
||||
"url": "/httpdns/resolveLogs",
|
||||
"isActive": tab == "resolveLogs",
|
||||
},
|
||||
{
|
||||
"name": "运行日志",
|
||||
"name": "\u8fd0\u884c\u65e5\u5fd7",
|
||||
"url": "/httpdns/runtimeLogs",
|
||||
"isActive": tab == "runtimeLogs",
|
||||
},
|
||||
{
|
||||
"name": "解析测试",
|
||||
"name": "\u89e3\u6790\u6d4b\u8bd5",
|
||||
"url": "/httpdns/sandbox",
|
||||
"isActive": tab == "sandbox",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddClusterTabbar builds the top tabbar on cluster pages.
|
||||
func AddClusterTabbar(action *actionutils.ParentAction, clusterName string, clusterId int64, selectedTab string) {
|
||||
cid := strconv.FormatInt(clusterId, 10)
|
||||
tabbar := actionutils.NewTabbar()
|
||||
tabbar.Add("", "", "/httpdns/clusters", "arrow left", false)
|
||||
titleItem := tabbar.Add(clusterName, "", "/httpdns/clusters/cluster?clusterId="+cid, "angle right", true)
|
||||
titleItem.IsTitle = true
|
||||
tabbar.Add("\u8282\u70b9\u5217\u8868", "", "/httpdns/clusters/cluster?clusterId="+cid, "server", selectedTab == "node")
|
||||
tabbar.Add("\u96c6\u7fa4\u8bbe\u7f6e", "", "/httpdns/clusters/cluster/settings?clusterId="+cid, "setting", selectedTab == "setting")
|
||||
tabbar.Add("\u5220\u9664\u96c6\u7fa4", "", "/httpdns/clusters/delete?clusterId="+cid, "trash", selectedTab == "delete")
|
||||
actionutils.SetTabbar(action, tabbar)
|
||||
}
|
||||
|
||||
// AddAppTabbar builds the top tabbar on app pages.
|
||||
func AddAppTabbar(action *actionutils.ParentAction, appName string, appId int64, selectedTab string) {
|
||||
aid := strconv.FormatInt(appId, 10)
|
||||
tabbar := actionutils.NewTabbar()
|
||||
tabbar.Add("", "", "/httpdns/apps", "arrow left", false)
|
||||
titleItem := tabbar.Add(appName, "", "/httpdns/apps/domains?appId="+aid, "angle right", true)
|
||||
titleItem.IsTitle = true
|
||||
tabbar.Add("\u57df\u540d\u5217\u8868", "", "/httpdns/apps/domains?appId="+aid, "list", selectedTab == "domains")
|
||||
tabbar.Add("\u5e94\u7528\u8bbe\u7f6e", "", "/httpdns/apps/app/settings?appId="+aid, "setting", selectedTab == "settings")
|
||||
tabbar.Add("\u5220\u9664\u5e94\u7528", "", "/httpdns/apps/delete?appId="+aid, "trash", selectedTab == "delete")
|
||||
actionutils.SetTabbar(action, tabbar)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ func init() {
|
||||
Data("teaSubMenu", "cluster").
|
||||
Prefix("/httpdns").
|
||||
Get("", new(IndexAction)).
|
||||
GetPost("/addPortPopup", new(AddPortPopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,10 +23,9 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
DefaultClusterId int64
|
||||
EnableUserDomainVerify bool
|
||||
DefaultTTL int
|
||||
DefaultFallbackMs int
|
||||
DefaultClusterId int64
|
||||
DefaultTTL int
|
||||
DefaultFallbackMs int
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
@@ -50,7 +49,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
|
||||
saveGlobalPolicies(maps.Map{
|
||||
"defaultClusterId": params.DefaultClusterId,
|
||||
"enableUserDomainVerify": params.EnableUserDomainVerify,
|
||||
"enableUserDomainVerify": true,
|
||||
"defaultTTL": params.DefaultTTL,
|
||||
"defaultFallbackMs": params.DefaultFallbackMs,
|
||||
})
|
||||
|
||||
@@ -51,7 +51,7 @@ func loadGlobalPolicies() maps.Map {
|
||||
|
||||
return maps.Map{
|
||||
"defaultClusterId": globalPoliciesStore.data.GetInt64("defaultClusterId"),
|
||||
"enableUserDomainVerify": globalPoliciesStore.data.GetBool("enableUserDomainVerify"),
|
||||
"enableUserDomainVerify": true,
|
||||
"defaultTTL": globalPoliciesStore.data.GetInt("defaultTTL"),
|
||||
"defaultFallbackMs": globalPoliciesStore.data.GetInt("defaultFallbackMs"),
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func saveGlobalPolicies(policies maps.Map) {
|
||||
globalPoliciesStore.Lock()
|
||||
globalPoliciesStore.data = maps.Map{
|
||||
"defaultClusterId": policies.GetInt64("defaultClusterId"),
|
||||
"enableUserDomainVerify": policies.GetBool("enableUserDomainVerify"),
|
||||
"enableUserDomainVerify": true,
|
||||
"defaultTTL": policies.GetInt("defaultTTL"),
|
||||
"defaultFallbackMs": policies.GetInt("defaultFallbackMs"),
|
||||
}
|
||||
@@ -110,6 +110,14 @@ func LoadDefaultClusterID() int64 {
|
||||
return globalPoliciesStore.data.GetInt64("defaultClusterId")
|
||||
}
|
||||
|
||||
// SaveDefaultClusterID updates default deploy cluster id.
|
||||
// Pass 0 to clear and let caller fallback to first available cluster.
|
||||
func SaveDefaultClusterID(clusterID int64) {
|
||||
globalPoliciesStore.Lock()
|
||||
globalPoliciesStore.data["defaultClusterId"] = clusterID
|
||||
globalPoliciesStore.Unlock()
|
||||
}
|
||||
|
||||
// LoadClusterGatewayByID returns gateway domain for the selected cluster.
|
||||
func LoadClusterGatewayByID(clusterID int64) string {
|
||||
clusters := loadAvailableDeployClusters()
|
||||
|
||||
@@ -25,8 +25,16 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
if params.ClusterId > 0 {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
} else {
|
||||
this.Data["clusterId"] = ""
|
||||
}
|
||||
if params.NodeId > 0 {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
} else {
|
||||
this.Data["nodeId"] = ""
|
||||
}
|
||||
this.Data["appId"] = params.AppId
|
||||
this.Data["domain"] = params.Domain
|
||||
this.Data["status"] = params.Status
|
||||
|
||||
@@ -25,8 +25,16 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}) {
|
||||
httpdnsutils.AddLeftMenu(this.Parent())
|
||||
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
if params.ClusterId > 0 {
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
} else {
|
||||
this.Data["clusterId"] = ""
|
||||
}
|
||||
if params.NodeId > 0 {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
} else {
|
||||
this.Data["nodeId"] = ""
|
||||
}
|
||||
this.Data["dayFrom"] = params.DayFrom
|
||||
this.Data["dayTo"] = params.DayTo
|
||||
this.Data["level"] = params.Level
|
||||
@@ -123,7 +131,6 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
if !strings.Contains(strings.ToLower(log["tag"].(string)), keyword) &&
|
||||
!strings.Contains(strings.ToLower(log["module"].(string)), keyword) &&
|
||||
!strings.Contains(strings.ToLower(log["description"].(string)), keyword) &&
|
||||
!strings.Contains(strings.ToLower(log["nodeName"].(string)), keyword) {
|
||||
continue
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package sandbox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -17,22 +14,14 @@ type TestAction struct {
|
||||
}
|
||||
|
||||
func (this *TestAction) RunPost(params struct {
|
||||
AppId string
|
||||
Domain string
|
||||
ClientIp string
|
||||
Qtype string
|
||||
SDNSParamsJSON string
|
||||
AppId string
|
||||
Domain string
|
||||
ClientIp string
|
||||
Qtype string
|
||||
}) {
|
||||
if len(params.ClientIp) == 0 {
|
||||
params.ClientIp = "203.0.113.100"
|
||||
}
|
||||
params.SDNSParamsJSON = strings.TrimSpace(params.SDNSParamsJSON)
|
||||
|
||||
sdnsParams, err := parseSDNSParamsJSON(params.SDNSParamsJSON)
|
||||
if err != nil {
|
||||
this.Fail(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
clientSubnet := this.maskSubnet(params.ClientIp, 24, 56)
|
||||
if len(clientSubnet) == 0 {
|
||||
@@ -51,9 +40,6 @@ func (this *TestAction) RunPost(params struct {
|
||||
query.Set("dn", params.Domain)
|
||||
query.Set("cip", params.ClientIp)
|
||||
query.Set("qtype", params.Qtype)
|
||||
for _, item := range sdnsParams {
|
||||
query.Add("sdns_"+item.GetString("name"), item.GetString("value"))
|
||||
}
|
||||
requestURL := "https://api.httpdns.example.com/resolve?" + query.Encode()
|
||||
|
||||
this.Data["result"] = maps.Map{
|
||||
@@ -61,12 +47,11 @@ func (this *TestAction) RunPost(params struct {
|
||||
"message": "ok (mock)",
|
||||
"requestId": "mock-rid-20260221-001",
|
||||
"data": maps.Map{
|
||||
"request_url": requestURL,
|
||||
"client_ip": params.ClientIp,
|
||||
"client_region": "中国, 上海, 上海",
|
||||
"line_name": "默认线路",
|
||||
"sdns_params": sdnsParams,
|
||||
"ips": []string{"203.0.113.10", "203.0.113.11"},
|
||||
"request_url": requestURL,
|
||||
"client_ip": params.ClientIp,
|
||||
"client_region": "中国, 上海, 上海",
|
||||
"line_name": "默认线路",
|
||||
"ips": []string{"203.0.113.10", "203.0.113.11"},
|
||||
"records": []maps.Map{
|
||||
{
|
||||
"domain": params.Domain,
|
||||
@@ -108,44 +93,6 @@ func (this *TestAction) RunPost(params struct {
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func parseSDNSParamsJSON(raw string) ([]maps.Map, error) {
|
||||
if len(raw) == 0 {
|
||||
return []maps.Map{}, nil
|
||||
}
|
||||
|
||||
list := []maps.Map{}
|
||||
if err := json.Unmarshal([]byte(raw), &list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) > 10 {
|
||||
return nil, fmt.Errorf("sdns params should be <= 10")
|
||||
}
|
||||
|
||||
result := make([]maps.Map, 0, len(list))
|
||||
for _, item := range list {
|
||||
name := strings.TrimSpace(item.GetString("name"))
|
||||
value := strings.TrimSpace(item.GetString("value"))
|
||||
if len(name) == 0 && len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(name) == 0 || len(name) > 64 {
|
||||
return nil, fmt.Errorf("sdns param name should be in 1-64")
|
||||
}
|
||||
if len(value) == 0 || len(value) > 64 {
|
||||
return nil, fmt.Errorf("sdns param value should be in 1-64")
|
||||
}
|
||||
result = append(result, maps.Map{
|
||||
"name": name,
|
||||
"value": value,
|
||||
})
|
||||
}
|
||||
|
||||
if len(result) > 10 {
|
||||
return nil, fmt.Errorf("sdns params should be <= 10")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (this *TestAction) maskSubnet(ip string, ipv4Prefix int, ipv6Prefix int) string {
|
||||
parsed := net.ParseIP(ip)
|
||||
if parsed == nil {
|
||||
|
||||
Reference in New Issue
Block a user