Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2888634fb0 | ||
|
|
94defc3e0c | ||
|
|
9089ed2657 | ||
|
|
b60bb5f6da | ||
|
|
ff4ea41963 | ||
|
|
b7dccad449 | ||
|
|
7fead214d4 | ||
|
|
d9590ec605 | ||
|
|
20b936580f | ||
|
|
b7b43bc31f | ||
|
|
6fd4f26755 | ||
|
|
f15d114708 | ||
|
|
fc24195b55 | ||
|
|
ed5de57244 | ||
|
|
4ce347738f | ||
|
|
f6e725781c | ||
|
|
55d70418cc | ||
|
|
7f5b070e36 | ||
|
|
993c7ee822 | ||
|
|
b5bb4e0df9 | ||
|
|
9f120fd0e0 | ||
|
|
77d614c9ea | ||
|
|
531ec3c55d | ||
|
|
0d6c064194 | ||
|
|
180e86c643 |
@@ -12,5 +12,5 @@ dbs:
|
|||||||
|
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled", "enableHTTP2", "retry50X", "autoSystemTuning" ]
|
bool: [ "uamIsOn", "followPort", "requestHostExcludingPort", "autoRemoteStart", "autoInstallNftables", "enableIPLists", "detectAgents", "checkingPorts", "enableRecordHealthCheck", "offlineIsNotified", "http2Enabled", "http3Enabled", "enableHTTP2", "retry50X", "retry40X", "autoSystemTuning", "disableDefaultDB" ]
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
go run `dirname $0`/../cmd/sql-dump/main.go -dir=`dirname $0`
|
# generate 'internal/setup/sql.json' file
|
||||||
|
|
||||||
|
CWD="$(dirname "$0")"
|
||||||
|
|
||||||
|
go run "${CWD}"/../cmd/sql-dump/main.go -dir="${CWD}"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "1.2.10"
|
Version = "1.3.1"
|
||||||
|
|
||||||
ProductName = "Edge API"
|
ProductName = "Edge API"
|
||||||
ProcessName = "edge-api"
|
ProcessName = "edge-api"
|
||||||
@@ -20,7 +20,7 @@ const (
|
|||||||
|
|
||||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||||
|
|
||||||
NodeVersion = "1.2.10"
|
NodeVersion = "1.3.1"
|
||||||
|
|
||||||
// SQLVersion SQL版本号
|
// SQLVersion SQL版本号
|
||||||
SQLVersion = "11"
|
SQLVersion = "11"
|
||||||
|
|||||||
6
internal/db/models/authority/authority_key_dao_test.go
Normal file
6
internal/db/models/authority/authority_key_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package authority_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
@@ -2,6 +2,18 @@ package authority
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthorityKeyField_Id dbs.FieldName = "id" // ID
|
||||||
|
AuthorityKeyField_Value dbs.FieldName = "value" // Key值
|
||||||
|
AuthorityKeyField_DayFrom dbs.FieldName = "dayFrom" // 开始日期
|
||||||
|
AuthorityKeyField_DayTo dbs.FieldName = "dayTo" // 结束日期
|
||||||
|
AuthorityKeyField_Hostname dbs.FieldName = "hostname" // Hostname
|
||||||
|
AuthorityKeyField_MacAddresses dbs.FieldName = "macAddresses" // MAC地址
|
||||||
|
AuthorityKeyField_UpdatedAt dbs.FieldName = "updatedAt" // 创建/修改时间
|
||||||
|
AuthorityKeyField_Company dbs.FieldName = "company" // 公司组织
|
||||||
|
AuthorityKeyField_RequestCode dbs.FieldName = "requestCode" // 申请码
|
||||||
|
)
|
||||||
|
|
||||||
// AuthorityKey 企业版认证信息
|
// AuthorityKey 企业版认证信息
|
||||||
type AuthorityKey struct {
|
type AuthorityKey struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
@@ -12,17 +24,19 @@ type AuthorityKey struct {
|
|||||||
MacAddresses dbs.JSON `field:"macAddresses"` // MAC地址
|
MacAddresses dbs.JSON `field:"macAddresses"` // MAC地址
|
||||||
UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间
|
UpdatedAt uint64 `field:"updatedAt"` // 创建/修改时间
|
||||||
Company string `field:"company"` // 公司组织
|
Company string `field:"company"` // 公司组织
|
||||||
|
RequestCode string `field:"requestCode"` // 申请码
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthorityKeyOperator struct {
|
type AuthorityKeyOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
Value interface{} // Key值
|
Value any // Key值
|
||||||
DayFrom interface{} // 开始日期
|
DayFrom any // 开始日期
|
||||||
DayTo interface{} // 结束日期
|
DayTo any // 结束日期
|
||||||
Hostname interface{} // Hostname
|
Hostname any // Hostname
|
||||||
MacAddresses interface{} // MAC地址
|
MacAddresses any // MAC地址
|
||||||
UpdatedAt interface{} // 创建/修改时间
|
UpdatedAt any // 创建/修改时间
|
||||||
Company interface{} // 公司组织
|
Company any // 公司组织
|
||||||
|
RequestCode any // 申请码
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthorityKeyOperator() *AuthorityKeyOperator {
|
func NewAuthorityKeyOperator() *AuthorityKeyOperator {
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := map[string]interface{}{}
|
var fields = map[string]any{}
|
||||||
fields["serverId"] = accessLog.ServerId
|
fields["serverId"] = accessLog.ServerId
|
||||||
fields["nodeId"] = accessLog.NodeId
|
fields["nodeId"] = accessLog.NodeId
|
||||||
fields["status"] = accessLog.Status
|
fields["status"] = accessLog.Status
|
||||||
@@ -265,7 +265,11 @@ func (this *HTTPAccessLogDAO) CreateHTTPAccessLog(tx *dbs.Tx, dao *HTTPAccessLog
|
|||||||
fields["remoteAddr"] = accessLog.RemoteAddr
|
fields["remoteAddr"] = accessLog.RemoteAddr
|
||||||
}
|
}
|
||||||
if tableDef.HasDomain {
|
if tableDef.HasDomain {
|
||||||
fields["domain"] = accessLog.Host
|
if len(accessLog.Host) > 128 {
|
||||||
|
fields["domain"] = accessLog.Host[:128]
|
||||||
|
} else {
|
||||||
|
fields["domain"] = accessLog.Host
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := json.Marshal(accessLog)
|
content, err := json.Marshal(accessLog)
|
||||||
@@ -863,8 +867,4 @@ func (this *HTTPAccessLogDAO) SetupQueue() {
|
|||||||
oldAccessLogQueue = accessLogQueue
|
oldAccessLogQueue = accessLogQueue
|
||||||
accessLogQueue = make(chan *pb.HTTPAccessLog, config.MaxLength)
|
accessLogQueue = make(chan *pb.HTTPAccessLog, config.MaxLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Tea.IsTesting() {
|
|
||||||
remotelogs.Println("HTTP_ACCESS_LOG_QUEUE", "change queue "+string(configJSON))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func (this *HTTPAccessLogManager) FindLastTable(db *dbs.DB, day string, force bo
|
|||||||
|
|
||||||
// CreateTable 创建访问日志表格
|
// CreateTable 创建访问日志表格
|
||||||
func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error {
|
func (this *HTTPAccessLogManager) CreateTable(db *dbs.DB, tableName string) error {
|
||||||
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(128) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
|
_, err := db.Exec("CREATE TABLE `" + tableName + "` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',\n `serverId` int(11) unsigned DEFAULT '0' COMMENT '服务ID',\n `nodeId` int(11) unsigned DEFAULT '0' COMMENT '节点ID',\n `status` int(3) unsigned DEFAULT '0' COMMENT '状态码',\n `createdAt` bigint(11) unsigned DEFAULT '0' COMMENT '创建时间',\n `content` json DEFAULT NULL COMMENT '日志内容',\n `requestId` varchar(128) DEFAULT NULL COMMENT '请求ID',\n `firewallPolicyId` int(11) unsigned DEFAULT '0' COMMENT 'WAF策略ID',\n `firewallRuleGroupId` int(11) unsigned DEFAULT '0' COMMENT 'WAF分组ID',\n `firewallRuleSetId` int(11) unsigned DEFAULT '0' COMMENT 'WAF集ID',\n `firewallRuleId` int(11) unsigned DEFAULT '0' COMMENT 'WAF规则ID',\n `remoteAddr` varchar(64) DEFAULT NULL COMMENT 'IP地址',\n `domain` varchar(255) DEFAULT NULL COMMENT '域名',\n `requestBody` mediumblob COMMENT '请求内容',\n `responseBody` mediumblob COMMENT '响应内容',\n PRIMARY KEY (`id`),\n KEY `serverId` (`serverId`),\n KEY `nodeId` (`nodeId`),\n KEY `serverId_status` (`serverId`,`status`),\n KEY `requestId` (`requestId`),\n KEY `firewallPolicyId` (`firewallPolicyId`),\n KEY `firewallRuleGroupId` (`firewallRuleGroupId`),\n KEY `firewallRuleSetId` (`firewallRuleSetId`),\n KEY `firewallRuleId` (`firewallRuleId`),\n KEY `remoteAddr` (`remoteAddr`),\n KEY `domain` (`domain`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问日志';")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if CheckSQLErrCode(err, 1050) { // Error 1050: Table 'xxx' already exists
|
if CheckSQLErrCode(err, 1050) { // Error 1050: Table 'xxx' already exists
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAndOnPolicies(tx *dbs.Tx) (res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreatePolicy 创建策略
|
// CreatePolicy 创建策略
|
||||||
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool) (policyId int64, err error) {
|
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool) (policyId int64, err error) {
|
||||||
var op = NewHTTPAccessLogPolicyOperator()
|
var op = NewHTTPAccessLogPolicyOperator()
|
||||||
op.Name = name
|
op.Name = name
|
||||||
op.Type = policyType
|
op.Type = policyType
|
||||||
@@ -120,12 +120,13 @@ func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policy
|
|||||||
op.IsPublic = isPublic
|
op.IsPublic = isPublic
|
||||||
op.IsOn = true
|
op.IsOn = true
|
||||||
op.FirewallOnly = firewallOnly
|
op.FirewallOnly = firewallOnly
|
||||||
|
op.DisableDefaultDB = disableDefaultDB
|
||||||
op.State = HTTPAccessLogPolicyStateEnabled
|
op.State = HTTPAccessLogPolicyStateEnabled
|
||||||
return this.SaveInt64(tx, op)
|
return this.SaveInt64(tx, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePolicy 修改策略
|
// UpdatePolicy 修改策略
|
||||||
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, isOn bool) error {
|
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool, isOn bool) error {
|
||||||
if policyId <= 0 {
|
if policyId <= 0 {
|
||||||
return errors.New("invalid policyId")
|
return errors.New("invalid policyId")
|
||||||
}
|
}
|
||||||
@@ -159,6 +160,7 @@ func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, nam
|
|||||||
|
|
||||||
op.IsPublic = isPublic
|
op.IsPublic = isPublic
|
||||||
op.FirewallOnly = firewallOnly
|
op.FirewallOnly = firewallOnly
|
||||||
|
op.DisableDefaultDB = disableDefaultDB
|
||||||
op.IsOn = isOn
|
op.IsOn = isOn
|
||||||
return this.Save(tx, op)
|
return this.Save(tx, op)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,39 +2,59 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
HTTPAccessLogPolicyField_Id dbs.FieldName = "id" // ID
|
||||||
|
HTTPAccessLogPolicyField_TemplateId dbs.FieldName = "templateId" // 模版ID
|
||||||
|
HTTPAccessLogPolicyField_AdminId dbs.FieldName = "adminId" // 管理员ID
|
||||||
|
HTTPAccessLogPolicyField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
HTTPAccessLogPolicyField_State dbs.FieldName = "state" // 状态
|
||||||
|
HTTPAccessLogPolicyField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
HTTPAccessLogPolicyField_Name dbs.FieldName = "name" // 名称
|
||||||
|
HTTPAccessLogPolicyField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
HTTPAccessLogPolicyField_Type dbs.FieldName = "type" // 存储类型
|
||||||
|
HTTPAccessLogPolicyField_Options dbs.FieldName = "options" // 存储选项
|
||||||
|
HTTPAccessLogPolicyField_Conds dbs.FieldName = "conds" // 请求条件
|
||||||
|
HTTPAccessLogPolicyField_IsPublic dbs.FieldName = "isPublic" // 是否为公用
|
||||||
|
HTTPAccessLogPolicyField_FirewallOnly dbs.FieldName = "firewallOnly" // 是否只记录防火墙相关
|
||||||
|
HTTPAccessLogPolicyField_Version dbs.FieldName = "version" // 版本号
|
||||||
|
HTTPAccessLogPolicyField_DisableDefaultDB dbs.FieldName = "disableDefaultDB" // 是否停止默认数据库存储
|
||||||
|
)
|
||||||
|
|
||||||
// HTTPAccessLogPolicy 访问日志策略
|
// HTTPAccessLogPolicy 访问日志策略
|
||||||
type HTTPAccessLogPolicy struct {
|
type HTTPAccessLogPolicy struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
TemplateId uint32 `field:"templateId"` // 模版ID
|
TemplateId uint32 `field:"templateId"` // 模版ID
|
||||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||||
UserId uint32 `field:"userId"` // 用户ID
|
UserId uint32 `field:"userId"` // 用户ID
|
||||||
State uint8 `field:"state"` // 状态
|
State uint8 `field:"state"` // 状态
|
||||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||||
Name string `field:"name"` // 名称
|
Name string `field:"name"` // 名称
|
||||||
IsOn bool `field:"isOn"` // 是否启用
|
IsOn bool `field:"isOn"` // 是否启用
|
||||||
Type string `field:"type"` // 存储类型
|
Type string `field:"type"` // 存储类型
|
||||||
Options dbs.JSON `field:"options"` // 存储选项
|
Options dbs.JSON `field:"options"` // 存储选项
|
||||||
Conds dbs.JSON `field:"conds"` // 请求条件
|
Conds dbs.JSON `field:"conds"` // 请求条件
|
||||||
IsPublic bool `field:"isPublic"` // 是否为公用
|
IsPublic bool `field:"isPublic"` // 是否为公用
|
||||||
FirewallOnly uint8 `field:"firewallOnly"` // 是否只记录防火墙相关
|
FirewallOnly uint8 `field:"firewallOnly"` // 是否只记录防火墙相关
|
||||||
Version uint32 `field:"version"` // 版本号
|
Version uint32 `field:"version"` // 版本号
|
||||||
|
DisableDefaultDB bool `field:"disableDefaultDB"` // 是否停止默认数据库存储
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPAccessLogPolicyOperator struct {
|
type HTTPAccessLogPolicyOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
TemplateId interface{} // 模版ID
|
TemplateId any // 模版ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId any // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId any // 用户ID
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
CreatedAt interface{} // 创建时间
|
CreatedAt any // 创建时间
|
||||||
Name interface{} // 名称
|
Name any // 名称
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
Type interface{} // 存储类型
|
Type any // 存储类型
|
||||||
Options interface{} // 存储选项
|
Options any // 存储选项
|
||||||
Conds interface{} // 请求条件
|
Conds any // 请求条件
|
||||||
IsPublic interface{} // 是否为公用
|
IsPublic any // 是否为公用
|
||||||
FirewallOnly interface{} // 是否只记录防火墙相关
|
FirewallOnly any // 是否只记录防火墙相关
|
||||||
Version interface{} // 版本号
|
Version any // 版本号
|
||||||
|
DisableDefaultDB any // 是否停止默认数据库存储
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator {
|
func NewHTTPAccessLogPolicyOperator() *HTTPAccessLogPolicyOperator {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func (this *HTTPPageDAO) FindEnabledHTTPPage(tx *dbs.Tx, id int64) (*HTTPPage, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreatePage 创建Page
|
// CreatePage 创建Page
|
||||||
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) (pageId int64, err error) {
|
func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []string, bodyType serverconfigs.HTTPPageBodyType, url string, body string, newStatus int, exceptURLPatterns []*shared.URLPattern, onlyURLPatterns []*shared.URLPattern) (pageId int64, err error) {
|
||||||
var op = NewHTTPPageOperator()
|
var op = NewHTTPPageOperator()
|
||||||
op.UserId = userId
|
op.UserId = userId
|
||||||
op.IsOn = true
|
op.IsOn = true
|
||||||
@@ -94,6 +94,29 @@ func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []strin
|
|||||||
op.Url = url
|
op.Url = url
|
||||||
op.Body = body
|
op.Body = body
|
||||||
op.NewStatus = newStatus
|
op.NewStatus = newStatus
|
||||||
|
|
||||||
|
{
|
||||||
|
if exceptURLPatterns == nil {
|
||||||
|
exceptURLPatterns = []*shared.URLPattern{}
|
||||||
|
}
|
||||||
|
exceptURLPatternsJSON, err := json.Marshal(exceptURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
op.ExceptURLPatterns = exceptURLPatternsJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if onlyURLPatterns == nil {
|
||||||
|
onlyURLPatterns = []*shared.URLPattern{}
|
||||||
|
}
|
||||||
|
onlyURLPatternsJSON, err := json.Marshal(onlyURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
op.OnlyURLPatterns = onlyURLPatternsJSON
|
||||||
|
}
|
||||||
|
|
||||||
err = this.Save(tx, op)
|
err = this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@@ -103,7 +126,7 @@ func (this *HTTPPageDAO) CreatePage(tx *dbs.Tx, userId int64, statusList []strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePage 修改Page
|
// UpdatePage 修改Page
|
||||||
func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []string, bodyType shared.BodyType, url string, body string, newStatus int) error {
|
func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []string, bodyType serverconfigs.HTTPPageBodyType, url string, body string, newStatus int, exceptURLPatterns []*shared.URLPattern, onlyURLPatterns []*shared.URLPattern) error {
|
||||||
if pageId <= 0 {
|
if pageId <= 0 {
|
||||||
return errors.New("invalid pageId")
|
return errors.New("invalid pageId")
|
||||||
}
|
}
|
||||||
@@ -126,6 +149,29 @@ func (this *HTTPPageDAO) UpdatePage(tx *dbs.Tx, pageId int64, statusList []strin
|
|||||||
op.Url = url
|
op.Url = url
|
||||||
op.Body = body
|
op.Body = body
|
||||||
op.NewStatus = newStatus
|
op.NewStatus = newStatus
|
||||||
|
|
||||||
|
{
|
||||||
|
if exceptURLPatterns == nil {
|
||||||
|
exceptURLPatterns = []*shared.URLPattern{}
|
||||||
|
}
|
||||||
|
exceptURLPatternsJSON, err := json.Marshal(exceptURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
op.ExceptURLPatterns = exceptURLPatternsJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if onlyURLPatterns == nil {
|
||||||
|
onlyURLPatterns = []*shared.URLPattern{}
|
||||||
|
}
|
||||||
|
onlyURLPatternsJSON, err := json.Marshal(onlyURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
op.OnlyURLPatterns = onlyURLPatternsJSON
|
||||||
|
}
|
||||||
|
|
||||||
err = this.Save(tx, op)
|
err = this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -156,6 +202,14 @@ func (this *HTTPPageDAO) ClonePage(tx *dbs.Tx, fromPageId int64) (newPageId int6
|
|||||||
op.Body = page.Body
|
op.Body = page.Body
|
||||||
op.BodyType = page.BodyType
|
op.BodyType = page.BodyType
|
||||||
op.State = page.State
|
op.State = page.State
|
||||||
|
|
||||||
|
if len(page.ExceptURLPatterns) > 0 {
|
||||||
|
op.ExceptURLPatterns = page.ExceptURLPatterns
|
||||||
|
}
|
||||||
|
if len(page.OnlyURLPatterns) > 0 {
|
||||||
|
op.OnlyURLPatterns = page.OnlyURLPatterns
|
||||||
|
}
|
||||||
|
|
||||||
return this.SaveInt64(tx, op)
|
return this.SaveInt64(tx, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +233,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &serverconfigs.HTTPPageConfig{}
|
var config = &serverconfigs.HTTPPageConfig{}
|
||||||
config.Id = int64(page.Id)
|
config.Id = int64(page.Id)
|
||||||
config.IsOn = page.IsOn
|
config.IsOn = page.IsOn
|
||||||
config.NewStatus = int(page.NewStatus)
|
config.NewStatus = int(page.NewStatus)
|
||||||
@@ -188,7 +242,7 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
|
|||||||
config.BodyType = page.BodyType
|
config.BodyType = page.BodyType
|
||||||
|
|
||||||
if len(page.BodyType) == 0 {
|
if len(page.BodyType) == 0 {
|
||||||
page.BodyType = shared.BodyTypeURL
|
page.BodyType = serverconfigs.HTTPPageBodyTypeURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(page.StatusList) > 0 {
|
if len(page.StatusList) > 0 {
|
||||||
@@ -202,6 +256,28 @@ func (this *HTTPPageDAO) ComposePageConfig(tx *dbs.Tx, pageId int64, cacheMap *u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(page.ExceptURLPatterns) > 0 {
|
||||||
|
var exceptURLPatterns = []*shared.URLPattern{}
|
||||||
|
err = json.Unmarshal(page.ExceptURLPatterns, &exceptURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(exceptURLPatterns) > 0 {
|
||||||
|
config.ExceptURLPatterns = exceptURLPatterns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(page.OnlyURLPatterns) > 0 {
|
||||||
|
var onlyURLPatterns = []*shared.URLPattern{}
|
||||||
|
err = json.Unmarshal(page.OnlyURLPatterns, &onlyURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(onlyURLPatterns) > 0 {
|
||||||
|
config.OnlyURLPatterns = onlyURLPatterns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if cacheMap != nil {
|
if cacheMap != nil {
|
||||||
cacheMap.Put(cacheKey, config)
|
cacheMap.Put(cacheKey, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,33 +2,53 @@ package models
|
|||||||
|
|
||||||
import "github.com/iwind/TeaGo/dbs"
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
HTTPPageField_Id dbs.FieldName = "id" // ID
|
||||||
|
HTTPPageField_AdminId dbs.FieldName = "adminId" // 管理员ID
|
||||||
|
HTTPPageField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
HTTPPageField_IsOn dbs.FieldName = "isOn" // 是否启用
|
||||||
|
HTTPPageField_StatusList dbs.FieldName = "statusList" // 状态列表
|
||||||
|
HTTPPageField_Url dbs.FieldName = "url" // 页面URL
|
||||||
|
HTTPPageField_NewStatus dbs.FieldName = "newStatus" // 新状态码
|
||||||
|
HTTPPageField_State dbs.FieldName = "state" // 状态
|
||||||
|
HTTPPageField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
HTTPPageField_Body dbs.FieldName = "body" // 页面内容
|
||||||
|
HTTPPageField_BodyType dbs.FieldName = "bodyType" // 内容类型
|
||||||
|
HTTPPageField_ExceptURLPatterns dbs.FieldName = "exceptURLPatterns" // 例外URL
|
||||||
|
HTTPPageField_OnlyURLPatterns dbs.FieldName = "onlyURLPatterns" // 限制URL
|
||||||
|
)
|
||||||
|
|
||||||
// HTTPPage 特殊页面
|
// HTTPPage 特殊页面
|
||||||
type HTTPPage struct {
|
type HTTPPage struct {
|
||||||
Id uint32 `field:"id"` // ID
|
Id uint32 `field:"id"` // ID
|
||||||
AdminId uint32 `field:"adminId"` // 管理员ID
|
AdminId uint32 `field:"adminId"` // 管理员ID
|
||||||
UserId uint32 `field:"userId"` // 用户ID
|
UserId uint32 `field:"userId"` // 用户ID
|
||||||
IsOn bool `field:"isOn"` // 是否启用
|
IsOn bool `field:"isOn"` // 是否启用
|
||||||
StatusList dbs.JSON `field:"statusList"` // 状态列表
|
StatusList dbs.JSON `field:"statusList"` // 状态列表
|
||||||
Url string `field:"url"` // 页面URL
|
Url string `field:"url"` // 页面URL
|
||||||
NewStatus int32 `field:"newStatus"` // 新状态码
|
NewStatus int32 `field:"newStatus"` // 新状态码
|
||||||
State uint8 `field:"state"` // 状态
|
State uint8 `field:"state"` // 状态
|
||||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||||
Body string `field:"body"` // 页面内容
|
Body string `field:"body"` // 页面内容
|
||||||
BodyType string `field:"bodyType"` // 内容类型
|
BodyType string `field:"bodyType"` // 内容类型
|
||||||
|
ExceptURLPatterns dbs.JSON `field:"exceptURLPatterns"` // 例外URL
|
||||||
|
OnlyURLPatterns dbs.JSON `field:"onlyURLPatterns"` // 限制URL
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPPageOperator struct {
|
type HTTPPageOperator struct {
|
||||||
Id interface{} // ID
|
Id any // ID
|
||||||
AdminId interface{} // 管理员ID
|
AdminId any // 管理员ID
|
||||||
UserId interface{} // 用户ID
|
UserId any // 用户ID
|
||||||
IsOn interface{} // 是否启用
|
IsOn any // 是否启用
|
||||||
StatusList interface{} // 状态列表
|
StatusList any // 状态列表
|
||||||
Url interface{} // 页面URL
|
Url any // 页面URL
|
||||||
NewStatus interface{} // 新状态码
|
NewStatus any // 新状态码
|
||||||
State interface{} // 状态
|
State any // 状态
|
||||||
CreatedAt interface{} // 创建时间
|
CreatedAt any // 创建时间
|
||||||
Body interface{} // 页面内容
|
Body any // 页面内容
|
||||||
BodyType interface{} // 内容类型
|
BodyType any // 内容类型
|
||||||
|
ExceptURLPatterns any // 例外URL
|
||||||
|
OnlyURLPatterns any // 限制URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPPageOperator() *HTTPPageOperator {
|
func NewHTTPPageOperator() *HTTPPageOperator {
|
||||||
|
|||||||
@@ -111,14 +111,17 @@ func (this *MessageDAO) FindEnabledMessage(tx *dbs.Tx, id int64) (*Message, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateClusterMessage 创建集群消息
|
// CreateClusterMessage 创建集群消息
|
||||||
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, body string, paramsJSON []byte) error {
|
func (this *MessageDAO) CreateClusterMessage(tx *dbs.Tx, role string, clusterId int64, messageType MessageType, level string, subject string, shortBody string, body string, paramsJSON []byte) error {
|
||||||
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, body, paramsJSON)
|
if len(shortBody) == 0 {
|
||||||
|
shortBody = body
|
||||||
|
}
|
||||||
|
_, err := this.createMessage(tx, role, clusterId, 0, messageType, level, subject, shortBody, paramsJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送给媒介接收人
|
// 发送给媒介接收人
|
||||||
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, 0, 0, 0, messageType, subject, body)
|
err = SharedMessageTaskDAO.CreateMessageTasks(tx, role, clusterId, 0, 0, messageType, subject, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func TestMessageDAO_CreateClusterMessage(t *testing.T) {
|
|||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
|
|
||||||
dao := NewMessageDAO()
|
dao := NewMessageDAO()
|
||||||
err := dao.CreateClusterMessage(tx, nodeconfigs.NodeRoleNode, 1, "test", "error", "123", "123", []byte("456"))
|
err := dao.CreateClusterMessage(tx, nodeconfigs.NodeRoleNode, 1, "test", "error", "123", "123", "123", []byte("456"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ func (this *MessageReceiverDAO) FindEnabledBestFitReceivers(tx *dbs.Tx, role str
|
|||||||
} else if nodeId > 0 {
|
} else if nodeId > 0 {
|
||||||
query.Attr("nodeId", nodeId)
|
query.Attr("nodeId", nodeId)
|
||||||
} else if clusterId > 0 {
|
} else if clusterId > 0 {
|
||||||
|
query.Attr("serverId", 0)
|
||||||
|
query.Attr("nodeId", 0)
|
||||||
query.Attr("clusterId", clusterId)
|
query.Attr("clusterId", clusterId)
|
||||||
}
|
}
|
||||||
_, err = query.
|
_, err = query.
|
||||||
|
|||||||
@@ -8,20 +8,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMessageTaskDAO_FindSendingMessageTasks(t *testing.T) {
|
|
||||||
dbs.NotifyReady()
|
|
||||||
|
|
||||||
var tx *dbs.Tx
|
|
||||||
tasks, err := models.NewMessageTaskDAO().FindSendingMessageTasks(tx, 100)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(len(tasks), "tasks")
|
|
||||||
for _, task := range tasks {
|
|
||||||
t.Log("task:", task.Id, "recipient:", task.RecipientId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMessageTaskDAO_CleanExpiredMessageTasks(t *testing.T) {
|
func TestMessageTaskDAO_CleanExpiredMessageTasks(t *testing.T) {
|
||||||
var dao = models.NewMessageTaskDAO()
|
var dao = models.NewMessageTaskDAO()
|
||||||
var tx *dbs.Tx
|
var tx *dbs.Tx
|
||||||
|
|||||||
@@ -1021,7 +1021,7 @@ func (this *NodeClusterDAO) FindClusterBasicInfo(tx *dbs.Tx, clusterId int64, ca
|
|||||||
cluster, err := this.Query(tx).
|
cluster, err := this.Query(tx).
|
||||||
Pk(clusterId).
|
Pk(clusterId).
|
||||||
State(NodeClusterStateEnabled).
|
State(NodeClusterStateEnabled).
|
||||||
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables", "autoSystemTuning").
|
Result("id", "name", "timeZone", "nodeMaxThreads", "cachePolicyId", "httpFirewallPolicyId", "autoOpenPorts", "webp", "uam", "cc", "httpPages", "http3", "isOn", "ddosProtection", "clock", "globalServerConfig", "autoInstallNftables", "autoSystemTuning", "networkSecurity").
|
||||||
Find()
|
Find()
|
||||||
if err != nil || cluster == nil {
|
if err != nil || cluster == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1269,6 +1269,57 @@ func (this *NodeClusterDAO) FindClusterHTTP3Policy(tx *dbs.Tx, clusterId int64,
|
|||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateClusterNetworkSecurityPolicy 修改网络安全策略设置
|
||||||
|
func (this *NodeClusterDAO) UpdateClusterNetworkSecurityPolicy(tx *dbs.Tx, clusterId int64, networkSecurityPolicy *nodeconfigs.NetworkSecurityPolicy) error {
|
||||||
|
if networkSecurityPolicy == nil {
|
||||||
|
networkSecurityPolicy = nodeconfigs.NewNetworkSecurityPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
networkSecurityPolicyJSON, err := json.Marshal(networkSecurityPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = this.Query(tx).
|
||||||
|
Pk(clusterId).
|
||||||
|
Set("networkSecurity", networkSecurityPolicyJSON).
|
||||||
|
UpdateQuickly()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.NotifyNetworkSecurityUpdate(tx, clusterId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindClusterNetworkSecurityPolicy 查询网络安全策略设置
|
||||||
|
func (this *NodeClusterDAO) FindClusterNetworkSecurityPolicy(tx *dbs.Tx, clusterId int64, cacheMap *utils.CacheMap) (*nodeconfigs.NetworkSecurityPolicy, error) {
|
||||||
|
var cacheKey = this.Table + ":FindClusterNetworkSecurityPolicy:" + types.String(clusterId)
|
||||||
|
if cacheMap != nil {
|
||||||
|
cache, ok := cacheMap.Get(cacheKey)
|
||||||
|
if ok {
|
||||||
|
return cache.(*nodeconfigs.NetworkSecurityPolicy), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
networkSecurityPolicyJSON, err := this.Query(tx).
|
||||||
|
Pk(clusterId).
|
||||||
|
Result("networkSecurity").
|
||||||
|
FindJSONCol()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsNull(networkSecurityPolicyJSON) {
|
||||||
|
return nodeconfigs.NewNetworkSecurityPolicy(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var policy = nodeconfigs.NewNetworkSecurityPolicy()
|
||||||
|
err = json.Unmarshal(networkSecurityPolicyJSON, policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return policy, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateClusterHTTPPagesPolicy 修改自定义页面设置
|
// UpdateClusterHTTPPagesPolicy 修改自定义页面设置
|
||||||
func (this *NodeClusterDAO) UpdateClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, httpPagesPolicy *nodeconfigs.HTTPPagesPolicy) error {
|
func (this *NodeClusterDAO) UpdateClusterHTTPPagesPolicy(tx *dbs.Tx, clusterId int64, httpPagesPolicy *nodeconfigs.HTTPPagesPolicy) error {
|
||||||
if httpPagesPolicy == nil {
|
if httpPagesPolicy == nil {
|
||||||
@@ -1452,6 +1503,11 @@ func (this *NodeClusterDAO) NotifyHTTP3Update(tx *dbs.Tx, clusterId int64) error
|
|||||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTP3PolicyChanged)
|
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTP3PolicyChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifyNetworkSecurityUpdate 通知网络安全策略更新
|
||||||
|
func (this *NodeClusterDAO) NotifyNetworkSecurityUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||||
|
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeNetworkSecurityPolicyChanged)
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
|
// NotifyHTTPPagesPolicyUpdate 通知HTTP Pages更新
|
||||||
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
|
func (this *NodeClusterDAO) NotifyHTTPPagesPolicyUpdate(tx *dbs.Tx, clusterId int64) error {
|
||||||
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
|
return SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, clusterId, 0, 0, NodeTaskTypeHTTPPagesPolicyChanged)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ const (
|
|||||||
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
|
NodeClusterField_Cc dbs.FieldName = "cc" // CC设置
|
||||||
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
|
NodeClusterField_Http3 dbs.FieldName = "http3" // HTTP3设置
|
||||||
NodeClusterField_AutoSystemTuning dbs.FieldName = "autoSystemTuning" // 是否自动调整系统参数
|
NodeClusterField_AutoSystemTuning dbs.FieldName = "autoSystemTuning" // 是否自动调整系统参数
|
||||||
|
NodeClusterField_NetworkSecurity dbs.FieldName = "networkSecurity" // 网络安全策略
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeCluster 节点集群
|
// NodeCluster 节点集群
|
||||||
@@ -89,6 +90,7 @@ type NodeCluster struct {
|
|||||||
Cc dbs.JSON `field:"cc"` // CC设置
|
Cc dbs.JSON `field:"cc"` // CC设置
|
||||||
Http3 dbs.JSON `field:"http3"` // HTTP3设置
|
Http3 dbs.JSON `field:"http3"` // HTTP3设置
|
||||||
AutoSystemTuning bool `field:"autoSystemTuning"` // 是否自动调整系统参数
|
AutoSystemTuning bool `field:"autoSystemTuning"` // 是否自动调整系统参数
|
||||||
|
NetworkSecurity dbs.JSON `field:"networkSecurity"` // 网络安全策略
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeClusterOperator struct {
|
type NodeClusterOperator struct {
|
||||||
@@ -133,6 +135,7 @@ type NodeClusterOperator struct {
|
|||||||
Cc any // CC设置
|
Cc any // CC设置
|
||||||
Http3 any // HTTP3设置
|
Http3 any // HTTP3设置
|
||||||
AutoSystemTuning any // 是否自动调整系统参数
|
AutoSystemTuning any // 是否自动调整系统参数
|
||||||
|
NetworkSecurity any // 网络安全策略
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeClusterOperator() *NodeClusterOperator {
|
func NewNodeClusterOperator() *NodeClusterOperator {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func (this *NodeCluster) DecodeDDoSProtection() *ddosconfigs.ProtectionConfig {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasDDoSProtection 检查是否有DDOS设置
|
// HasDDoSProtection 检查是否有DDoS设置
|
||||||
func (this *NodeCluster) HasDDoSProtection() bool {
|
func (this *NodeCluster) HasDDoSProtection() bool {
|
||||||
var config = this.DecodeDDoSProtection()
|
var config = this.DecodeDDoSProtection()
|
||||||
if config != nil {
|
if config != nil {
|
||||||
@@ -46,6 +46,27 @@ func (this *NodeCluster) HasDDoSProtection() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasNetworkSecurityPolicy 检查是否有安全策略设置
|
||||||
|
func (this *NodeCluster) HasNetworkSecurityPolicy() bool {
|
||||||
|
var policy = this.DecodeNetworkSecurityPolicy()
|
||||||
|
if policy != nil {
|
||||||
|
return policy.IsOn()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeNetworkSecurityPolicy 解析安全策略设置
|
||||||
|
func (this *NodeCluster) DecodeNetworkSecurityPolicy() *nodeconfigs.NetworkSecurityPolicy {
|
||||||
|
var policy = nodeconfigs.NewNetworkSecurityPolicy()
|
||||||
|
if IsNotNull(this.NetworkSecurity) {
|
||||||
|
err := json.Unmarshal(this.NetworkSecurity, policy)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("NodeCluster.DecodeNetworkSecurityPolicy()", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return policy
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeClock 解析时钟配置
|
// DecodeClock 解析时钟配置
|
||||||
func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
|
func (this *NodeCluster) DecodeClock() *nodeconfigs.ClockConfig {
|
||||||
var clock = nodeconfigs.DefaultClockConfig()
|
var clock = nodeconfigs.DefaultClockConfig()
|
||||||
|
|||||||
@@ -1018,6 +1018,13 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
}
|
}
|
||||||
config.AllowedIPs = append(config.AllowedIPs, apiNodeIPs...)
|
config.AllowedIPs = append(config.AllowedIPs, apiNodeIPs...)
|
||||||
|
|
||||||
|
// 当前的节点IP地址
|
||||||
|
nodeNodeIPs, err := SharedNodeIPAddressDAO.FindAllEnabledAddressStringsWithNode(tx, nodeId, nodeconfigs.NodeRoleNode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.IPAddresses = nodeNodeIPs
|
||||||
|
|
||||||
// 所属集群
|
// 所属集群
|
||||||
var primaryClusterId = int64(node.ClusterId)
|
var primaryClusterId = int64(node.ClusterId)
|
||||||
var clusterIds = []int64{primaryClusterId}
|
var clusterIds = []int64{primaryClusterId}
|
||||||
@@ -1076,7 +1083,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 节点IP地址
|
// 所有节点IP地址
|
||||||
nodeIPAddresses, err := SharedNodeIPAddressDAO.FindAllAccessibleIPAddressesWithClusterId(tx, nodeconfigs.NodeRoleNode, clusterId, cacheMap)
|
nodeIPAddresses, err := SharedNodeIPAddressDAO.FindAllAccessibleIPAddressesWithClusterId(tx, nodeconfigs.NodeRoleNode, clusterId, cacheMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1221,6 +1228,11 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
|||||||
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
|
config.AutoSystemTuning = nodeCluster.AutoSystemTuning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 安全设置
|
||||||
|
if clusterIndex == 0 {
|
||||||
|
config.NetworkSecurityPolicy = nodeCluster.DecodeNetworkSecurityPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
clusterIndex++
|
clusterIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
|
|||||||
op.PrivateKey = privateKey
|
op.PrivateKey = privateKey
|
||||||
op.Passphrase = passphrase
|
op.Passphrase = passphrase
|
||||||
}
|
}
|
||||||
op.Su = su
|
if username != "root" { // only for non-root user
|
||||||
|
op.Su = su
|
||||||
|
}
|
||||||
op.Description = description
|
op.Description = description
|
||||||
op.NodeId = nodeId
|
op.NodeId = nodeId
|
||||||
op.State = NodeGrantStateEnabled
|
op.State = NodeGrantStateEnabled
|
||||||
@@ -117,7 +119,11 @@ func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, me
|
|||||||
op.PrivateKey = privateKey
|
op.PrivateKey = privateKey
|
||||||
op.Passphrase = passphrase
|
op.Passphrase = passphrase
|
||||||
}
|
}
|
||||||
op.Su = su
|
if username != "root" { // only for non-root user
|
||||||
|
op.Su = su
|
||||||
|
} else {
|
||||||
|
op.Su = false
|
||||||
|
}
|
||||||
op.Description = description
|
op.Description = description
|
||||||
op.NodeId = nodeId
|
op.NodeId = nodeId
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
|
|||||||
@@ -256,6 +256,32 @@ func (this *NodeIPAddressDAO) FindAllEnabledAddressesWithNode(tx *dbs.Tx, nodeId
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindAllEnabledAddressStringsWithNode 查找节点的所有的IP地址地府传
|
||||||
|
func (this *NodeIPAddressDAO) FindAllEnabledAddressStringsWithNode(tx *dbs.Tx, nodeId int64, role nodeconfigs.NodeRole) (result []string, err error) {
|
||||||
|
if len(role) == 0 {
|
||||||
|
role = nodeconfigs.NodeRoleNode
|
||||||
|
}
|
||||||
|
ones, err := this.Query(tx).
|
||||||
|
Attr("nodeId", nodeId).
|
||||||
|
Attr("role", role).
|
||||||
|
State(NodeIPAddressStateEnabled).
|
||||||
|
Result("ip", "backupIP").
|
||||||
|
FindAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, one := range ones {
|
||||||
|
var addr = one.(*NodeIPAddress)
|
||||||
|
result = append(result, addr.Ip)
|
||||||
|
if len(addr.BackupIP) > 0 {
|
||||||
|
result = append(result, addr.BackupIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// FindFirstNodeAccessIPAddress 查找节点的第一个可访问的IP地址
|
// FindFirstNodeAccessIPAddress 查找节点的第一个可访问的IP地址
|
||||||
func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddress(tx *dbs.Tx, nodeId int64, mustUp bool, role nodeconfigs.NodeRole) (ip string, addrId int64, err error) {
|
func (this *NodeIPAddressDAO) FindFirstNodeAccessIPAddress(tx *dbs.Tx, nodeId int64, mustUp bool, role nodeconfigs.NodeRole) (ip string, addrId int64, err error) {
|
||||||
if len(role) == 0 {
|
if len(role) == 0 {
|
||||||
|
|||||||
@@ -17,21 +17,22 @@ type NodeTaskType = string
|
|||||||
const (
|
const (
|
||||||
// CDN相关
|
// CDN相关
|
||||||
|
|
||||||
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
|
NodeTaskTypeConfigChanged NodeTaskType = "configChanged" // 节点整体配置变化
|
||||||
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
|
NodeTaskTypeDDosProtectionChanged NodeTaskType = "ddosProtectionChanged" // 节点DDoS配置变更
|
||||||
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
|
NodeTaskTypeGlobalServerConfigChanged NodeTaskType = "globalServerConfigChanged" // 全局服务设置变化
|
||||||
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
|
NodeTaskTypeIPListDeleted NodeTaskType = "ipListDeleted" // IPList被删除
|
||||||
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
|
NodeTaskTypeIPItemChanged NodeTaskType = "ipItemChanged" // IP条目变更
|
||||||
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
|
NodeTaskTypeNodeVersionChanged NodeTaskType = "nodeVersionChanged" // 节点版本变化
|
||||||
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
|
NodeTaskTypeScriptsChanged NodeTaskType = "scriptsChanged" // 脚本配置变化
|
||||||
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
|
NodeTaskTypeNodeLevelChanged NodeTaskType = "nodeLevelChanged" // 节点级别变化
|
||||||
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
|
NodeTaskTypeUserServersStateChanged NodeTaskType = "userServersStateChanged" // 用户服务状态变化
|
||||||
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
|
NodeTaskTypeUAMPolicyChanged NodeTaskType = "uamPolicyChanged" // UAM策略变化
|
||||||
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
|
NodeTaskTypeHTTPPagesPolicyChanged NodeTaskType = "httpPagesPolicyChanged" // 自定义页面变化
|
||||||
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
|
NodeTaskTypeHTTPCCPolicyChanged NodeTaskType = "httpCCPolicyChanged" // CC策略变化
|
||||||
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
|
NodeTaskTypeHTTP3PolicyChanged NodeTaskType = "http3PolicyChanged" // HTTP3策略变化
|
||||||
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
|
NodeTaskTypeNetworkSecurityPolicyChanged NodeTaskType = "networkSecurityPolicyChanged" // 网络安全策略变化
|
||||||
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
|
NodeTaskTypeUpdatingServers NodeTaskType = "updatingServers" // 更新一组服务
|
||||||
|
NodeTaskTypeTOAChanged NodeTaskType = "toaChanged" // TOA配置变化
|
||||||
|
|
||||||
// NS相关
|
// NS相关
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
"github.com/iwind/TeaGo/types"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -153,12 +147,13 @@ func (this *NodeThresholdDAO) FindAllEnabledAndOnClusterThresholds(tx *dbs.Tx, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindAllEnabledAndOnNodeThresholds 查询节点专属的阈值设置
|
// FindAllEnabledAndOnNodeThresholds 查询节点专属的阈值设置
|
||||||
func (this *NodeThresholdDAO) FindAllEnabledAndOnNodeThresholds(tx *dbs.Tx, role string, nodeId int64, item string) (result []*NodeThreshold, err error) {
|
func (this *NodeThresholdDAO) FindAllEnabledAndOnNodeThresholds(tx *dbs.Tx, role string, clusterId int64, nodeId int64, item string) (result []*NodeThreshold, err error) {
|
||||||
if nodeId <= 0 {
|
if clusterId <= 0 || nodeId <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = this.Query(tx).
|
_, err = this.Query(tx).
|
||||||
Attr("role", role).
|
Attr("role", role).
|
||||||
|
Attr("clusterId", clusterId).
|
||||||
Attr("nodeId", nodeId).
|
Attr("nodeId", nodeId).
|
||||||
Attr("item", item).
|
Attr("item", item).
|
||||||
Attr("isOn", true).
|
Attr("isOn", true).
|
||||||
@@ -186,87 +181,3 @@ func (this *NodeThresholdDAO) CountAllEnabledThresholds(tx *dbs.Tx, role string,
|
|||||||
query.State(NodeThresholdStateEnabled)
|
query.State(NodeThresholdStateEnabled)
|
||||||
return query.Count()
|
return query.Count()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FireNodeThreshold 触发相关阈值设置
|
|
||||||
func (this *NodeThresholdDAO) FireNodeThreshold(tx *dbs.Tx, role string, nodeId int64, item string) error {
|
|
||||||
clusterId, err := SharedNodeDAO.FindNodeClusterId(tx, nodeId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if clusterId == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 集群相关阈值
|
|
||||||
var thresholds []*NodeThreshold
|
|
||||||
{
|
|
||||||
clusterThresholds, err := this.FindAllEnabledAndOnClusterThresholds(tx, role, clusterId, item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
thresholds = append(thresholds, clusterThresholds...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 节点相关阈值
|
|
||||||
{
|
|
||||||
nodeThresholds, err := this.FindAllEnabledAndOnNodeThresholds(tx, role, nodeId, item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
thresholds = append(thresholds, nodeThresholds...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(thresholds) > 0 {
|
|
||||||
for _, threshold := range thresholds {
|
|
||||||
if len(threshold.Param) == 0 || threshold.Duration <= 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
paramValue, err := SharedNodeValueDAO.SumNodeValues(tx, role, nodeId, item, threshold.Param, threshold.SumMethod, types.Int32(threshold.Duration), threshold.DurationUnit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
originValue := nodeconfigs.UnmarshalNodeValue(threshold.Value)
|
|
||||||
thresholdValue := types.Float64(originValue)
|
|
||||||
isMatched := nodeconfigs.CompareNodeValue(threshold.Operator, paramValue, thresholdValue)
|
|
||||||
if isMatched {
|
|
||||||
// TODO 执行其他动作
|
|
||||||
|
|
||||||
// 是否已经通知过
|
|
||||||
if threshold.NotifyDuration > 0 && threshold.NotifiedAt > 0 && time.Now().Unix()-int64(threshold.NotifiedAt) < int64(threshold.NotifyDuration*60) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建消息
|
|
||||||
nodeName, err := SharedNodeDAO.FindNodeName(tx, nodeId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
itemName := nodeconfigs.FindNodeValueItemName(threshold.Item)
|
|
||||||
paramName := nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param)
|
|
||||||
operatorName := nodeconfigs.FindNodeValueOperatorName(threshold.Operator)
|
|
||||||
|
|
||||||
subject := "节点 \"" + nodeName + "\" " + itemName + " 达到阈值"
|
|
||||||
body := "节点 \"" + nodeName + "\" " + itemName + " 达到阈值\n阈值设置:" + paramName + " " + operatorName + " " + originValue + "\n当前值:" + fmt.Sprintf("%.2f", paramValue) + "\n触发时间:" + timeutil.Format("Y-m-d H:i:s")
|
|
||||||
if len(threshold.Message) > 0 {
|
|
||||||
body = threshold.Message
|
|
||||||
body = strings.Replace(body, "${item.name}", itemName, -1)
|
|
||||||
body = strings.Replace(body, "${value}", fmt.Sprintf("%.2f", paramValue), -1)
|
|
||||||
}
|
|
||||||
err = SharedMessageDAO.CreateNodeMessage(tx, role, clusterId, nodeId, MessageTypeThresholdSatisfied, MessageLevelWarning, subject, body, maps.Map{}.AsJSON(), true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置通知时间
|
|
||||||
_, err = this.Query(tx).
|
|
||||||
Pk(threshold.Id).
|
|
||||||
Set("notifiedAt", time.Now().Unix()).
|
|
||||||
Update()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
12
internal/db/models/node_threshold_dao_ext.go
Normal file
12
internal/db/models/node_threshold_dao_ext.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
// FireNodeThreshold 触发相关阈值设置
|
||||||
|
func (this *NodeThresholdDAO) FireNodeThreshold(tx *dbs.Tx, role string, nodeId int64, item string) error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -227,6 +227,8 @@ func (this *OriginDAO) UpdateOrigin(tx *dbs.Tx,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
op.Oss = ossConfigJSON
|
op.Oss = ossConfigJSON
|
||||||
|
} else {
|
||||||
|
op.Oss = dbs.SQL("NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
op.Description = description
|
op.Description = description
|
||||||
@@ -400,6 +402,7 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addr
|
// addr
|
||||||
|
var isOSS = false
|
||||||
if IsNotNull(origin.Addr) {
|
if IsNotNull(origin.Addr) {
|
||||||
var addr = &serverconfigs.NetworkAddressConfig{}
|
var addr = &serverconfigs.NetworkAddressConfig{}
|
||||||
err = json.Unmarshal(origin.Addr, addr)
|
err = json.Unmarshal(origin.Addr, addr)
|
||||||
@@ -407,10 +410,11 @@ func (this *OriginDAO) ComposeOriginConfig(tx *dbs.Tx, originId int64, dataMap *
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.Addr = addr
|
config.Addr = addr
|
||||||
|
isOSS = ossconfigs.IsOSSProtocol(string(addr.Protocol))
|
||||||
}
|
}
|
||||||
|
|
||||||
// oss
|
// oss
|
||||||
if IsNotNull(origin.Oss) {
|
if isOSS && IsNotNull(origin.Oss) {
|
||||||
var ossConfig = ossconfigs.NewOSSConfig()
|
var ossConfig = ossconfigs.NewOSSConfig()
|
||||||
err = json.Unmarshal(origin.Oss, ossConfig)
|
err = json.Unmarshal(origin.Oss, ossConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ func (this *ReverseProxyDAO) ComposeReverseProxyConfig(tx *dbs.Tx, reverseProxyI
|
|||||||
config.AutoFlush = reverseProxy.AutoFlush == 1
|
config.AutoFlush = reverseProxy.AutoFlush == 1
|
||||||
config.FollowRedirects = reverseProxy.FollowRedirects == 1
|
config.FollowRedirects = reverseProxy.FollowRedirects == 1
|
||||||
config.Retry50X = reverseProxy.Retry50X
|
config.Retry50X = reverseProxy.Retry50X
|
||||||
|
config.Retry40X = reverseProxy.Retry40X
|
||||||
|
|
||||||
var schedulingConfig = &serverconfigs.SchedulingConfig{}
|
var schedulingConfig = &serverconfigs.SchedulingConfig{}
|
||||||
if IsNotNull(reverseProxy.Scheduling) {
|
if IsNotNull(reverseProxy.Scheduling) {
|
||||||
@@ -219,7 +220,8 @@ func (this *ReverseProxyDAO) CreateReverseProxy(tx *dbs.Tx, adminId int64, userI
|
|||||||
op.AdminId = adminId
|
op.AdminId = adminId
|
||||||
op.UserId = userId
|
op.UserId = userId
|
||||||
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
|
op.RequestHostType = serverconfigs.RequestHostTypeProxyServer
|
||||||
op.Retry50X = true
|
op.Retry50X = false
|
||||||
|
op.Retry40X = false
|
||||||
|
|
||||||
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
|
defaultHeaders := []string{"X-Real-IP", "X-Forwarded-For", "X-Forwarded-By", "X-Forwarded-Host", "X-Forwarded-Proto"}
|
||||||
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
|
defaultHeadersJSON, err := json.Marshal(defaultHeaders)
|
||||||
@@ -428,7 +430,8 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
|||||||
maxIdleConns int32,
|
maxIdleConns int32,
|
||||||
proxyProtocolJSON []byte,
|
proxyProtocolJSON []byte,
|
||||||
followRedirects bool,
|
followRedirects bool,
|
||||||
retry50X bool) error {
|
retry50X bool,
|
||||||
|
retry40X bool) error {
|
||||||
if reverseProxyId <= 0 {
|
if reverseProxyId <= 0 {
|
||||||
return errors.New("invalid reverseProxyId")
|
return errors.New("invalid reverseProxyId")
|
||||||
}
|
}
|
||||||
@@ -494,6 +497,7 @@ func (this *ReverseProxyDAO) UpdateReverseProxy(tx *dbs.Tx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
op.Retry50X = retry50X
|
op.Retry50X = retry50X
|
||||||
|
op.Retry40X = retry40X
|
||||||
|
|
||||||
err = this.Save(tx, op)
|
err = this.Save(tx, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const (
|
|||||||
ReverseProxyField_ProxyProtocol dbs.FieldName = "proxyProtocol" // Proxy Protocol配置
|
ReverseProxyField_ProxyProtocol dbs.FieldName = "proxyProtocol" // Proxy Protocol配置
|
||||||
ReverseProxyField_FollowRedirects dbs.FieldName = "followRedirects" // 回源跟随
|
ReverseProxyField_FollowRedirects dbs.FieldName = "followRedirects" // 回源跟随
|
||||||
ReverseProxyField_Retry50X dbs.FieldName = "retry50X" // 启用50X重试
|
ReverseProxyField_Retry50X dbs.FieldName = "retry50X" // 启用50X重试
|
||||||
|
ReverseProxyField_Retry40X dbs.FieldName = "retry40X" // 启用40X重试
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReverseProxy 反向代理配置
|
// ReverseProxy 反向代理配置
|
||||||
@@ -57,6 +58,7 @@ type ReverseProxy struct {
|
|||||||
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
|
ProxyProtocol dbs.JSON `field:"proxyProtocol"` // Proxy Protocol配置
|
||||||
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
|
FollowRedirects uint8 `field:"followRedirects"` // 回源跟随
|
||||||
Retry50X bool `field:"retry50X"` // 启用50X重试
|
Retry50X bool `field:"retry50X"` // 启用50X重试
|
||||||
|
Retry40X bool `field:"retry40X"` // 启用40X重试
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReverseProxyOperator struct {
|
type ReverseProxyOperator struct {
|
||||||
@@ -85,6 +87,7 @@ type ReverseProxyOperator struct {
|
|||||||
ProxyProtocol any // Proxy Protocol配置
|
ProxyProtocol any // Proxy Protocol配置
|
||||||
FollowRedirects any // 回源跟随
|
FollowRedirects any // 回源跟随
|
||||||
Retry50X any // 启用50X重试
|
Retry50X any // 启用50X重试
|
||||||
|
Retry40X any // 启用40X重试
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReverseProxyOperator() *ReverseProxyOperator {
|
func NewReverseProxyOperator() *ReverseProxyOperator {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func (this *ServerDomainHourlyStatDAO) IncreaseHourlyStat(tx *dbs.Tx, clusterId
|
|||||||
if len(hour) != 10 {
|
if len(hour) != 10 {
|
||||||
return errors.New("invalid hour '" + hour + "'")
|
return errors.New("invalid hour '" + hour + "'")
|
||||||
}
|
}
|
||||||
if len(domain) == 0 {
|
if len(domain) == 0 || len(domain) > 64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := this.Query(tx).
|
err := this.Query(tx).
|
||||||
|
|||||||
@@ -428,6 +428,20 @@ func (this *UserDAO) CheckUserEmailPassword(tx *dbs.Tx, verifiedEmail string, en
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserMobilePassword 检查邮箱+密码
|
||||||
|
func (this *UserDAO) CheckUserMobilePassword(tx *dbs.Tx, verifiedEmail string, encryptedPassword string) (int64, error) {
|
||||||
|
if len(verifiedEmail) == 0 || len(encryptedPassword) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
Attr("verifiedMobile", verifiedEmail).
|
||||||
|
Attr("password", encryptedPassword).
|
||||||
|
Attr("state", UserStateEnabled).
|
||||||
|
Attr("isOn", true).
|
||||||
|
ResultPk().
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserClusterId 查找用户所在集群
|
// FindUserClusterId 查找用户所在集群
|
||||||
func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error) {
|
func (this *UserDAO) FindUserClusterId(tx *dbs.Tx, userId int64) (int64, error) {
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
@@ -663,7 +677,7 @@ func (this *UserDAO) RenewUserServersState(tx *dbs.Tx, userId int64) (bool, erro
|
|||||||
// FindUserIdWithVerifiedEmail 使用验证后Email查找用户ID
|
// FindUserIdWithVerifiedEmail 使用验证后Email查找用户ID
|
||||||
func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail string) (int64, error) {
|
func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail string) (int64, error) {
|
||||||
if len(verifiedEmail) == 0 {
|
if len(verifiedEmail) == 0 {
|
||||||
|
return 0, nil
|
||||||
}
|
}
|
||||||
return this.Query(tx).
|
return this.Query(tx).
|
||||||
ResultPk().
|
ResultPk().
|
||||||
@@ -672,6 +686,18 @@ func (this *UserDAO) FindUserIdWithVerifiedEmail(tx *dbs.Tx, verifiedEmail strin
|
|||||||
FindInt64Col(0)
|
FindInt64Col(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindUserIdWithVerifiedMobile 使用验证后手机号码查找用户ID
|
||||||
|
func (this *UserDAO) FindUserIdWithVerifiedMobile(tx *dbs.Tx, verifiedMobile string) (int64, error) {
|
||||||
|
if len(verifiedMobile) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
ResultPk().
|
||||||
|
State(UserStateEnabled).
|
||||||
|
Attr("verifiedMobile", verifiedMobile).
|
||||||
|
FindInt64Col(0)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateUserVerifiedEmail 修改已激活邮箱
|
// UpdateUserVerifiedEmail 修改已激活邮箱
|
||||||
func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedEmail string) error {
|
func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedEmail string) error {
|
||||||
if userId <= 0 {
|
if userId <= 0 {
|
||||||
@@ -684,6 +710,18 @@ func (this *UserDAO) UpdateUserVerifiedEmail(tx *dbs.Tx, userId int64, verifiedE
|
|||||||
UpdateQuickly()
|
UpdateQuickly()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateUserVerifiedMobile 修改已激活手机号码
|
||||||
|
func (this *UserDAO) UpdateUserVerifiedMobile(tx *dbs.Tx, userId int64, verifiedMobile string) error {
|
||||||
|
if userId <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return this.Query(tx).
|
||||||
|
Pk(userId).
|
||||||
|
Set("verifiedMobile", verifiedMobile).
|
||||||
|
Set("mobileIsVerified", true).
|
||||||
|
UpdateQuickly()
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserBandwidthAlgoForView 获取用户浏览用的带宽算法
|
// FindUserBandwidthAlgoForView 获取用户浏览用的带宽算法
|
||||||
func (this *UserDAO) FindUserBandwidthAlgoForView(tx *dbs.Tx, userId int64, uiConfig *systemconfigs.UserUIConfig) (bandwidthAlgo string, err error) {
|
func (this *UserDAO) FindUserBandwidthAlgoForView(tx *dbs.Tx, userId int64, uiConfig *systemconfigs.UserUIConfig) (bandwidthAlgo string, err error) {
|
||||||
bandwidthAlgo, err = this.Query(tx).
|
bandwidthAlgo, err = this.Query(tx).
|
||||||
|
|||||||
28
internal/db/models/user_mobile_verification_dao.go
Normal file
28
internal/db/models/user_mobile_verification_dao.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/iwind/TeaGo/dbs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserMobileVerificationDAO dbs.DAO
|
||||||
|
|
||||||
|
func NewUserMobileVerificationDAO() *UserMobileVerificationDAO {
|
||||||
|
return dbs.NewDAO(&UserMobileVerificationDAO{
|
||||||
|
DAOObject: dbs.DAOObject{
|
||||||
|
DB: Tea.Env,
|
||||||
|
Table: "edgeUserMobileVerifications",
|
||||||
|
Model: new(UserMobileVerification),
|
||||||
|
PkName: "id",
|
||||||
|
},
|
||||||
|
}).(*UserMobileVerificationDAO)
|
||||||
|
}
|
||||||
|
|
||||||
|
var SharedUserMobileVerificationDAO *UserMobileVerificationDAO
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbs.OnReady(func() {
|
||||||
|
SharedUserMobileVerificationDAO = NewUserMobileVerificationDAO()
|
||||||
|
})
|
||||||
|
}
|
||||||
6
internal/db/models/user_mobile_verification_dao_test.go
Normal file
6
internal/db/models/user_mobile_verification_dao_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
|
)
|
||||||
41
internal/db/models/user_mobile_verification_model.go
Normal file
41
internal/db/models/user_mobile_verification_model.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "github.com/iwind/TeaGo/dbs"
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserMobileVerificationField_Id dbs.FieldName = "id" // ID
|
||||||
|
UserMobileVerificationField_Mobile dbs.FieldName = "mobile" // 手机号码
|
||||||
|
UserMobileVerificationField_UserId dbs.FieldName = "userId" // 用户ID
|
||||||
|
UserMobileVerificationField_Code dbs.FieldName = "code" // 激活码
|
||||||
|
UserMobileVerificationField_CreatedAt dbs.FieldName = "createdAt" // 创建时间
|
||||||
|
UserMobileVerificationField_IsSent dbs.FieldName = "isSent" // 是否已发送
|
||||||
|
UserMobileVerificationField_IsVerified dbs.FieldName = "isVerified" // 是否已激活
|
||||||
|
UserMobileVerificationField_Day dbs.FieldName = "day" // YYYYMMDD
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserMobileVerification 邮箱激活邮件队列
|
||||||
|
type UserMobileVerification struct {
|
||||||
|
Id uint64 `field:"id"` // ID
|
||||||
|
Mobile string `field:"mobile"` // 手机号码
|
||||||
|
UserId uint64 `field:"userId"` // 用户ID
|
||||||
|
Code string `field:"code"` // 激活码
|
||||||
|
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||||
|
IsSent bool `field:"isSent"` // 是否已发送
|
||||||
|
IsVerified bool `field:"isVerified"` // 是否已激活
|
||||||
|
Day string `field:"day"` // YYYYMMDD
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserMobileVerificationOperator struct {
|
||||||
|
Id any // ID
|
||||||
|
Mobile any // 手机号码
|
||||||
|
UserId any // 用户ID
|
||||||
|
Code any // 激活码
|
||||||
|
CreatedAt any // 创建时间
|
||||||
|
IsSent any // 是否已发送
|
||||||
|
IsVerified any // 是否已激活
|
||||||
|
Day any // YYYYMMDD
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserMobileVerificationOperator() *UserMobileVerificationOperator {
|
||||||
|
return &UserMobileVerificationOperator{}
|
||||||
|
}
|
||||||
1
internal/db/models/user_mobile_verification_model_ext.go
Normal file
1
internal/db/models/user_mobile_verification_model_ext.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package models
|
||||||
@@ -10,6 +10,7 @@ const (
|
|||||||
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
|
UserField_Fullname dbs.FieldName = "fullname" // 真实姓名
|
||||||
UserField_Mobile dbs.FieldName = "mobile" // 手机号
|
UserField_Mobile dbs.FieldName = "mobile" // 手机号
|
||||||
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
|
UserField_VerifiedMobile dbs.FieldName = "verifiedMobile" // 已验证手机号
|
||||||
|
UserField_MobileIsVerified dbs.FieldName = "mobileIsVerified" // 手机号是否已验证
|
||||||
UserField_Tel dbs.FieldName = "tel" // 联系电话
|
UserField_Tel dbs.FieldName = "tel" // 联系电话
|
||||||
UserField_Remark dbs.FieldName = "remark" // 备注
|
UserField_Remark dbs.FieldName = "remark" // 备注
|
||||||
UserField_Email dbs.FieldName = "email" // 邮箱地址
|
UserField_Email dbs.FieldName = "email" // 邮箱地址
|
||||||
@@ -47,6 +48,7 @@ type User struct {
|
|||||||
Fullname string `field:"fullname"` // 真实姓名
|
Fullname string `field:"fullname"` // 真实姓名
|
||||||
Mobile string `field:"mobile"` // 手机号
|
Mobile string `field:"mobile"` // 手机号
|
||||||
VerifiedMobile string `field:"verifiedMobile"` // 已验证手机号
|
VerifiedMobile string `field:"verifiedMobile"` // 已验证手机号
|
||||||
|
MobileIsVerified uint8 `field:"mobileIsVerified"` // 手机号是否已验证
|
||||||
Tel string `field:"tel"` // 联系电话
|
Tel string `field:"tel"` // 联系电话
|
||||||
Remark string `field:"remark"` // 备注
|
Remark string `field:"remark"` // 备注
|
||||||
Email string `field:"email"` // 邮箱地址
|
Email string `field:"email"` // 邮箱地址
|
||||||
@@ -83,6 +85,7 @@ type UserOperator struct {
|
|||||||
Fullname any // 真实姓名
|
Fullname any // 真实姓名
|
||||||
Mobile any // 手机号
|
Mobile any // 手机号
|
||||||
VerifiedMobile any // 已验证手机号
|
VerifiedMobile any // 已验证手机号
|
||||||
|
MobileIsVerified any // 手机号是否已验证
|
||||||
Tel any // 联系电话
|
Tel any // 联系电话
|
||||||
Remark any // 备注
|
Remark any // 备注
|
||||||
Email any // 邮箱地址
|
Email any // 邮箱地址
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ var dnsPodHTTPClient = &http.Client{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNSPodProvider DNSPod服务商
|
// DNSPodProvider DNSPod服务商
|
||||||
// TODO 考虑支持线路ID
|
|
||||||
// TODO 支持自定义线路
|
|
||||||
type DNSPodProvider struct {
|
type DNSPodProvider struct {
|
||||||
BaseProvider
|
BaseProvider
|
||||||
|
|
||||||
@@ -42,19 +40,30 @@ type DNSPodProvider struct {
|
|||||||
region string
|
region string
|
||||||
apiId string
|
apiId string
|
||||||
apiToken string
|
apiToken string
|
||||||
|
|
||||||
|
tencentDNSProvider *TencentDNSProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth 认证
|
// Auth 认证
|
||||||
func (this *DNSPodProvider) Auth(params maps.Map) error {
|
func (this *DNSPodProvider) Auth(params maps.Map) error {
|
||||||
this.apiId = params.GetString("id")
|
// 兼容腾讯云API
|
||||||
this.apiToken = params.GetString("token")
|
var apiType = params.GetString("apiType")
|
||||||
this.region = params.GetString("region")
|
|
||||||
|
|
||||||
if len(this.apiId) == 0 {
|
switch apiType {
|
||||||
return errors.New("'id' should be not empty")
|
case "tencentDNS":
|
||||||
}
|
this.tencentDNSProvider = NewTencentDNSProvider()
|
||||||
if len(this.apiToken) == 0 {
|
return this.tencentDNSProvider.Auth(params)
|
||||||
return errors.New("'token' should not be empty")
|
default:
|
||||||
|
this.apiId = params.GetString("id")
|
||||||
|
this.apiToken = params.GetString("token")
|
||||||
|
this.region = params.GetString("region")
|
||||||
|
|
||||||
|
if len(this.apiId) == 0 {
|
||||||
|
return errors.New("'id' should be not empty")
|
||||||
|
}
|
||||||
|
if len(this.apiToken) == 0 {
|
||||||
|
return errors.New("'token' should not be empty")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -62,6 +71,10 @@ func (this *DNSPodProvider) Auth(params maps.Map) error {
|
|||||||
|
|
||||||
// GetDomains 获取所有域名列表
|
// GetDomains 获取所有域名列表
|
||||||
func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
|
func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.GetDomains()
|
||||||
|
}
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
var size = 3000
|
var size = 3000
|
||||||
|
|
||||||
@@ -92,6 +105,10 @@ func (this *DNSPodProvider) GetDomains() (domains []string, err error) {
|
|||||||
|
|
||||||
// GetRecords 获取域名列表
|
// GetRecords 获取域名列表
|
||||||
func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
|
func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.GetRecords(domain)
|
||||||
|
}
|
||||||
|
|
||||||
var offset = 0
|
var offset = 0
|
||||||
var size = 3000
|
var size = 3000
|
||||||
for {
|
for {
|
||||||
@@ -135,6 +152,10 @@ func (this *DNSPodProvider) GetRecords(domain string) (records []*dnstypes.Recor
|
|||||||
|
|
||||||
// GetRoutes 读取线路数据
|
// GetRoutes 读取线路数据
|
||||||
func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
|
func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.GetRoutes(domain)
|
||||||
|
}
|
||||||
|
|
||||||
var domainInfoResp = new(dnspod.DomainInfoResponse)
|
var domainInfoResp = new(dnspod.DomainInfoResponse)
|
||||||
err = this.doAPI("/Domain.Info", map[string]string{
|
err = this.doAPI("/Domain.Info", map[string]string{
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
@@ -217,6 +238,10 @@ func (this *DNSPodProvider) GetRoutes(domain string) (routes []*dnstypes.Route,
|
|||||||
|
|
||||||
// QueryRecord 查询单个记录
|
// QueryRecord 查询单个记录
|
||||||
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.QueryRecord(domain, name, recordType)
|
||||||
|
}
|
||||||
|
|
||||||
// 从缓存中读取
|
// 从缓存中读取
|
||||||
if this.ProviderId > 0 {
|
if this.ProviderId > 0 {
|
||||||
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
|
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
|
||||||
@@ -239,6 +264,10 @@ func (this *DNSPodProvider) QueryRecord(domain string, name string, recordType d
|
|||||||
|
|
||||||
// QueryRecords 查询多个记录
|
// QueryRecords 查询多个记录
|
||||||
func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.QueryRecords(domain, name, recordType)
|
||||||
|
}
|
||||||
|
|
||||||
// 从缓存中读取
|
// 从缓存中读取
|
||||||
if this.ProviderId > 0 {
|
if this.ProviderId > 0 {
|
||||||
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
|
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
|
||||||
@@ -262,6 +291,10 @@ func (this *DNSPodProvider) QueryRecords(domain string, name string, recordType
|
|||||||
|
|
||||||
// AddRecord 设置记录
|
// AddRecord 设置记录
|
||||||
func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.AddRecord(domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
if newRecord == nil {
|
if newRecord == nil {
|
||||||
return errors.New("invalid new record")
|
return errors.New("invalid new record")
|
||||||
}
|
}
|
||||||
@@ -298,6 +331,10 @@ func (this *DNSPodProvider) AddRecord(domain string, newRecord *dnstypes.Record)
|
|||||||
|
|
||||||
// UpdateRecord 修改记录
|
// UpdateRecord 修改记录
|
||||||
func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
|
func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.UpdateRecord(domain, record, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
if record == nil {
|
if record == nil {
|
||||||
return errors.New("invalid record")
|
return errors.New("invalid record")
|
||||||
}
|
}
|
||||||
@@ -339,6 +376,10 @@ func (this *DNSPodProvider) UpdateRecord(domain string, record *dnstypes.Record,
|
|||||||
|
|
||||||
// DeleteRecord 删除记录
|
// DeleteRecord 删除记录
|
||||||
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
func (this *DNSPodProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.DeleteRecord(domain, record)
|
||||||
|
}
|
||||||
|
|
||||||
if record == nil {
|
if record == nil {
|
||||||
return errors.New("invalid record to delete")
|
return errors.New("invalid record to delete")
|
||||||
}
|
}
|
||||||
@@ -412,6 +453,10 @@ func (this *DNSPodProvider) doAPI(path string, params map[string]string, respPtr
|
|||||||
|
|
||||||
// DefaultRoute 默认线路
|
// DefaultRoute 默认线路
|
||||||
func (this *DNSPodProvider) DefaultRoute() string {
|
func (this *DNSPodProvider) DefaultRoute() string {
|
||||||
|
if this.tencentDNSProvider != nil {
|
||||||
|
return this.tencentDNSProvider.DefaultRoute()
|
||||||
|
}
|
||||||
|
|
||||||
if this.isInternational() {
|
if this.isInternational() {
|
||||||
return "Default"
|
return "Default"
|
||||||
}
|
}
|
||||||
|
|||||||
409
internal/dnsclients/provider_tencent_dns.go
Normal file
409
internal/dnsclients/provider_tencent_dns.go
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package dnsclients
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/dnsclients/dnstypes"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||||
|
tencenterrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||||
|
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||||
|
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentDNSProvider 腾讯云DNS云解析
|
||||||
|
type TencentDNSProvider struct {
|
||||||
|
BaseProvider
|
||||||
|
|
||||||
|
ProviderId int64
|
||||||
|
|
||||||
|
client *dnspod.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTencentDNSProvider() *TencentDNSProvider {
|
||||||
|
return &TencentDNSProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth 认证
|
||||||
|
func (this *TencentDNSProvider) Auth(params maps.Map) error {
|
||||||
|
var accessKeyId = params.GetString("accessKeyId")
|
||||||
|
var accessKeySecret = params.GetString("accessKeySecret")
|
||||||
|
if len(accessKeyId) == 0 {
|
||||||
|
return errors.New("'accessKeyId' required")
|
||||||
|
}
|
||||||
|
if len(accessKeySecret) == 0 {
|
||||||
|
return errors.New("'accessKeySecret' required")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := dnspod.NewClient(common.NewCredential(accessKeyId, accessKeySecret), "", profile.NewClientProfile())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
this.client = client
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDomains 获取所有域名列表
|
||||||
|
func (this *TencentDNSProvider) GetDomains() (domains []string, err error) {
|
||||||
|
var offset int64 = 0
|
||||||
|
var limit int64 = 1000
|
||||||
|
for {
|
||||||
|
var req = dnspod.NewDescribeDomainListRequest()
|
||||||
|
req.Offset = this.int64Val(offset)
|
||||||
|
req.Limit = this.int64Val(limit)
|
||||||
|
resp, respErr := this.client.DescribeDomainList(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if this.isNotFoundErr(respErr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
var countDomains = len(resp.Response.DomainList)
|
||||||
|
if countDomains == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, domainObj := range resp.Response.DomainList {
|
||||||
|
domains = append(domains, *domainObj.Name)
|
||||||
|
}
|
||||||
|
offset += int64(countDomains)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecords 获取域名列表
|
||||||
|
func (this *TencentDNSProvider) GetRecords(domain string) (records []*dnstypes.Record, err error) {
|
||||||
|
var offset uint64 = 0
|
||||||
|
var limit uint64 = 1000
|
||||||
|
for {
|
||||||
|
var req = dnspod.NewDescribeRecordListRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.Offset = this.uint64Val(offset)
|
||||||
|
req.Limit = this.uint64Val(limit)
|
||||||
|
resp, respErr := this.client.DescribeRecordList(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if this.isNotFoundErr(respErr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
var countRecords = len(resp.Response.RecordList)
|
||||||
|
if countRecords == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, recordObj := range resp.Response.RecordList {
|
||||||
|
records = append(records, &dnstypes.Record{
|
||||||
|
Id: types.String(*recordObj.RecordId),
|
||||||
|
Name: *recordObj.Name,
|
||||||
|
Type: *recordObj.Type,
|
||||||
|
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
|
||||||
|
Route: *recordObj.LineId,
|
||||||
|
TTL: types.Int32(*recordObj.TTL),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
offset += uint64(countRecords)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.WriteDomainRecords(this.ProviderId, domain, records)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoutes 读取线路数据
|
||||||
|
func (this *TencentDNSProvider) GetRoutes(domain string) (routes []*dnstypes.Route, err error) {
|
||||||
|
// 等级信息
|
||||||
|
var domainGrade string
|
||||||
|
{
|
||||||
|
var req = dnspod.NewDescribeDomainRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
resp, respErr := this.client.DescribeDomain(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if this.isNotFoundErr(respErr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
if resp.Response.DomainInfo == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domainGrade = *resp.Response.DomainInfo.Grade
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等级允许的线路
|
||||||
|
{
|
||||||
|
var req = dnspod.NewDescribeRecordLineListRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.DomainGrade = this.stringVal(domainGrade)
|
||||||
|
resp, respErr := this.client.DescribeRecordLineList(req)
|
||||||
|
if respErr != nil {
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
for _, lineGroupObj := range resp.Response.LineGroupList {
|
||||||
|
routes = append(routes, &dnstypes.Route{
|
||||||
|
Name: "Group:" + *lineGroupObj.Name,
|
||||||
|
Code: *lineGroupObj.LineId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, lineObj := range resp.Response.LineList {
|
||||||
|
routes = append(routes, &dnstypes.Route{
|
||||||
|
Name: *lineObj.Name,
|
||||||
|
Code: *lineObj.LineId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRecord 查询单个记录
|
||||||
|
func (this *TencentDNSProvider) QueryRecord(domain string, name string, recordType dnstypes.RecordType) (*dnstypes.Record, error) {
|
||||||
|
// 从缓存中读取
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
record, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecord(this.ProviderId, domain, name, recordType)
|
||||||
|
if hasRecords { // 有效的搜索
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint64 = 0
|
||||||
|
var limit uint64 = 1000
|
||||||
|
var req = dnspod.NewDescribeRecordFilterListRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.Offset = this.uint64Val(offset)
|
||||||
|
req.Limit = this.uint64Val(limit)
|
||||||
|
req.SubDomain = this.stringVal(name)
|
||||||
|
req.RecordType = []*string{this.stringVal(recordType)}
|
||||||
|
resp, respErr := this.client.DescribeRecordFilterList(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if this.isNotFoundErr(respErr) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
var countRecords = len(resp.Response.RecordList)
|
||||||
|
if countRecords == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
for _, recordObj := range resp.Response.RecordList {
|
||||||
|
if *recordObj.Name == name && *recordObj.Type == recordType {
|
||||||
|
return &dnstypes.Record{
|
||||||
|
Id: types.String(*recordObj.RecordId),
|
||||||
|
Name: *recordObj.Name,
|
||||||
|
Type: *recordObj.Type,
|
||||||
|
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
|
||||||
|
Route: *recordObj.LineId,
|
||||||
|
TTL: types.Int32(*recordObj.TTL),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRecords 查询多个记录
|
||||||
|
func (this *TencentDNSProvider) QueryRecords(domain string, name string, recordType dnstypes.RecordType) ([]*dnstypes.Record, error) {
|
||||||
|
// 从缓存中读取
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
records, hasRecords, _ := sharedDomainRecordsCache.QueryDomainRecords(this.ProviderId, domain, name, recordType)
|
||||||
|
if hasRecords { // 有效的搜索
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint64 = 0
|
||||||
|
var limit uint64 = 1000
|
||||||
|
var records []*dnstypes.Record
|
||||||
|
for {
|
||||||
|
var req = dnspod.NewDescribeRecordFilterListRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.Offset = this.uint64Val(offset)
|
||||||
|
req.Limit = this.uint64Val(limit)
|
||||||
|
req.SubDomain = this.stringVal(name)
|
||||||
|
req.RecordType = []*string{this.stringVal(recordType)}
|
||||||
|
resp, respErr := this.client.DescribeRecordFilterList(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if this.isNotFoundErr(respErr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, respErr
|
||||||
|
}
|
||||||
|
var countRecords = len(resp.Response.RecordList)
|
||||||
|
if countRecords == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, recordObj := range resp.Response.RecordList {
|
||||||
|
records = append(records, &dnstypes.Record{
|
||||||
|
Id: types.String(*recordObj.RecordId),
|
||||||
|
Name: *recordObj.Name,
|
||||||
|
Type: *recordObj.Type,
|
||||||
|
Value: this.fixCNAME(*recordObj.Type, *recordObj.Value),
|
||||||
|
Route: *recordObj.LineId,
|
||||||
|
TTL: types.Int32(*recordObj.TTL),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
offset += uint64(countRecords)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecord 设置记录
|
||||||
|
func (this *TencentDNSProvider) AddRecord(domain string, newRecord *dnstypes.Record) error {
|
||||||
|
if newRecord == nil {
|
||||||
|
return errors.New("invalid new record")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在CHANGE记录后面加入点
|
||||||
|
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
|
||||||
|
newRecord.Value += "."
|
||||||
|
}
|
||||||
|
|
||||||
|
var ttl = newRecord.TTL
|
||||||
|
if ttl <= 0 {
|
||||||
|
ttl = 600
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = dnspod.NewCreateRecordRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.SubDomain = this.stringVal(newRecord.Name)
|
||||||
|
req.RecordType = this.stringVal(newRecord.Type)
|
||||||
|
req.TTL = this.uint64Val(uint64(ttl))
|
||||||
|
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项,但以RecordLineId优先
|
||||||
|
req.RecordLineId = this.stringVal(newRecord.Route)
|
||||||
|
req.Value = this.stringVal(newRecord.Value)
|
||||||
|
resp, respErr := this.client.CreateRecord(req)
|
||||||
|
if respErr != nil {
|
||||||
|
return respErr
|
||||||
|
}
|
||||||
|
newRecord.Id = types.String(*resp.Response.RecordId)
|
||||||
|
|
||||||
|
// 加入缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.AddDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRecord 修改记录
|
||||||
|
func (this *TencentDNSProvider) UpdateRecord(domain string, record *dnstypes.Record, newRecord *dnstypes.Record) error {
|
||||||
|
if record == nil {
|
||||||
|
return errors.New("invalid record")
|
||||||
|
}
|
||||||
|
if newRecord == nil {
|
||||||
|
return errors.New("invalid new record")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在CHANGE记录后面加入点
|
||||||
|
if newRecord.Type == dnstypes.RecordTypeCNAME && !strings.HasSuffix(newRecord.Value, ".") {
|
||||||
|
newRecord.Value += "."
|
||||||
|
}
|
||||||
|
|
||||||
|
var newRoute = newRecord.Route
|
||||||
|
if len(newRoute) == 0 {
|
||||||
|
newRoute = this.DefaultRoute()
|
||||||
|
}
|
||||||
|
|
||||||
|
var ttl = newRecord.TTL
|
||||||
|
if ttl <= 0 {
|
||||||
|
ttl = 600
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = dnspod.NewModifyRecordRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.RecordId = this.uint64Val(types.Uint64(record.Id))
|
||||||
|
req.SubDomain = this.stringVal(newRecord.Name)
|
||||||
|
req.RecordType = this.stringVal(newRecord.Type)
|
||||||
|
req.TTL = this.uint64Val(uint64(ttl))
|
||||||
|
req.RecordLine = this.stringVal(this.DefaultRouteName()) // 默认必填项,但以RecordLineId优先
|
||||||
|
req.RecordLineId = this.stringVal(newRecord.Route)
|
||||||
|
req.Value = this.stringVal(newRecord.Value)
|
||||||
|
_, respErr := this.client.ModifyRecord(req)
|
||||||
|
if respErr != nil {
|
||||||
|
return respErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.UpdateDomainRecord(this.ProviderId, domain, newRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRecord 删除记录
|
||||||
|
func (this *TencentDNSProvider) DeleteRecord(domain string, record *dnstypes.Record) error {
|
||||||
|
if record == nil {
|
||||||
|
return errors.New("invalid record to delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = dnspod.NewDeleteRecordRequest()
|
||||||
|
req.Domain = this.stringVal(domain)
|
||||||
|
req.RecordId = this.uint64Val(types.Uint64(record.Id))
|
||||||
|
_, respErr := this.client.DeleteRecord(req)
|
||||||
|
if respErr != nil {
|
||||||
|
if len(record.Id) > 0 && this.isRecordInvalidErr(respErr) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return respErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除缓存
|
||||||
|
if this.ProviderId > 0 {
|
||||||
|
sharedDomainRecordsCache.DeleteDomainRecord(this.ProviderId, domain, record.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultRoute 默认线路
|
||||||
|
func (this *TencentDNSProvider) DefaultRoute() string {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) DefaultRouteName() string {
|
||||||
|
return "默认"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) fixCNAME(recordType string, recordValue string) string {
|
||||||
|
// 修正Record
|
||||||
|
if strings.ToUpper(recordType) == dnstypes.RecordTypeCNAME && !strings.HasSuffix(recordValue, ".") {
|
||||||
|
recordValue += "."
|
||||||
|
}
|
||||||
|
return recordValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) int64Val(v int64) *int64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) uint64Val(v uint64) *uint64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) stringVal(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) isNotFoundErr(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var sdkErr *tencenterrors.TencentCloudSDKError
|
||||||
|
return errors.As(err, &sdkErr) && strings.HasPrefix(sdkErr.Code, "ResourceNotFound.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TencentDNSProvider) isRecordInvalidErr(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var sdkErr *tencenterrors.TencentCloudSDKError
|
||||||
|
return errors.As(err, &sdkErr) && sdkErr.Code == "InvalidParameter.RecordIdInvalid"
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ func FindAllProviderTypes() []maps.Map {
|
|||||||
"description": "阿里云提供的DNS服务。",
|
"description": "阿里云提供的DNS服务。",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "DNSPod",
|
"name": "腾讯云DNSPod",
|
||||||
"code": ProviderTypeDNSPod,
|
"code": ProviderTypeDNSPod,
|
||||||
"description": "DNSPod提供的DNS服务。",
|
"description": "DNSPod提供的DNS服务。",
|
||||||
},
|
},
|
||||||
@@ -52,7 +52,7 @@ func FindAllProviderTypes() []maps.Map {
|
|||||||
typeMaps = append(typeMaps, maps.Map{
|
typeMaps = append(typeMaps, maps.Map{
|
||||||
"name": "自定义HTTP DNS",
|
"name": "自定义HTTP DNS",
|
||||||
"code": ProviderTypeCustomHTTP,
|
"code": ProviderTypeCustomHTTP,
|
||||||
"description": "通过自定义的HTTP接口提供DNS服务。",
|
"description": "通过自定义的HTTP接口提供DNS服务,具体使用方法请参考官网文档:https://goedge.cn/docs/DNS/CustomHTTP.md ",
|
||||||
})
|
})
|
||||||
return typeMaps
|
return typeMaps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import (
|
|||||||
// FindProvider 查找服务商实例
|
// FindProvider 查找服务商实例
|
||||||
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
|
func FindProvider(providerType ProviderType, providerId int64) ProviderInterface {
|
||||||
switch providerType {
|
switch providerType {
|
||||||
|
case ProviderTypeTencentDNS:
|
||||||
|
return &TencentDNSProvider{
|
||||||
|
ProviderId: providerId,
|
||||||
|
}
|
||||||
case ProviderTypeDNSPod:
|
case ProviderTypeDNSPod:
|
||||||
return &DNSPodProvider{
|
return &DNSPodProvider{
|
||||||
ProviderId: providerId,
|
ProviderId: providerId,
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ func (this *HTTPAccessLogService) CreateHTTPAccessLogs(ctx context.Context, req
|
|||||||
|
|
||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
err = models.SharedHTTPAccessLogDAO.CreateHTTPAccessLogs(tx, req.HttpAccessLogs)
|
if this.canWriteAccessLogsToDB() {
|
||||||
if err != nil {
|
err = models.SharedHTTPAccessLogDAO.CreateHTTPAccessLogs(tx, req.HttpAccessLogs)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = this.writeAccessLogsToPolicy(req.HttpAccessLogs)
|
err = this.writeAccessLogsToPolicy(req.HttpAccessLogs)
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ package services
|
|||||||
|
|
||||||
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
import "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
|
||||||
|
func (this *HTTPAccessLogService) canWriteAccessLogsToDB() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (this *HTTPAccessLogService) writeAccessLogsToPolicy(pbAccessLogs []*pb.HTTPAccessLog) error {
|
func (this *HTTPAccessLogService) writeAccessLogsToPolicy(pbAccessLogs []*pb.HTTPAccessLog) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
)
|
)
|
||||||
@@ -30,7 +32,7 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
|
|||||||
const maxBodyLength = 32 * 1024
|
const maxBodyLength = 32 * 1024
|
||||||
|
|
||||||
switch req.BodyType {
|
switch req.BodyType {
|
||||||
case shared.BodyTypeURL:
|
case serverconfigs.HTTPPageBodyTypeURL:
|
||||||
if len(req.Url) > maxURLLength {
|
if len(req.Url) > maxURLLength {
|
||||||
return nil, errors.New("'url' too long")
|
return nil, errors.New("'url' too long")
|
||||||
}
|
}
|
||||||
@@ -41,7 +43,18 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
|
|||||||
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
req.Body = ""
|
req.Body = ""
|
||||||
}
|
}
|
||||||
case shared.BodyTypeHTML:
|
case serverconfigs.HTTPPageBodyTypeRedirectURL:
|
||||||
|
if len(req.Url) > maxURLLength {
|
||||||
|
return nil, errors.New("'url' too long")
|
||||||
|
}
|
||||||
|
if !regexputils.HTTPProtocol.MatchString(req.Url) {
|
||||||
|
return nil, errors.New("invalid 'url' format")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
|
req.Body = ""
|
||||||
|
}
|
||||||
|
case serverconfigs.HTTPPageBodyTypeHTML:
|
||||||
if len(req.Body) > maxBodyLength {
|
if len(req.Body) > maxBodyLength {
|
||||||
return nil, errors.New("'body' too long")
|
return nil, errors.New("'body' too long")
|
||||||
}
|
}
|
||||||
@@ -53,7 +66,35 @@ func (this *HTTPPageService) CreateHTTPPage(ctx context.Context, req *pb.CreateH
|
|||||||
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
|
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
|
var exceptURLPatterns = []*shared.URLPattern{}
|
||||||
|
if len(req.ExceptURLPatternsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(req.ExceptURLPatternsJSON, &exceptURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pattern := range exceptURLPatterns {
|
||||||
|
err = pattern.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var onlyURLPatterns = []*shared.URLPattern{}
|
||||||
|
if len(req.OnlyURLPatternsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(req.OnlyURLPatternsJSON, &onlyURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pattern := range onlyURLPatterns {
|
||||||
|
err = pattern.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageId, err := models.SharedHTTPPageDAO.CreatePage(tx, userId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus), exceptURLPatterns, onlyURLPatterns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -82,7 +123,7 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
|
|||||||
const maxBodyLength = 32 * 1024
|
const maxBodyLength = 32 * 1024
|
||||||
|
|
||||||
switch req.BodyType {
|
switch req.BodyType {
|
||||||
case shared.BodyTypeURL:
|
case serverconfigs.HTTPPageBodyTypeURL:
|
||||||
if len(req.Url) > maxURLLength {
|
if len(req.Url) > maxURLLength {
|
||||||
return nil, errors.New("'url' too long")
|
return nil, errors.New("'url' too long")
|
||||||
}
|
}
|
||||||
@@ -93,7 +134,18 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
|
|||||||
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
req.Body = ""
|
req.Body = ""
|
||||||
}
|
}
|
||||||
case shared.BodyTypeHTML:
|
case serverconfigs.HTTPPageBodyTypeRedirectURL:
|
||||||
|
if len(req.Url) > maxURLLength {
|
||||||
|
return nil, errors.New("'url' too long")
|
||||||
|
}
|
||||||
|
if !regexputils.HTTPProtocol.MatchString(req.Url) {
|
||||||
|
return nil, errors.New("invalid 'url' format")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
|
req.Body = ""
|
||||||
|
}
|
||||||
|
case serverconfigs.HTTPPageBodyTypeHTML:
|
||||||
if len(req.Body) > maxBodyLength {
|
if len(req.Body) > maxBodyLength {
|
||||||
return nil, errors.New("'body' too long")
|
return nil, errors.New("'body' too long")
|
||||||
}
|
}
|
||||||
@@ -105,7 +157,35 @@ func (this *HTTPPageService) UpdateHTTPPage(ctx context.Context, req *pb.UpdateH
|
|||||||
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
|
return nil, errors.New("invalid 'bodyType': " + req.BodyType)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus))
|
var exceptURLPatterns = []*shared.URLPattern{}
|
||||||
|
if len(req.ExceptURLPatternsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(req.ExceptURLPatternsJSON, &exceptURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pattern := range exceptURLPatterns {
|
||||||
|
err = pattern.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var onlyURLPatterns = []*shared.URLPattern{}
|
||||||
|
if len(req.OnlyURLPatternsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(req.OnlyURLPatternsJSON, &onlyURLPatterns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pattern := range onlyURLPatterns {
|
||||||
|
err = pattern.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("validate url pattern '"+pattern.Pattern+"' failed: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = models.SharedHTTPPageDAO.UpdatePage(tx, req.HttpPageId, req.StatusList, req.BodyType, req.Url, req.Body, types.Int(req.NewStatus), exceptURLPatterns, onlyURLPatterns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
|
||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -365,7 +364,7 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch shutdownConfig.BodyType {
|
switch shutdownConfig.BodyType {
|
||||||
case shared.BodyTypeURL:
|
case serverconfigs.HTTPPageBodyTypeURL:
|
||||||
if len(shutdownConfig.URL) > maxURLLength {
|
if len(shutdownConfig.URL) > maxURLLength {
|
||||||
return nil, errors.New("'url' too long")
|
return nil, errors.New("'url' too long")
|
||||||
}
|
}
|
||||||
@@ -376,7 +375,18 @@ func (this *HTTPWebService) UpdateHTTPWebShutdown(ctx context.Context, req *pb.U
|
|||||||
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
|
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
shutdownConfig.Body = ""
|
shutdownConfig.Body = ""
|
||||||
}
|
}
|
||||||
case shared.BodyTypeHTML:
|
case serverconfigs.HTTPPageBodyTypeRedirectURL:
|
||||||
|
if len(shutdownConfig.URL) > maxURLLength {
|
||||||
|
return nil, errors.New("'url' too long")
|
||||||
|
}
|
||||||
|
if shutdownConfig.IsOn /** validate when it's on **/ && !regexputils.HTTPProtocol.MatchString(shutdownConfig.URL) {
|
||||||
|
return nil, errors.New("invalid 'url' format")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(shutdownConfig.Body) > maxBodyLength { // we keep short body for user experience
|
||||||
|
shutdownConfig.Body = ""
|
||||||
|
}
|
||||||
|
case serverconfigs.HTTPPageBodyTypeHTML:
|
||||||
if len(shutdownConfig.Body) > maxBodyLength {
|
if len(shutdownConfig.Body) > maxBodyLength {
|
||||||
return nil, errors.New("'body' too long")
|
return nil, errors.New("'body' too long")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2066,7 +2066,7 @@ func (this *NodeService) FindEnabledNodeConfigInfo(ctx context.Context, req *pb.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// thresholds
|
// thresholds
|
||||||
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, 0, req.NodeId)
|
countThresholds, err := models.SharedNodeThresholdDAO.CountAllEnabledThresholds(tx, nodeconfigs.NodeRoleNode, int64(node.ClusterId), req.NodeId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1197,6 +1197,9 @@ func (this *NodeClusterService) FindEnabledNodeClusterConfigInfo(ctx context.Con
|
|||||||
result.Http3IsOn = http3Policy.IsOn
|
result.Http3IsOn = http3Policy.IsOn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 网络安全策略
|
||||||
|
result.HasNetworkSecurityPolicy = cluster.HasNetworkSecurityPolicy()
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,13 @@ import (
|
|||||||
func (this *NodeClusterService) FindNodeClusterHTTP3Policy(ctx context.Context, req *pb.FindNodeClusterHTTP3PolicyRequest) (*pb.FindNodeClusterHTTP3PolicyResponse, error) {
|
func (this *NodeClusterService) FindNodeClusterHTTP3Policy(ctx context.Context, req *pb.FindNodeClusterHTTP3PolicyRequest) (*pb.FindNodeClusterHTTP3PolicyResponse, error) {
|
||||||
return nil, this.NotImplementedYet()
|
return nil, this.NotImplementedYet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNodeClusterNetworkSecurityPolicy 获取集群的网络安全策略
|
||||||
|
func (this *NodeClusterService) FindNodeClusterNetworkSecurityPolicy(ctx context.Context, req *pb.FindNodeClusterNetworkSecurityPolicyRequest) (*pb.FindNodeClusterNetworkSecurityPolicyResponse, error) {
|
||||||
|
return nil, this.NotImplementedYet()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNodeClusterNetworkSecurityPolicy 修改集群的网络安全策略
|
||||||
|
func (this *NodeClusterService) UpdateNodeClusterNetworkSecurityPolicy(ctx context.Context, req *pb.UpdateNodeClusterNetworkSecurityPolicyRequest) (*pb.RPCSuccess, error) {
|
||||||
|
return nil, this.NotImplementedYet()
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,3 +52,8 @@ func (this *NodeService) CopyNodeActionsToNodeCluster(ctx context.Context, req *
|
|||||||
func (this *NodeService) FindNodeTOAConfig(ctx context.Context, req *pb.FindNodeTOAConfigRequest) (*pb.FindNodeTOAConfigResponse, error) {
|
func (this *NodeService) FindNodeTOAConfig(ctx context.Context, req *pb.FindNodeTOAConfigRequest) (*pb.FindNodeTOAConfigResponse, error) {
|
||||||
return nil, this.NotImplementedYet()
|
return nil, this.NotImplementedYet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindNodeNetworkSecurityPolicy 查找节点的网络安全策略
|
||||||
|
func (this *NodeService) FindNodeNetworkSecurityPolicy(ctx context.Context, req *pb.FindNodeNetworkSecurityPolicyRequest) (*pb.FindNodeNetworkSecurityPolicyResponse, error) {
|
||||||
|
return nil, this.NotImplementedYet()
|
||||||
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func (this *ReverseProxyService) UpdateReverseProxy(ctx context.Context, req *pb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects, req.Retry50X)
|
err = models.SharedReverseProxyDAO.UpdateReverseProxy(tx, req.ReverseProxyId, types.Int8(req.RequestHostType), req.RequestHost, req.RequestHostExcludingPort, req.RequestURI, req.StripPrefix, req.AutoFlush, req.AddHeaders, connTimeout, readTimeout, idleTimeout, req.MaxConns, req.MaxIdleConns, req.ProxyProtocolJSON, req.FollowRedirects, req.Retry50X, req.Retry40X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -414,6 +414,17 @@ func (this *ServerStatBoardService) ComposeServerStatNodeBoard(ctx context.Conte
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkPacketsValues, err := models.SharedNodeValueDAO.ListValues(tx, "node", req.NodeId, nodeconfigs.NodeValueItemNetworkPackets, nodeconfigs.NodeValueRangeMinute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, v := range networkPacketsValues {
|
||||||
|
result.NetworkPacketsValues = append(result.NetworkPacketsValues, &pb.NodeValue{
|
||||||
|
ValueJSON: v.Value,
|
||||||
|
CreatedAt: int64(v.CreatedAt),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
cacheDirValues, err := models.SharedNodeValueDAO.ListValues(tx, "node", req.NodeId, nodeconfigs.NodeValueItemCacheDir, nodeconfigs.NodeValueRangeMinute)
|
cacheDirValues, err := models.SharedNodeValueDAO.ListValues(tx, "node", req.NodeId, nodeconfigs.NodeValueItemCacheDir, nodeconfigs.NodeValueRangeMinute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -241,28 +241,31 @@ func (this *UserService) FindEnabledUser(ctx context.Context, req *pb.FindEnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.FindEnabledUserResponse{User: &pb.User{
|
return &pb.FindEnabledUserResponse{
|
||||||
Id: int64(user.Id),
|
User: &pb.User{
|
||||||
Username: user.Username,
|
Id: int64(user.Id),
|
||||||
Fullname: user.Fullname,
|
Username: user.Username,
|
||||||
Mobile: user.Mobile,
|
Fullname: user.Fullname,
|
||||||
Tel: user.Tel,
|
Mobile: user.Mobile,
|
||||||
Email: user.Email,
|
Tel: user.Tel,
|
||||||
VerifiedEmail: user.VerifiedEmail,
|
Email: user.Email,
|
||||||
Remark: user.Remark,
|
VerifiedEmail: user.VerifiedEmail,
|
||||||
IsOn: user.IsOn,
|
VerifiedMobile: user.VerifiedMobile,
|
||||||
CreatedAt: int64(user.CreatedAt),
|
Remark: user.Remark,
|
||||||
RegisteredIP: user.RegisteredIP,
|
IsOn: user.IsOn,
|
||||||
IsVerified: user.IsVerified,
|
CreatedAt: int64(user.CreatedAt),
|
||||||
IsRejected: user.IsRejected,
|
RegisteredIP: user.RegisteredIP,
|
||||||
RejectReason: user.RejectReason,
|
IsVerified: user.IsVerified,
|
||||||
NodeCluster: pbCluster,
|
IsRejected: user.IsRejected,
|
||||||
IsIndividualIdentified: isIndividualIdentified,
|
RejectReason: user.RejectReason,
|
||||||
IsEnterpriseIdentified: isEnterpriseIdentified,
|
NodeCluster: pbCluster,
|
||||||
BandwidthAlgo: user.BandwidthAlgo,
|
IsIndividualIdentified: isIndividualIdentified,
|
||||||
OtpLogin: pbOtpAuth,
|
IsEnterpriseIdentified: isEnterpriseIdentified,
|
||||||
Lang: user.Lang,
|
BandwidthAlgo: user.BandwidthAlgo,
|
||||||
}}, nil
|
OtpLogin: pbOtpAuth,
|
||||||
|
Lang: user.Lang,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckUserUsername 检查用户名是否存在
|
// CheckUserUsername 检查用户名是否存在
|
||||||
@@ -312,11 +315,14 @@ func (this *UserService) LoginUser(ctx context.Context, req *pb.LoginUserRequest
|
|||||||
var tx = this.NullTx()
|
var tx = this.NullTx()
|
||||||
|
|
||||||
// 邮箱登录
|
// 邮箱登录
|
||||||
|
var registerConfig *userconfigs.UserRegisterConfig
|
||||||
if strings.Contains(req.Username, "@") {
|
if strings.Contains(req.Username, "@") {
|
||||||
// 是否允许
|
// 是否允许
|
||||||
registerConfig, err := models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
if registerConfig == nil {
|
||||||
if err != nil {
|
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if registerConfig != nil && registerConfig.EmailVerification.CanLogin {
|
if registerConfig != nil && registerConfig.EmailVerification.CanLogin {
|
||||||
userId, err := models.SharedUserDAO.CheckUserEmailPassword(tx, req.Username, req.Password)
|
userId, err := models.SharedUserDAO.CheckUserEmailPassword(tx, req.Username, req.Password)
|
||||||
@@ -332,6 +338,29 @@ func (this *UserService) LoginUser(ctx context.Context, req *pb.LoginUserRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 手机号登录
|
||||||
|
if utils.IsValidMobile(req.Username) {
|
||||||
|
// 是否允许
|
||||||
|
if registerConfig == nil {
|
||||||
|
registerConfig, err = models.SharedSysSettingDAO.ReadUserRegisterConfig(tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if registerConfig != nil && registerConfig.MobileVerification.CanLogin {
|
||||||
|
userId, err := models.SharedUserDAO.CheckUserMobilePassword(tx, req.Username, req.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userId > 0 {
|
||||||
|
return &pb.LoginUserResponse{
|
||||||
|
UserId: userId,
|
||||||
|
IsOk: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 用户名登录
|
// 用户名登录
|
||||||
userId, err := models.SharedUserDAO.CheckUserPassword(tx, req.Username, req.Password)
|
userId, err := models.SharedUserDAO.CheckUserPassword(tx, req.Username, req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -840,6 +869,28 @@ func (this *UserService) CheckUserEmail(ctx context.Context, req *pb.CheckUserEm
|
|||||||
return &pb.CheckUserEmailResponse{Exists: false}, nil
|
return &pb.CheckUserEmailResponse{Exists: false}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserMobile 检查手机号码是否被使用
|
||||||
|
func (this *UserService) CheckUserMobile(ctx context.Context, req *pb.CheckUserMobileRequest) (*pb.CheckUserMobileResponse, error) {
|
||||||
|
userId, err := this.ValidateUserNode(ctx, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.Mobile) == 0 {
|
||||||
|
return nil, errors.New("'mobile' required")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = this.NullTx()
|
||||||
|
mobileOwnerUserId, err := models.SharedUserDAO.FindUserIdWithVerifiedMobile(tx, req.Mobile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if mobileOwnerUserId > 0 && userId != mobileOwnerUserId {
|
||||||
|
return &pb.CheckUserMobileResponse{Exists: true}, nil
|
||||||
|
}
|
||||||
|
return &pb.CheckUserMobileResponse{Exists: false}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindUserVerifiedEmailWithUsername 根据用户名查询用户绑定的邮箱
|
// FindUserVerifiedEmailWithUsername 根据用户名查询用户绑定的邮箱
|
||||||
func (this *UserService) FindUserVerifiedEmailWithUsername(ctx context.Context, req *pb.FindUserVerifiedEmailWithUsernameRequest) (*pb.FindUserVerifiedEmailWithUsernameResponse, error) {
|
func (this *UserService) FindUserVerifiedEmailWithUsername(ctx context.Context, req *pb.FindUserVerifiedEmailWithUsernameRequest) (*pb.FindUserVerifiedEmailWithUsernameResponse, error) {
|
||||||
_, err := this.ValidateUserNode(ctx, false)
|
_, err := this.ValidateUserNode(ctx, false)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -127,8 +129,32 @@ func (this *HealthCheckClusterTask) Loop() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var message = "有" + numberutils.FormatInt(len(failedResults)) + "个节点IP在健康检查中出现问题"
|
var subject = "有" + numberutils.FormatInt(len(failedResults)) + "个节点IP在健康检查中出现问题"
|
||||||
err = models.NewMessageDAO().CreateClusterMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, models.MessageTypeHealthCheckFailed, models.MessageLevelError, message, message, failedResultsJSON)
|
var message = "有" + numberutils.FormatInt(len(failedResults)) + "个节点IP在健康检查中出现问题:"
|
||||||
|
var failedDescriptions = []string{}
|
||||||
|
var failedIndex int
|
||||||
|
for _, result := range results {
|
||||||
|
if result.IsOk || result.Node == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
failedIndex++
|
||||||
|
failedDescriptions = append(failedDescriptions, "节点"+types.String(failedIndex)+":"+result.Node.Name+",IP:"+result.NodeAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxNodeDescriptions = 10
|
||||||
|
var isOverMax = false
|
||||||
|
if len(failedDescriptions) > maxNodeDescriptions {
|
||||||
|
failedDescriptions = failedDescriptions[:maxNodeDescriptions]
|
||||||
|
isOverMax = true
|
||||||
|
}
|
||||||
|
message += strings.Join(failedDescriptions, ";")
|
||||||
|
if isOverMax {
|
||||||
|
message += " ..."
|
||||||
|
} else {
|
||||||
|
message += "。"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = models.NewMessageDAO().CreateClusterMessage(nil, nodeconfigs.NodeRoleNode, this.clusterId, models.MessageTypeHealthCheckFailed, models.MessageLevelError, subject, subject, message, failedResultsJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
12
internal/utils/mobile.go
Normal file
12
internal/utils/mobile.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
var mobileRegex = regexp.MustCompile(`^1\d{10}$`)
|
||||||
|
|
||||||
|
// IsValidMobile validate mobile number
|
||||||
|
func IsValidMobile(mobile string) bool {
|
||||||
|
return mobileRegex.MatchString(mobile)
|
||||||
|
}
|
||||||
17
internal/utils/mobile_test.go
Normal file
17
internal/utils/mobile_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsValidMobile(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
a.IsFalse(utils.IsValidMobile("138"))
|
||||||
|
a.IsFalse(utils.IsValidMobile("1382222"))
|
||||||
|
a.IsFalse(utils.IsValidMobile("1381234567890"))
|
||||||
|
a.IsTrue(utils.IsValidMobile("13812345678"))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user