This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
func DefaultClockConfig() *ClockConfig {
return &ClockConfig{
AutoSync: true,
Server: "",
CheckChrony: true,
}
}
// ClockConfig 时钟相关配置
type ClockConfig struct {
AutoSync bool `yaml:"autoSync" json:"autoSync"` // 自动尝试同步时钟
Server string `yaml:"server" json:"server"` // 时钟同步服务器
CheckChrony bool `yaml:"checkChrony" json:"checkChrony"` // 检查 chronyd 是否在运行
}
func (this *ClockConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,11 @@
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/reporterconfigs"
// Connectivity 连通性状态
type Connectivity struct {
CostMs float64 `json:"costMs"` // 平均耗时
Level reporterconfigs.ReportLevel `json:"level"` // 级别
Percent float64 `json:"percent"` // 连通的百分比是一个0到100之间的小数
UpdatedAt int64 `json:"updatedAt"` // 更新时间
}

View File

@@ -0,0 +1,37 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
import "github.com/iwind/TeaGo/maps"
// 一组系统默认值
// 修改单个IP相关限制值时要考虑到NAT中每个IP会代表很多个主机并非1对1的关系
const (
DefaultMaxThreads = 20000 // 单节点最大线程数
DefaultMaxThreadsMin = 1000 // 单节点最大线程数最小值
DefaultMaxThreadsMax = 100_000 // 单节点最大线程数最大值
DefaultTCPMaxConnections = 100_000 // 单节点TCP最大连接数
DefaultTCPMaxConnectionsPerIP = 1000 // 单IP最大连接数
DefaultTCPMinConnectionsPerIP = 5 // 单IP最小连接数
DefaultTCPNewConnectionsMinutelyRate = 500 // 单IP连接速率限制按分钟
DefaultTCPNewConnectionsMinMinutelyRate = 3 // 单IP最小连接速率
DefaultTCPNewConnectionsSecondlyRate = 300 // 单IP连接速率限制按秒
DefaultTCPNewConnectionsMinSecondlyRate = 3 // 单IP最小连接速率
DefaultTCPLinger = 5 // 单节点TCP Linger值
DefaultTLSHandshakeTimeout = 3 // TLS握手超时时间
)
var DefaultConfigs = maps.Map{
"tcpMaxConnections": DefaultTCPMaxConnections,
"tcpMaxConnectionsPerIP": DefaultTCPMaxConnectionsPerIP,
"tcpMinConnectionsPerIP": DefaultTCPMinConnectionsPerIP,
"tcpNewConnectionsMinutelyRate": DefaultTCPNewConnectionsMinutelyRate,
"tcpNewConnectionsMinMinutelyRate": DefaultTCPNewConnectionsMinMinutelyRate,
"tcpNewConnectionsSecondlyRate": DefaultTCPNewConnectionsSecondlyRate,
"tcpNewConnectionsMinSecondlyRate": DefaultTCPNewConnectionsMinSecondlyRate,
}

View File

@@ -0,0 +1,25 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
type DNSResolverType = string
const (
DNSResolverTypeDefault = "default"
DNSResolverTypeGoNative = "goNative"
DNSResolverTypeCGO = "cgo"
)
func DefaultDNSResolverConfig() *DNSResolverConfig {
return &DNSResolverConfig{
Type: DNSResolverTypeDefault,
}
}
type DNSResolverConfig struct {
Type string `yaml:"type" json:"type"` // 使用Go语言内置的DNS解析器
}
func (this *DNSResolverConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,25 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
const DefaultHTTP3Port = 443
type HTTP3Policy struct {
IsOn bool `yaml:"isOn" json:"isOn"`
Port int `yaml:"port" json:"port"`
SupportMobileBrowsers bool `yaml:"supportMobileBrowsers" json:"supportMobileBrowsers"` // enable http/3 on common mobile browsers
}
func NewHTTP3Policy() *HTTP3Policy {
return &HTTP3Policy{
Port: DefaultHTTP3Port,
SupportMobileBrowsers: false,
}
}
func (this *HTTP3Policy) Init() error {
if this.Port <= 0 {
this.Port = DefaultHTTP3Port
}
return nil
}

View File

@@ -0,0 +1,22 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
// HTTPCCPolicy CC策略
type HTTPCCPolicy struct {
IsOn bool `json:"isOn" yaml:"isOn"`
Thresholds []*serverconfigs.HTTPCCThreshold `json:"thresholds" yaml:"thresholds"` // 阈值
}
func NewHTTPCCPolicy() *HTTPCCPolicy {
return &HTTPCCPolicy{
IsOn: true,
}
}
func (this *HTTPCCPolicy) Init() error {
return nil
}

View File

@@ -0,0 +1,56 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package nodeconfigs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
)
const (
HTTPCCPolicyMaxConnectionsPerIP = 30
HTTPCCPolicyRedirectsCheckingValidatePath = "/GE/CC/VALIDATOR"
HTTPCCPolicyRedirectsCheckingDurationSeconds = 120
HTTPCCPolicyRedirectsCheckingMaxRedirects = 30
HTTPCCPolicyRedirectsCheckingBlockSeconds = 3600
)
// HTTPCCPolicy CC策略
type HTTPCCPolicy struct {
IsOn bool `json:"isOn" yaml:"isOn"`
Thresholds []*serverconfigs.HTTPCCThreshold `json:"thresholds" yaml:"thresholds"` // 阈值
MaxConnectionsPerIP int `json:"maxConnectionsPerIP" yaml:"maxConnectionsPerIP"` // 单IP最大并发连接数
// 跳转校验
RedirectsChecking struct {
ValidatePath string `json:"validatePath" yaml:"validatePath"` // 校验路径
DurationSeconds int `json:"durationSeconds" yaml:"durationSeconds"` // 无效跳转检测周期
MaxRedirects int `json:"maxRedirects" yaml:"maxRedirects"` // 最大跳转次数
BlockSeconds int `json:"blockSeconds" yaml:"blockSeconds"` // 拦截时间
} `json:"redirectsChecking" yaml:"redirectsChecking"`
// 防火墙策略
Firewall struct {
Scope firewallconfigs.FirewallScope `json:"scope" yaml:"scope"`
} `json:"firewall" yaml:"firewall"`
}
func NewHTTPCCPolicy() *HTTPCCPolicy {
var policy = &HTTPCCPolicy{
IsOn: true,
}
policy.Firewall.Scope = firewallconfigs.FirewallScopeGlobal
return policy
}
func (this *HTTPCCPolicy) Init() error {
return nil
}
func (this *HTTPCCPolicy) FirewallScope() firewallconfigs.FirewallScope {
if len(this.Firewall.Scope) == 0 {
return firewallconfigs.FirewallScopeGlobal
}
return this.Firewall.Scope
}

View File

@@ -0,0 +1,28 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
// HTTPPagesPolicy 全局的HTTP自定义页面设置
type HTTPPagesPolicy struct {
IsOn bool `json:"isOn" yaml:"isOn"` // 是否启用
Pages []*serverconfigs.HTTPPageConfig `json:"pages" yaml:"pages"` // 自定义页面
}
func NewHTTPPagesPolicy() *HTTPPagesPolicy {
return &HTTPPagesPolicy{}
}
func (this *HTTPPagesPolicy) Init() error {
if len(this.Pages) > 0 {
for _, page := range this.Pages {
err := page.Init()
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,51 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
func init() {
_ = DefaultWebPImagePolicy.Init()
}
var DefaultWebPImagePolicy = NewWebPImagePolicy()
func NewWebPImagePolicy() *WebPImagePolicy {
return &WebPImagePolicy{
IsOn: true,
RequireCache: true,
MinLength: shared.NewSizeCapacity(0, shared.SizeCapacityUnitKB),
MaxLength: shared.NewSizeCapacity(128, shared.SizeCapacityUnitMB),
}
}
// WebPImagePolicy WebP策略
type WebPImagePolicy struct {
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
RequireCache bool `yaml:"requireCache" json:"requireCache"` // 需要在缓存条件下进行
MinLength *shared.SizeCapacity `yaml:"minLength" json:"minLength"` // 最小压缩对象比如4m, 24k
MaxLength *shared.SizeCapacity `yaml:"maxLength" json:"maxLength"` // 最大压缩对象
Quality int `yaml:"quality" json:"quality"` // 生成的图片质量0-100
minLength int64
maxLength int64
}
func (this *WebPImagePolicy) Init() error {
if this.MinLength != nil {
this.minLength = this.MinLength.Bytes()
}
if this.MaxLength != nil {
this.maxLength = this.MaxLength.Bytes()
}
return nil
}
func (this *WebPImagePolicy) MinLengthBytes() int64 {
return this.minLength
}
func (this *WebPImagePolicy) MaxLengthBytes() int64 {
return this.maxLength
}

View File

@@ -0,0 +1,49 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
import (
"bytes"
"encoding/json"
)
type NetworkSecurityStatus = string
const (
NetworkSecurityStatusAuto NetworkSecurityStatus = "auto"
NetworkSecurityStatusOn NetworkSecurityStatus = "on"
NetworkSecurityStatusOff NetworkSecurityStatus = "off"
)
// NetworkSecurityPolicy 节点网络安全策略
type NetworkSecurityPolicy struct {
Status NetworkSecurityStatus `json:"status"` // 启用状态
TCP struct{} `json:"tcp"` // TODO
UDP struct{} `json:"udp"` // TODO
ICMP struct{} `json:"icmp"` // TODO
}
func NewNetworkSecurityPolicy() *NetworkSecurityPolicy {
var policy = &NetworkSecurityPolicy{}
policy.Status = NetworkSecurityStatusAuto
return policy
}
func (this *NetworkSecurityPolicy) Init() error {
return nil
}
func (this *NetworkSecurityPolicy) AsJSON() ([]byte, error) {
return json.Marshal(this)
}
func (this *NetworkSecurityPolicy) IsOn() bool {
return this.Status != NetworkSecurityStatusOff
}
func (this *NetworkSecurityPolicy) IsSame(anotherPolicy *NetworkSecurityPolicy) bool {
data1, _ := json.Marshal(this)
data2, _ := json.Marshal(anotherPolicy)
return bytes.Equal(data1, data2)
}

View File

@@ -0,0 +1,455 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package nodeconfigs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type NodeActionParam = string
const (
NodeActionParamDailyTrafficOut NodeActionParam = "dailyTrafficOut" // 节点日出口流量
NodeActionParamMonthlyTrafficOut NodeActionParam = "monthlyTrafficOut" // 节点月出口流量
// NodeActionParamTotalTraffic NodeActionParam = "totalTraffic" // 节点总流量 TODO 需要实现
NodeActionParamBandwidthIn NodeActionParam = "bandwidthIn" // 节点入口带宽
NodeActionParamBandwidthOut NodeActionParam = "bandwidthOut" // 节点出口带宽
NodeActionParamUDPDPSIn NodeActionParam = "udpDPSIn" // 节点单秒入口UDP数据报数量
NodeActionParamUDPDPSOut NodeActionParam = "udpDPSOut" // 节点单秒出口UDP数据报数量
NodeActionParamCPUUsage NodeActionParam = "cpuUsage" // 节点CPU用量百分比制0-100
NodeActionParamMemoryUsage NodeActionParam = "memoryUsage" // 节点内存用量百分比制0-100
NodeActionParamLoad NodeActionParam = "load" // 当前节点负载
// NodeActionParamConnectivity NodeActionParam = "connectivity" // 节点连通性 TODO 需要实现
NodeActionParamHealthCheckFailure NodeActionParam = "heathCheckFailure" // 节点健康检查失败
)
type NodeActionParamDefinition struct {
Name string `json:"name"`
Code string `json:"code"`
Description string `json:"description"`
Operators []NodeActionOperator `json:"operators"`
ValueName string `json:"valueName"`
ValueType string `json:"valueType"`
HasDuration bool `json:"hasDuration"`
}
func FindAllNodeActionParamDefinitions() []*NodeActionParamDefinition {
return []*NodeActionParamDefinition{
{
Code: NodeActionParamBandwidthOut,
Name: "节点出口带宽",
Description: "当前节点当前时间点的出口发送平均带宽(从节点发送到客户端)。",
Operators: allNodeActionNumberOperators,
ValueName: "对比带宽",
ValueType: "bandwidth",
HasDuration: true,
},
{
Code: NodeActionParamBandwidthIn,
Name: "节点入口带宽",
Description: "当前节点当前时间点的入口接收平均带宽(从客户端发送到节点)。",
Operators: allNodeActionNumberOperators,
ValueName: "对比带宽",
ValueType: "bandwidth",
HasDuration: true,
},
{
Code: NodeActionParamMonthlyTrafficOut,
Name: "节点当月流量",
Description: "当前节点在当月的出口发送流量。",
Operators: allNodeActionNumberOperators,
ValueName: "对比流量",
ValueType: "traffic",
HasDuration: false,
},
{
Code: NodeActionParamDailyTrafficOut,
Name: "节点当日流量",
Description: "当前节点在当天的出口发送流量。",
Operators: allNodeActionNumberOperators,
ValueName: "对比流量",
ValueType: "traffic",
HasDuration: false,
},
{
Code: NodeActionParamCPUUsage,
Name: "节点CPU利用率",
Description: "节点当前CPU利用率取值范围为0-100。",
Operators: allNodeActionNumberOperators,
ValueName: "CPU利用率",
ValueType: "cpu",
HasDuration: true,
},
{
Code: NodeActionParamMemoryUsage,
Name: "节点内存利用率",
Description: "节点当前内存利用率取值范围为0-100。",
Operators: allNodeActionNumberOperators,
ValueName: "内存利用率",
ValueType: "memory",
HasDuration: true,
},
{
Code: NodeActionParamLoad,
Name: "节点负载",
Description: "节点当前负载取值范围为0-∞通常超过10表示系统负载较重。",
Operators: allNodeActionNumberOperators,
ValueName: "系统负载",
ValueType: "load",
HasDuration: true,
},
{
Code: NodeActionParamHealthCheckFailure,
Name: "节点健康检查失败",
Description: "当前节点任一IP健康检查失败此功能需要当前集群开启健康检查。",
Operators: nil,
HasDuration: true,
},
{
Code: NodeActionParamUDPDPSOut,
Name: "节点UDP数据报发送速率",
Description: "当前节点当前时间点的UDP数据报发送速率。",
Operators: allNodeActionNumberOperators,
ValueName: "对比速率",
ValueType: "rate",
HasDuration: true,
},
{
Code: NodeActionParamUDPDPSIn,
Name: "节点UDP数据报接收速率",
Description: "当前节点当前时间点的UDP数据报接收速率。",
Operators: allNodeActionNumberOperators,
ValueName: "对比速率",
ValueType: "rate",
HasDuration: true,
},
}
}
type NodeActionOperator = string
const (
NodeActionOperatorGt NodeActionOperator = "gt"
NodeActionOperatorGte NodeActionOperator = "gte"
NodeActionOperatorLt NodeActionOperator = "lt"
NodeActionOperatorLte NodeActionOperator = "lte"
NodeActionOperatorEq NodeActionOperator = "eq"
)
var allNodeActionNumberOperators = []NodeActionOperator{NodeActionOperatorGt, NodeActionOperatorGte, NodeActionOperatorLt, NodeActionOperatorLte, NodeActionOperatorEq}
func FindAllNodeActionOperatorDefinitions() []*shared.Definition {
return []*shared.Definition{
{
Code: NodeActionOperatorGt,
Name: "大于()",
},
{
Code: NodeActionOperatorGte,
Name: "大于等于(≥)",
},
{
Code: NodeActionOperatorLt,
Name: "小于()",
},
{
Code: NodeActionOperatorLte,
Name: "小于等于(≤)",
},
{
Code: NodeActionOperatorEq,
Name: "等于(=)",
},
}
}
// NodeActionCondConnector 条件之间关系
type NodeActionCondConnector = string
const (
NodeActionCondConnectorAnd NodeActionCondConnector = "and"
NodeActionCondConnectorOr NodeActionCondConnector = "or"
)
type NodeActionCond struct {
Param NodeActionParam `json:"param"` // 参数名
Operator NodeActionOperator `json:"operator"` // 操作符
Value any `json:"value"` // 对比值
}
func (this *NodeActionCond) Match(value any) bool {
var paramDef *NodeActionParamDefinition
for _, paramDef2 := range FindAllNodeActionParamDefinitions() {
if paramDef2.Code == this.Param {
paramDef = paramDef2
break
}
}
if paramDef == nil {
return false
}
switch paramDef.ValueType {
case "bandwidth":
if value != nil && !this.isScalar(value) {
var value1Map = maps.NewMap(value)
value = this.toBandwidthBits(value1Map)
}
var value2Map = maps.NewMap(this.Value)
return this.compare(value, this.toBandwidthBits(value2Map))
case "traffic":
if value != nil && !this.isScalar(value) {
var value1Map = maps.NewMap(value)
value = this.toTrafficBytes(value1Map)
}
var value2Map = maps.NewMap(this.Value)
return this.compare(value, this.toTrafficBytes(value2Map))
case "cpu":
return this.compare(value, this.Value)
case "memory":
return this.compare(value, this.Value)
case "load":
return this.compare(value, this.Value)
case "rate":
return this.compare(value, this.Value)
case "":
return true
}
return false
}
func (this *NodeActionCond) compare(value1, value2 any) bool {
switch this.Operator {
case NodeActionOperatorGt:
return types.Int64(value1) > types.Int64(value2)
case NodeActionOperatorGte:
return types.Int64(value1) >= types.Int64(value2)
case NodeActionOperatorLt:
return types.Int64(value1) < types.Int64(value2)
case NodeActionOperatorLte:
return types.Int64(value1) <= types.Int64(value2)
case NodeActionOperatorEq:
return types.Int64(value1) == types.Int64(value2)
}
return false
}
func (this *NodeActionCond) toBandwidthBits(m maps.Map) int64 {
var count = m.GetInt64("count")
var unit = m.GetString("unit")
if count <= 0 {
return 0
}
switch unit {
case "b":
return count
case "kb":
return count << 10
case "mb":
return count << 20
case "gb":
return count << 30
case "tb":
return count << 40
}
return 0
}
func (this *NodeActionCond) toTrafficBytes(m maps.Map) int64 {
var count = m.GetInt64("count")
var unit = m.GetString("unit")
if count <= 0 {
return 0
}
switch unit {
case "b":
return count
case "kb":
return count << 10
case "mb":
return count << 20
case "gb":
return count << 30
case "tb":
return count << 40
case "pb":
return count << 50
case "eb":
return count << 60
}
return 0
}
func (this *NodeActionCond) isScalar(value any) bool {
if value == nil {
return false
}
switch value.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint64, float32, float64, string, bool:
return true
}
return false
}
type NodeActionCondsConfig struct {
Conds []*NodeActionCond `json:"conds"`
Connector NodeActionCondConnector `json:"connector"`
}
func NewNodeActionCondsConfig() *NodeActionCondsConfig {
return &NodeActionCondsConfig{
Connector: NodeActionCondConnectorAnd,
}
}
func (this *NodeActionCondsConfig) Match(valueGetter func(param NodeActionParam) (value any, err error)) (bool, error) {
if len(this.Conds) == 0 {
return false, nil
}
for index, cond := range this.Conds {
value, err := valueGetter(cond.Param)
if err != nil {
return false, err
}
var b = cond.Match(value)
if !b {
if this.Connector == NodeActionCondConnectorAnd {
return false, nil
}
// 如果是最后一个OR条件则直接返回false
if index == len(this.Conds)-1 {
return false, nil
}
} else {
if this.Connector == NodeActionCondConnectorOr {
return true, nil
}
// 如果是最后一个AND条件则直接返回true
if index == len(this.Conds)-1 {
return true, nil
}
}
}
return true, nil
}
// NodeActionCode 动作代号
type NodeActionCode = string
const (
NodeActionCodeUp NodeActionCode = "up" // 上线
NodeActionCodeDown NodeActionCode = "down" // 下线
NodeActionCodeSwitchToBackupNodesInCluster NodeActionCode = "switchToBackupNodesInCluster" // 切换到集群备用节点
NodeActionCodeSwitchToBackupNodesInGroup NodeActionCode = "switchToBackupNodesInGroup" // 切换到分组备用节点
NodeActionCodeSwitchToBackupIP NodeActionCode = "switchToBackupIP" // 切换到备用IP
NodeActionCodeEnableBackupNodesInCluster NodeActionCode = "enableBackupNodesInCluster" // 启用集群备用节点
NodeActionCodeEnableBackupNodesInGroup NodeActionCode = "enableBackupNodesInGroup" // 启用分组备用节点
NodeActionCodeEnableBackupIP NodeActionCode = "enableBackupIP" // 启用备用IP
NodeActionCodeWebHook NodeActionCode = "webHook" // WebHook
)
func FindAllNodeActionDefinitions() []*shared.Definition {
return []*shared.Definition{
{
Code: NodeActionCodeUp,
Name: "上线当前节点",
Description: "将当前节点状态设置为在线。",
},
{
Code: NodeActionCodeDown,
Name: "下线当前节点",
Description: "将当前节点状态设置为离线。",
},
{
Code: NodeActionCodeSwitchToBackupNodesInCluster,
Name: "切换到集群备用节点",
Description: "下线当前节点并启用节点所在集群备用节点。",
},
{
Code: NodeActionCodeSwitchToBackupNodesInGroup,
Name: "切换到分组备用节点",
Description: "下线当前节点并启用节点所在分组备用节点。",
},
{
Code: NodeActionCodeSwitchToBackupIP,
Name: "切换到备用IP",
Description: "将当前节点的IP切换到当前节点配置的备用IP。",
},
{
Code: NodeActionCodeEnableBackupNodesInCluster,
Name: "启用集群备用节点",
Description: "保持当前节点并启用节点所在集群备用节点。",
},
{
Code: NodeActionCodeEnableBackupNodesInGroup,
Name: "启用分组备用节点",
Description: "保持当前节点并启用节点所在分组备用节点。",
},
{
Code: NodeActionCodeEnableBackupIP,
Name: "启用备用IP",
Description: "保持当前节点的IP并启用当前节点配置的备用IP。",
},
{
Code: NodeActionCodeWebHook,
Name: "WebHook",
Description: "通过WebHook发送通知到URL。",
},
}
}
func FindNodeActionDefinition(code NodeActionCode) *shared.Definition {
for _, def := range FindAllNodeActionDefinitions() {
if def.Code == code {
return def
}
}
return nil
}
func FindNodeActionName(code NodeActionCode) string {
var def = FindNodeActionDefinition(code)
if def != nil {
return def.Name
}
return ""
}
// NodeActionConfig 动作配置
type NodeActionConfig struct {
Code NodeActionCode `json:"code"` // 动作代号
Params any `json:"params"` // 动作参数
}
func NewNodeActionConfig() *NodeActionConfig {
return &NodeActionConfig{}
}
type NodeActionCodeWebHookParams struct {
URL string `json:"url"` // URL路径
}
// NodeActionStatus 动作状态
type NodeActionStatus struct {
ActionId int64 `json:"actionId"` // 动作ID
CreatedAt int64 `json:"createdAt"` // 状态创建时间
Conds *NodeActionCondsConfig `json:"conds"` // 动作条件
Action *NodeActionConfig `json:"action"` // 动作配置
ExpiresAt int64 `json:"expiresAt"` // 过期时间
DurationSeconds int64 `json:"durationSeconds"` // 周期秒数
}

View File

@@ -0,0 +1,852 @@
package nodeconfigs
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"os"
"reflect"
"strconv"
"strings"
"sync"
)
var sharedNodeConfig *NodeConfig = nil
var uamPolicyLocker = &sync.RWMutex{}
var httpCCPolicyLocker = &sync.RWMutex{}
var http3PolicyLocker = &sync.RWMutex{}
var httpPagesPolicyLocker = &sync.RWMutex{}
var webPPolicyLocker = &sync.RWMutex{}
var plansLocker = &sync.RWMutex{}
type ServerError struct {
Id int64
Message string
}
func NewServerError(serverId int64, message string) *ServerError {
return &ServerError{Id: serverId, Message: message}
}
// NodeConfig 边缘节点配置
type NodeConfig struct {
Id int64 `yaml:"id" json:"id"`
Edition string `yaml:"edition" json:"edition"`
NodeId string `yaml:"nodeId" json:"nodeId"`
Secret string `yaml:"secret" json:"secret"`
IsOn bool `yaml:"isOn" json:"isOn"`
Servers []*serverconfigs.ServerConfig `yaml:"servers" json:"servers"`
SupportCNAME bool `yaml:"supportCNAME" json:"supportCNAME"`
Version int64 `yaml:"version" json:"version"`
Name string `yaml:"name" json:"name"`
GroupId int64 `yaml:"groupId" json:"groupId"`
RegionId int64 `yaml:"regionId" json:"regionId"`
OCSPVersion int64 `yaml:"ocspVersion" json:"ocspVersion"`
DataMap *shared.DataMap `yaml:"dataMap" json:"dataMap"`
UpdatingServerListId int64 `yaml:"updatingServerListId" json:"updatingServerListId"`
// 性能
MaxCPU int32 `yaml:"maxCPU" json:"maxCPU"`
APINodeAddrs []*serverconfigs.NetworkAddressConfig `yaml:"apiNodeAddrs" json:"apiNodeAddrs"`
CacheDiskDir string `yaml:"cacheDiskDir" json:"cacheDiskDir"` // 文件缓存目录
MaxCacheDiskCapacity *shared.SizeCapacity `yaml:"maxCacheDiskCapacity" json:"maxCacheDiskCapacity"` // 文件缓存容量
CacheDiskSubDirs []*serverconfigs.CacheDir `yaml:"cacheDiskSubDirs" json:"cacheDiskSubDirs"` // 其余缓存目录
MaxCacheMemoryCapacity *shared.SizeCapacity `yaml:"maxCacheMemoryCapacity" json:"maxCacheMemoryCapacity"` // 内容缓存容量
MaxThreads int `yaml:"maxThreads" json:"maxThreads"` // 最大线程数
DDoSProtection *ddosconfigs.ProtectionConfig `yaml:"ddosProtection" json:"ddosProtection"` // DDoS防护
EnableIPLists bool `yaml:"enableIPLists" json:"enableIPLists"` // 启用IP名单
// 级别
Level int32 `yaml:"level" json:"level"`
ParentNodes map[int64][]*ParentNodeConfig `yaml:"parentNodes" json:"parentNodes"` // clusterId => []*ParentNodeConfig
// 全局配置
GlobalServerConfig *serverconfigs.GlobalServerConfig `yaml:"globalServerConfig" json:"globalServerConfig"` // 服务全局配置,用来替代 GlobalConfig
ProductConfig *ProductConfig `yaml:"productConfig" json:"productConfig"`
// 集群统一配置
HTTPFirewallPolicies []*firewallconfigs.HTTPFirewallPolicy `yaml:"httpFirewallPolicies" json:"httpFirewallPolicies"`
HTTPCachePolicies []*serverconfigs.HTTPCachePolicy `yaml:"httpCachePolicies" json:"httpCachePolicies"`
TOA *TOAConfig `yaml:"toa" json:"toa"`
SystemServices map[string]maps.Map `yaml:"systemServices" json:"systemServices"` // 系统服务配置 type => params
FirewallActions []*firewallconfigs.FirewallActionConfig `yaml:"firewallActions" json:"firewallActions"` // 防火墙动作
TimeZone string `yaml:"timeZone" json:"timeZone"` // 自动设置时区
AutoOpenPorts bool `yaml:"autoOpenPorts" json:"autoOpenPorts"` // 自动开放所需端口
Clock *ClockConfig `yaml:"clock" json:"clock"` // 时钟配置
AutoInstallNftables bool `yaml:"autoInstallNftables" json:"autoInstallNftables"` // 自动安装nftables
AutoSystemTuning bool `yaml:"autoSystemTuning" json:"autoSystemTuning"` // 自动调整系统参数
AutoTrimDisks bool `yaml:"autoTrimDisks" json:"autoTrimDisks"` // 自动执行TRIM
MaxConcurrentReads int `yaml:"maxConcurrentReads" json:"maxConcurrentReads"` // 最大并发读
MaxConcurrentWrites int `yaml:"maxConcurrentWrites" json:"maxConcurrentWrites"` // 最大并发写
// 指标
MetricItems []*serverconfigs.MetricItemConfig `yaml:"metricItems" json:"metricItems"`
IPAddresses []string `yaml:"ipAddresses" json:"ipAddresses"` // IP地址
AllowedIPs []string `yaml:"allowedIPs" json:"allowedIPs"` // 自动IP白名单
// 脚本
CommonScripts []*serverconfigs.CommonScript `yaml:"commonScripts" json:"commonScripts"`
WebPImagePolicies map[int64]*WebPImagePolicy `yaml:"webpImagePolicies" json:"webpImagePolicies"` // WebP相关配置clusterId => *WebPImagePolicy
UAMPolicies map[int64]*UAMPolicy `yaml:"uamPolicies" json:"uamPolicies"` // UAM相关配置clusterId => *UAMPolicy
HTTPCCPolicies map[int64]*HTTPCCPolicy `yaml:"httpCCPolicies" json:"httpCCPolicies"` // CC相关配置 clusterId => *HTTPCCPolicy
HTTP3Policies map[int64]*HTTP3Policy `yaml:"http3Policies" json:"http3Policies"` // HTTP3相关配置 clusterId => *HTTP3Policy
HTTPPagesPolicies map[int64]*HTTPPagesPolicy `yaml:"httpPagesPolicies" json:"httpPagesPolicies"` // 自定义页面clusterId => *HTTPPagesPolicy
NetworkSecurityPolicy *NetworkSecurityPolicy `yaml:"networkSecurityPolicy" json:"networkSecurityPolicy"` // 网络安全策略
Plans map[int64]*serverconfigs.PlanConfig `yaml:"plans" json:"plans"` // 套餐 plan id => *serverconfigs.PlanConfig
// DNS
DNSResolver *DNSResolverConfig `yaml:"dnsResolver" json:"dnsResolver"`
// Cluster
ClusterSecret string `yaml:"clusterSecret" json:"clusterSecret"`
paddedId string
// firewall
firewallPolicies []*firewallconfigs.HTTPFirewallPolicy
// metrics
hasHTTPConnectionMetrics bool
// 源站集合
originMap map[int64]*serverconfigs.OriginConfig
// 自动白名单
allowedIPMap map[string]bool
// syn flood
synFlood *firewallconfigs.SYNFloodConfig
secretHash string
}
// SharedNodeConfig 取得当前节点配置单例
func SharedNodeConfig() (*NodeConfig, error) {
shared.Locker.Lock()
defer shared.Locker.Unlock()
if sharedNodeConfig != nil {
return sharedNodeConfig, nil
}
// 从本地缓存读取
var configFile = Tea.ConfigFile("node.json")
var readCacheOk = false
defer func() {
if !readCacheOk {
_ = os.Remove(configFile)
}
}()
data, err := os.ReadFile(configFile)
if err != nil {
return &NodeConfig{}, err
}
encodedNodeInfo, encodedJSONData, found := bytes.Cut(data, []byte("\n"))
if !found {
// 删除缓存文件
return &NodeConfig{}, errors.New("node.json: invalid data format")
}
encodedNodeInfoData, err := base64.StdEncoding.DecodeString(string(encodedNodeInfo))
if err != nil {
// 删除缓存文件
return &NodeConfig{}, err
}
nodeUniqueId, nodeSecret, found := strings.Cut(string(encodedNodeInfoData), "|")
if !found {
// 删除缓存文件
return &NodeConfig{}, errors.New("node.json: node info: invalid data format")
}
jsonData, err := nodeutils.DecryptData(nodeUniqueId, nodeSecret, string(encodedJSONData))
if err != nil {
return &NodeConfig{}, err
}
var config = &NodeConfig{}
err = json.Unmarshal(jsonData, &config)
if err != nil {
return &NodeConfig{}, err
}
readCacheOk = true
sharedNodeConfig = config
return config, nil
}
// ResetNodeConfig 重置节点配置
func ResetNodeConfig(nodeConfig *NodeConfig) {
shared.Locker.Lock()
sharedNodeConfig = nodeConfig
shared.Locker.Unlock()
}
// CloneNodeConfig 复制节点配置
func CloneNodeConfig(nodeConfig *NodeConfig) (*NodeConfig, error) {
if nodeConfig == nil {
return nil, errors.New("node config should not be nil")
}
uamPolicyLocker.RLock()
defer uamPolicyLocker.RUnlock()
httpCCPolicyLocker.RLock()
defer httpCCPolicyLocker.RUnlock()
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
httpPagesPolicyLocker.RLock()
defer httpPagesPolicyLocker.RUnlock()
webPPolicyLocker.RLock()
defer webPPolicyLocker.RUnlock()
plansLocker.RLock()
defer plansLocker.RUnlock()
var newConfigValue = reflect.Indirect(reflect.ValueOf(&NodeConfig{}))
var oldValue = reflect.Indirect(reflect.ValueOf(nodeConfig))
var valueType = oldValue.Type()
for i := 0; i < valueType.NumField(); i++ {
var field = valueType.Field(i)
var fieldName = field.Name
if !field.IsExported() {
continue
}
if fieldName == "Servers" {
continue
}
newConfigValue.FieldByName(fieldName).Set(oldValue.FieldByName(fieldName))
}
var newConfig = newConfigValue.Interface().(NodeConfig)
newConfig.Servers = append([]*serverconfigs.ServerConfig{}, nodeConfig.Servers...)
return &newConfig, nil
}
// Init 初始化
func (this *NodeConfig) Init(ctx context.Context) (err error, serverErrors []*ServerError) {
// 设置Context
if ctx == nil {
ctx = context.Background()
}
ctx = context.WithValue(ctx, "DataMap", this.DataMap)
this.secretHash = fmt.Sprintf("%x", sha256.Sum256([]byte(this.NodeId+"@"+this.Secret)))
this.paddedId = fmt.Sprintf("%08d", this.Id)
// servers
for _, server := range this.Servers {
// 避免在运行时重新初始化
if server.IsInitialized() {
continue
}
// 初始化
errs := server.Init(ctx)
if len(errs) > 0 {
// 这里不返回错误,而是继续往下,防止单个服务错误而影响其他服务
for _, serverErr := range errs {
serverErrors = append(serverErrors, NewServerError(server.Id, "server '"+strconv.FormatInt(server.Id, 10)+"' init failed: "+serverErr.Error()))
}
}
// 检查ACME支持
if server.IsOn && server.SupportCNAME {
this.SupportCNAME = true
}
}
// cache policy
if len(this.HTTPCachePolicies) > 0 {
for _, policy := range this.HTTPCachePolicies {
err = policy.Init()
if err != nil {
return
}
}
}
// firewall policy
if len(this.HTTPFirewallPolicies) > 0 {
for _, policy := range this.HTTPFirewallPolicies {
err = policy.Init()
if err != nil {
return
}
}
}
// TOA
if this.TOA != nil {
err = this.TOA.Init()
if err != nil {
return
}
}
// 源站
this.originMap = map[int64]*serverconfigs.OriginConfig{}
// 查找FirewallPolicy
this.synFlood = nil
this.firewallPolicies = []*firewallconfigs.HTTPFirewallPolicy{}
for _, policy := range this.HTTPFirewallPolicies {
if policy.IsOn {
this.firewallPolicies = append(this.firewallPolicies, policy)
if policy.SYNFlood != nil && policy.SYNFlood.IsOn {
this.synFlood = policy.SYNFlood
}
}
}
for _, server := range this.Servers {
if !server.IsOk() || !server.IsOn {
continue
}
// WAF策略
if server.HTTPFirewallPolicyId > 0 {
for _, policy := range this.HTTPFirewallPolicies {
if server.HTTPFirewallPolicyId == policy.Id {
server.HTTPFirewallPolicy = policy
break
}
}
}
// 缓存策略
if server.HTTPCachePolicyId > 0 {
for _, policy := range this.HTTPCachePolicies {
if server.HTTPCachePolicyId == policy.Id {
server.HTTPCachePolicy = policy
}
}
}
// 源站
if server.ReverseProxyRef != nil && server.ReverseProxyRef.IsOn && server.ReverseProxy != nil && server.ReverseProxy.IsOn {
for _, origin := range server.ReverseProxy.PrimaryOrigins {
if origin.IsOn {
this.originMap[origin.Id] = origin
}
}
for _, origin := range server.ReverseProxy.BackupOrigins {
if origin.IsOn {
this.originMap[origin.Id] = origin
}
}
}
if server.Web != nil {
this.lookupWeb(server, server.Web)
}
}
// firewall actions
for _, action := range this.FirewallActions {
err = action.Init()
if err != nil {
return
}
}
// metric items
this.hasHTTPConnectionMetrics = false
for _, item := range this.MetricItems {
err = item.Init()
if err != nil {
return
}
if item.IsOn && item.HasHTTPConnectionValue() {
this.hasHTTPConnectionMetrics = true
}
}
// 自动白名单
this.allowedIPMap = map[string]bool{}
for _, allowIP := range this.AllowedIPs {
this.allowedIPMap[allowIP] = true
}
// webp image policy
webPPolicyLocker.RLock()
if this.WebPImagePolicies != nil {
for _, policy := range this.WebPImagePolicies {
err = policy.Init()
if err != nil {
webPPolicyLocker.RUnlock()
return
}
}
}
webPPolicyLocker.RUnlock()
// uam policy
uamPolicyLocker.RLock()
if len(this.UAMPolicies) > 0 {
for _, policy := range this.UAMPolicies {
err = policy.Init()
if err != nil {
uamPolicyLocker.RUnlock()
return
}
}
}
uamPolicyLocker.RUnlock()
// http cc policy
httpCCPolicyLocker.RLock()
if len(this.HTTPCCPolicies) > 0 {
for _, policy := range this.HTTPCCPolicies {
err = policy.Init()
if err != nil {
httpCCPolicyLocker.RUnlock()
return
}
}
}
httpCCPolicyLocker.RUnlock()
// http3 policy
http3PolicyLocker.RLock()
if len(this.HTTP3Policies) > 0 {
for _, policy := range this.HTTP3Policies {
err = policy.Init()
if err != nil {
http3PolicyLocker.RUnlock()
return
}
}
}
http3PolicyLocker.RUnlock()
// http pages policy
httpPagesPolicyLocker.RLock()
if len(this.HTTPPagesPolicies) > 0 {
for _, policy := range this.HTTPPagesPolicies {
err = policy.Init()
if err != nil {
httpPagesPolicyLocker.RUnlock()
return
}
}
}
httpPagesPolicyLocker.RUnlock()
// plans
plansLocker.RLock()
if len(this.Plans) > 0 {
for _, plan := range this.Plans {
err = plan.Init()
if err != nil {
plansLocker.RUnlock()
return
}
}
}
plansLocker.RUnlock()
// dns resolver
if this.DNSResolver != nil {
err = this.DNSResolver.Init()
if err != nil {
return
}
}
// 全局服务设置
if this.GlobalServerConfig != nil {
err = this.GlobalServerConfig.Init()
if err != nil {
return
}
}
// api node addrs
if len(this.APINodeAddrs) > 0 {
for _, addr := range this.APINodeAddrs {
err = addr.Init()
if err != nil {
return err, nil
}
}
}
// network security policy
if this.NetworkSecurityPolicy != nil {
err = this.NetworkSecurityPolicy.Init()
if err != nil {
return err, nil
}
}
return
}
// AddServer 添加服务
func (this *NodeConfig) AddServer(server *serverconfigs.ServerConfig) {
if server == nil {
return
}
var found = false
for index, oldServer := range this.Servers {
if oldServer.Id == server.Id {
this.Servers[index] = server
found = true
break
}
}
if !found {
this.Servers = append(this.Servers, server)
}
}
// RemoveServer 删除服务
func (this *NodeConfig) RemoveServer(serverId int64) {
for index, oldServer := range this.Servers {
if oldServer.Id == serverId {
this.Servers = append(this.Servers[:index], this.Servers[index+1:]...)
break
}
}
}
// AvailableGroups 根据网络地址和协议分组
func (this *NodeConfig) AvailableGroups() []*serverconfigs.ServerAddressGroup {
var groupMapping = map[string]*serverconfigs.ServerAddressGroup{} // protocol://addr => Server Group
for _, server := range this.Servers {
if !server.IsOk() || !server.IsOn {
continue
}
for _, addr := range server.FullAddresses() {
group, ok := groupMapping[addr]
if ok {
group.Add(server)
} else {
group = serverconfigs.NewServerAddressGroup(addr)
group.Add(server)
}
groupMapping[addr] = group
}
}
var result = []*serverconfigs.ServerAddressGroup{}
for _, group := range groupMapping {
result = append(result, group)
}
return result
}
// HTTP3Group HTTP/3网站分组
// 这里暂时不区分集群
func (this *NodeConfig) HTTP3Group() *serverconfigs.ServerAddressGroup {
var group = serverconfigs.NewServerAddressGroup("HTTP3")
for _, server := range this.Servers {
if !server.SupportsHTTP3() {
continue
}
group.Add(server)
}
return group
}
// FindAllFirewallPolicies 获取所有的防火墙策略
func (this *NodeConfig) FindAllFirewallPolicies() []*firewallconfigs.HTTPFirewallPolicy {
return this.firewallPolicies
}
// Save 写入到文件
func (this *NodeConfig) Save() error {
shared.Locker.Lock()
defer shared.Locker.Unlock()
data, err := json.Marshal(this)
if err != nil {
return err
}
var headerData = []byte(base64.StdEncoding.EncodeToString([]byte(this.NodeId+"|"+this.Secret)) + "\n")
encodedData, err := nodeutils.EncryptData(this.NodeId, this.Secret, data)
if err != nil {
return err
}
return os.WriteFile(Tea.ConfigFile("node.json"), append(headerData, encodedData...), 0777)
}
// PaddedId 获取填充后的ID
func (this *NodeConfig) PaddedId() string {
return this.paddedId
}
// HasHTTPConnectionMetrics 是否含有HTTP连接数的指标
func (this *NodeConfig) HasHTTPConnectionMetrics() bool {
return this.hasHTTPConnectionMetrics
}
// FindOrigin 读取源站配置
func (this *NodeConfig) FindOrigin(originId int64) *serverconfigs.OriginConfig {
if this.originMap == nil {
return nil
}
config, ok := this.originMap[originId]
if ok {
return config
}
return nil
}
// 搜索WAF策略
func (this *NodeConfig) lookupWeb(server *serverconfigs.ServerConfig, web *serverconfigs.HTTPWebConfig) {
if web == nil || !web.IsOn {
return
}
if web.FirewallPolicy != nil && web.FirewallPolicy.IsOn {
// 复用节点的选项设置
if server.HTTPFirewallPolicy != nil {
if (web.FirewallPolicy.BlockOptions == nil || !web.FirewallPolicy.BlockOptions.IsPrior) && server.HTTPFirewallPolicy.BlockOptions != nil {
web.FirewallPolicy.BlockOptions = server.HTTPFirewallPolicy.BlockOptions
}
if (web.FirewallPolicy.PageOptions == nil || !web.FirewallPolicy.PageOptions.IsPrior) && server.HTTPFirewallPolicy.PageOptions != nil {
web.FirewallPolicy.PageOptions = server.HTTPFirewallPolicy.PageOptions
}
if (web.FirewallPolicy.CaptchaOptions == nil || !web.FirewallPolicy.CaptchaOptions.IsPrior) && server.HTTPFirewallPolicy.CaptchaOptions != nil {
web.FirewallPolicy.CaptchaOptions = server.HTTPFirewallPolicy.CaptchaOptions
}
if (web.FirewallPolicy.Get302Options == nil || !web.FirewallPolicy.Get302Options.IsPrior) && server.HTTPFirewallPolicy.Get302Options != nil {
web.FirewallPolicy.Get302Options = server.HTTPFirewallPolicy.Get302Options
}
if (web.FirewallPolicy.Post307Options == nil || !web.FirewallPolicy.Post307Options.IsPrior) && server.HTTPFirewallPolicy.Post307Options != nil {
web.FirewallPolicy.Post307Options = server.HTTPFirewallPolicy.Post307Options
}
if (web.FirewallPolicy.JSCookieOptions == nil || !web.FirewallPolicy.JSCookieOptions.IsPrior) && server.HTTPFirewallPolicy.JSCookieOptions != nil {
web.FirewallPolicy.JSCookieOptions = server.HTTPFirewallPolicy.JSCookieOptions
}
if (web.FirewallPolicy.SYNFlood == nil || !web.FirewallPolicy.SYNFlood.IsPrior) && server.HTTPFirewallPolicy.SYNFlood != nil {
web.FirewallPolicy.SYNFlood = server.HTTPFirewallPolicy.SYNFlood
}
if (web.FirewallPolicy.Log == nil || !web.FirewallPolicy.Log.IsPrior) && server.HTTPFirewallPolicy.Log != nil {
web.FirewallPolicy.Log = server.HTTPFirewallPolicy.Log
}
web.FirewallPolicy.Mode = server.HTTPFirewallPolicy.Mode
web.FirewallPolicy.UseLocalFirewall = server.HTTPFirewallPolicy.UseLocalFirewall
}
this.firewallPolicies = append(this.firewallPolicies, web.FirewallPolicy)
}
if len(web.Locations) > 0 {
for _, location := range web.Locations {
// 源站
if location.IsOn && location.ReverseProxyRef != nil && location.ReverseProxyRef.IsOn && location.ReverseProxy != nil && location.ReverseProxy.IsOn {
for _, origin := range location.ReverseProxy.PrimaryOrigins {
if origin.IsOn {
this.originMap[origin.Id] = origin
}
}
for _, origin := range location.ReverseProxy.BackupOrigins {
if origin.IsOn {
this.originMap[origin.Id] = origin
}
}
}
// Web
if location.Web != nil && location.Web.IsOn {
this.lookupWeb(server, location.Web)
}
}
}
}
// IPIsAutoAllowed 检查是否自动允许某个IP
func (this *NodeConfig) IPIsAutoAllowed(ip string) bool {
_, ok := this.allowedIPMap[ip]
return ok
}
// SYNFloodConfig 获取SYN Flood配置
func (this *NodeConfig) SYNFloodConfig() *firewallconfigs.SYNFloodConfig {
return this.synFlood
}
// UpdateCertOCSP 修改证书OCSP
func (this *NodeConfig) UpdateCertOCSP(certId int64, ocsp []byte, expiresAt int64) {
shared.Locker.Lock()
defer shared.Locker.Unlock()
var servers = this.Servers
for _, server := range servers {
if server.HTTPS != nil &&
server.HTTPS.SSLPolicy != nil &&
server.HTTPS.SSLPolicy.OCSPIsOn &&
server.HTTPS.SSLPolicy.ContainsCert(certId) {
server.HTTPS.SSLPolicy.UpdateCertOCSP(certId, ocsp, expiresAt)
}
if server.TLS != nil &&
server.TLS.SSLPolicy != nil &&
server.TLS.SSLPolicy.OCSPIsOn &&
server.TLS.SSLPolicy.ContainsCert(certId) {
server.TLS.SSLPolicy.UpdateCertOCSP(certId, ocsp, expiresAt)
}
}
}
// FindWebPImagePolicyWithClusterId 使用集群ID查找WebP策略
func (this *NodeConfig) FindWebPImagePolicyWithClusterId(clusterId int64) *WebPImagePolicy {
webPPolicyLocker.RLock()
defer webPPolicyLocker.RUnlock()
if this.WebPImagePolicies == nil {
return nil
}
return this.WebPImagePolicies[clusterId]
}
// UpdateWebPImagePolicies 修改集群WebP策略
func (this *NodeConfig) UpdateWebPImagePolicies(policies map[int64]*WebPImagePolicy) {
webPPolicyLocker.Lock()
defer webPPolicyLocker.Unlock()
this.WebPImagePolicies = policies
}
// FindUAMPolicyWithClusterId 使用集群ID查找UAM策略
func (this *NodeConfig) FindUAMPolicyWithClusterId(clusterId int64) *UAMPolicy {
uamPolicyLocker.RLock()
defer uamPolicyLocker.RUnlock()
if this.UAMPolicies == nil {
return nil
}
return this.UAMPolicies[clusterId]
}
// UpdateUAMPolicies 修改集群UAM策略
func (this *NodeConfig) UpdateUAMPolicies(policies map[int64]*UAMPolicy) {
uamPolicyLocker.Lock()
defer uamPolicyLocker.Unlock()
this.UAMPolicies = policies
}
// FindHTTPCCPolicyWithClusterId 使用集群ID查找CC策略
func (this *NodeConfig) FindHTTPCCPolicyWithClusterId(clusterId int64) *HTTPCCPolicy {
httpCCPolicyLocker.RLock()
defer httpCCPolicyLocker.RUnlock()
if this.HTTPCCPolicies == nil {
return nil
}
return this.HTTPCCPolicies[clusterId]
}
// UpdateHTTPCCPolicies 修改集群CC策略
func (this *NodeConfig) UpdateHTTPCCPolicies(policies map[int64]*HTTPCCPolicy) {
httpCCPolicyLocker.Lock()
defer httpCCPolicyLocker.Unlock()
this.HTTPCCPolicies = policies
}
// FindHTTP3PolicyWithClusterId 使用集群ID查找HTTP/3策略
func (this *NodeConfig) FindHTTP3PolicyWithClusterId(clusterId int64) *HTTP3Policy {
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
if this.HTTP3Policies == nil {
return nil
}
return this.HTTP3Policies[clusterId]
}
// FindHTTP3Ports 查询HTTP/3所有端口
func (this *NodeConfig) FindHTTP3Ports() (ports []int) {
http3PolicyLocker.RLock()
defer http3PolicyLocker.RUnlock()
for _, policy := range this.HTTP3Policies {
if !policy.IsOn {
continue
}
if policy.Port <= 0 {
policy.Port = DefaultHTTP3Port
}
if !lists.ContainsInt(ports, policy.Port) {
ports = append(ports, policy.Port)
}
}
return
}
// UpdateHTTP3Policies 修改集群HTTP/3策略
func (this *NodeConfig) UpdateHTTP3Policies(policies map[int64]*HTTP3Policy) {
http3PolicyLocker.Lock()
defer http3PolicyLocker.Unlock()
this.HTTP3Policies = policies
}
// UpdateHTTPPagesPolicies 修改集群自定义页面策略
func (this *NodeConfig) UpdateHTTPPagesPolicies(policies map[int64]*HTTPPagesPolicy) {
httpPagesPolicyLocker.Lock()
defer httpPagesPolicyLocker.Unlock()
this.HTTPPagesPolicies = policies
}
// FindHTTPPagesPolicyWithClusterId 使用集群ID查找自定义页面策略
func (this *NodeConfig) FindHTTPPagesPolicyWithClusterId(clusterId int64) *HTTPPagesPolicy {
httpPagesPolicyLocker.RLock()
defer httpPagesPolicyLocker.RUnlock()
if this.HTTPPagesPolicies == nil {
return nil
}
return this.HTTPPagesPolicies[clusterId]
}
// UpdatePlans 更新套餐
func (this *NodeConfig) UpdatePlans(planMap map[int64]*serverconfigs.PlanConfig) {
plansLocker.Lock()
this.Plans = planMap
plansLocker.Unlock()
}
// FindAllPlans 查找所有套餐
func (this *NodeConfig) FindAllPlans() map[int64]*serverconfigs.PlanConfig {
plansLocker.RLock()
defer plansLocker.RUnlock()
return this.Plans
}
// 查找单个套餐
func (this *NodeConfig) FindPlan(planId int64) *serverconfigs.PlanConfig {
plansLocker.RLock()
defer plansLocker.RUnlock()
return this.Plans[planId]
}
// SecretHash 对Id和Secret的Hash计算
func (this *NodeConfig) SecretHash() string {
return this.secretHash
}
// HasConnTimeoutSettings 检查是否有连接超时设置
func (this *NodeConfig) HasConnTimeoutSettings() bool {
return this.GlobalServerConfig != nil && (this.GlobalServerConfig.Performance.AutoReadTimeout || this.GlobalServerConfig.Performance.AutoWriteTimeout)
}

View File

@@ -0,0 +1,120 @@
package nodeconfigs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
_ "github.com/iwind/TeaGo/bootstrap"
"github.com/iwind/TeaGo/logs"
"testing"
"time"
)
func TestSharedNodeConfig(t *testing.T) {
{
config, err := SharedNodeConfig()
if err != nil {
t.Fatal(err)
}
t.Log(config)
}
// read from memory cache
{
config, err := SharedNodeConfig()
if err != nil {
t.Fatal(err)
}
t.Log(config)
}
}
func TestNodeConfig_Groups(t *testing.T) {
config := &NodeConfig{}
config.Servers = []*serverconfigs.ServerConfig{
{
IsOn: true,
HTTP: &serverconfigs.HTTPProtocolConfig{
BaseProtocol: serverconfigs.BaseProtocol{
IsOn: true,
Listen: []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolHTTP,
Host: "127.0.0.1",
PortRange: "1234",
},
{
Protocol: serverconfigs.ProtocolHTTP,
PortRange: "8080",
},
},
},
},
},
{
HTTP: &serverconfigs.HTTPProtocolConfig{
BaseProtocol: serverconfigs.BaseProtocol{
IsOn: true,
Listen: []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolHTTP,
PortRange: "8080",
},
},
},
},
},
}
logs.PrintAsJSON(config.AvailableGroups(), t)
}
func TestCloneNodeConfig(t *testing.T) {
var config = &NodeConfig{Id: 1, NodeId: "1", IsOn: true}
for i := 0; i < 100_000; i++ {
config.Servers = append(config.Servers, &serverconfigs.ServerConfig{})
}
var before = time.Now()
newConfig, err := CloneNodeConfig(config)
t.Log(time.Since(before))
if err != nil {
t.Fatal(err)
}
newConfig.Servers = []*serverconfigs.ServerConfig{}
logs.PrintAsJSON(newConfig, t)
}
func TestNodeConfig_AddServer(t *testing.T) {
var config = &NodeConfig{Id: 1, NodeId: "1", IsOn: true}
config.AddServer(&serverconfigs.ServerConfig{Id: 1})
config.AddServer(&serverconfigs.ServerConfig{Id: 2})
t.Log("===before===")
for _, s := range config.Servers {
t.Log(s.Id)
}
t.Log("===after===")
config.AddServer(&serverconfigs.ServerConfig{Id: 3})
config.RemoveServer(2)
for _, s := range config.Servers {
t.Log(s.Id)
}
}
func TestCloneNodeConfig_UAMPolicies(t *testing.T) {
var config = &NodeConfig{}
config.UAMPolicies = map[int64]*UAMPolicy{}
t.Logf("%p", config.UAMPolicies)
clonedConfig, err := CloneNodeConfig(config)
if err != nil {
t.Fatal(err)
}
t.Logf("%p", clonedConfig.UAMPolicies)
}
func BenchmarkNodeConfig(b *testing.B) {
var config = &NodeConfig{}
for i := 0; i < b.N; i++ {
_, _ = CloneNodeConfig(config)
}
}

View File

@@ -0,0 +1,12 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
type NodeIPAddr struct {
Id int64 `json:"id"`
Name string `json:"name"`
IP string `json:"ip"`
IsOn bool `json:"isOn"`
IsUp bool `json:"isUp"`
CanAccess bool `json:"canAccess"`
}

View File

@@ -0,0 +1,37 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
type NodeLevel struct {
Name string `yaml:"name" json:"name"`
Code int `yaml:"code" json:"code"`
Description string `yaml:"description" json:"description"`
}
func FindAllNodeLevels() []*NodeLevel {
return []*NodeLevel{
{
Name: "边缘节点",
Code: 1,
Description: "普通的边缘节点。",
},
{
Name: "L2节点",
Code: 2,
Description: "特殊的边缘节点,同时负责同组上一级节点的回源。",
},
}
}
func FindNodeLevel(level int) *NodeLevel {
level--
var levels = FindAllNodeLevels()
if level < 0 {
return levels[0]
}
if level < len(levels) {
return levels[level]
}
return levels[0]
}

View File

@@ -0,0 +1,12 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
type NodeLogType = string
const (
NodeLogTypeListenAddressFailed NodeLogType = "listenAddressFailed"
NodeLogTypeServerConfigInitFailed NodeLogType = "serverConfigInitFailed"
NodeLogTypeRunScriptFailed NodeLogType = "runScriptFailed"
NodeLogTypeScriptConsoleLog NodeLogType = "scriptConsoleLog"
)

View File

@@ -0,0 +1,10 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
// ParentNodeConfig 父级节点配置
type ParentNodeConfig struct {
Id int64 `yaml:"id" json:"id"`
Addrs []string `yaml:"addrs" json:"addrs"`
SecretHash string `yaml:"secretHash" json:"secretHash"`
}

View File

@@ -0,0 +1,18 @@
package nodeconfigs
type NodeRole = string
const (
NodeRoleAdmin NodeRole = "admin"
NodeRoleUser NodeRole = "user"
NodeRoleProvider NodeRole = "provider"
NodeRoleAPI NodeRole = "api"
NodeRoleDatabase NodeRole = "database"
NodeRoleLog NodeRole = "log"
NodeRoleDNS NodeRole = "dns"
NodeRoleMonitor NodeRole = "monitor"
NodeRoleNode NodeRole = "node"
NodeRoleCluster NodeRole = "cluster"
NodeRoleAuthority NodeRole = "authority"
NodeRoleReport NodeRole = "report"
)

View File

@@ -0,0 +1,43 @@
package nodeconfigs
// NodeStatus 节点状态
type NodeStatus struct {
BuildVersion string `json:"buildVersion"` // 编译版本
BuildVersionCode uint32 `json:"buildVersionCode"` // 版本数字
ConfigVersion int64 `json:"configVersion"` // 节点配置版本
OS string `json:"os"`
Arch string `json:"arch"`
Hostname string `json:"hostname"`
HostIP string `json:"hostIP"`
CPUUsage float64 `json:"cpuUsage"`
CPULogicalCount int `json:"cpuLogicalCount"`
CPUPhysicalCount int `json:"cpuPhysicalCount"`
MemoryUsage float64 `json:"memoryUsage"`
MemoryTotal uint64 `json:"memoryTotal"`
DiskUsage float64 `json:"diskUsage"`
DiskMaxUsage float64 `json:"diskMaxUsage"`
DiskMaxUsagePartition string `json:"diskMaxUsagePartition"`
DiskTotal uint64 `json:"diskTotal"`
DiskWritingSpeedMB int `json:"diskWritingSpeedMB"` // 硬盘写入速度
UpdatedAt int64 `json:"updatedAt"`
Timestamp int64 `json:"timestamp"` // 当前节点时间戳
Load1m float64 `json:"load1m"`
Load5m float64 `json:"load5m"`
Load15m float64 `json:"load15m"`
ConnectionCount int `json:"connectionCount"` // 连接数
ExePath string `json:"exePath"` // 可执行文件路径
APISuccessPercent float64 `json:"apiSuccessPercent"` // API成功比例
APIAvgCostSeconds float64 `json:"apiAvgCostSeconds"` // API平均耗时
TrafficInBytes uint64 `json:"trafficInBytes"`
TrafficOutBytes uint64 `json:"trafficOutBytes"`
CacheTotalDiskSize int64 `json:"cacheTotalDiskSize"`
CacheTotalMemorySize int64 `json:"cacheTotalMemorySize"`
LocalFirewallName string `json:"localFirewallName"`
IsActive bool `json:"isActive"`
Error string `json:"error"`
}

View File

@@ -0,0 +1,355 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
import (
"encoding/json"
)
// NodeValueItem 监控项
type NodeValueItem = string
const (
NodeValueItemCPU NodeValueItem = "cpu" // CPU
NodeValueItemMemory NodeValueItem = "memory" // 内存
NodeValueItemLoad NodeValueItem = "load" // 负载
NodeValueItemTrafficIn NodeValueItem = "trafficIn" // 业务上行流量
NodeValueItemTrafficOut NodeValueItem = "trafficOut" // 业务下行流量
NodeValueItemAllTraffic NodeValueItem = "allTraffic" // 所有流量
NodeValueItemConnections NodeValueItem = "connections" // 连接数
NodeValueItemRequests NodeValueItem = "requests" // 请求访问量
NodeValueItemAttackRequests NodeValueItem = "attackRequests" // 攻击请求访问量
NodeValueItemDisk NodeValueItem = "disk" // 磁盘
NodeValueItemCacheDir NodeValueItem = "cacheDir" // 缓存目录
NodeValueItemNetworkPackets NodeValueItem = "networkPackets" // 网络数据包统计
)
type nodeValueItemDefinition struct {
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description"`
Params []*nodeValueItemParamDefinition `json:"params"`
}
type nodeValueItemParamDefinition struct {
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description"`
IsPercent bool `json:"isPercent"` // 是否支持百分比
}
var nodeValueItemDefinitions = []*nodeValueItemDefinition{
{
Code: NodeValueItemCPU,
Name: "CPU",
Params: []*nodeValueItemParamDefinition{
{
Code: "usage",
Name: "使用比例",
Description: "0到100之间的数字",
IsPercent: true,
},
},
},
{
Code: NodeValueItemMemory,
Name: "内存",
Params: []*nodeValueItemParamDefinition{
{
Code: "usage",
Name: "使用比例",
Description: "0到100之间的数字",
IsPercent: true,
},
},
},
{
Code: NodeValueItemLoad,
Name: "负载",
Params: []*nodeValueItemParamDefinition{
{
Code: "load1m",
Name: "1分钟负载",
Description: "1分钟内的平均负载",
},
{
Code: "load5m",
Name: "5分钟负载",
Description: "5分钟内的平均负载",
},
{
Code: "load15m",
Name: "15分钟负载",
Description: "15分钟内的平均负载",
},
},
},
{
Code: NodeValueItemTrafficIn,
Name: "上行流量",
Description: "平均每分钟客户端发送到服务器端的流量。",
Params: []*nodeValueItemParamDefinition{
{
Code: "total",
Name: "流量",
Description: "单位为字节",
},
},
},
{
Code: NodeValueItemTrafficOut,
Name: "下行流量",
Description: "平均每分钟服务器端发送到客户端的流量。",
Params: []*nodeValueItemParamDefinition{
{
Code: "total",
Name: "流量",
Description: "单位为字节",
},
},
},
{
Code: NodeValueItemConnections,
Name: "连接数",
Description: "平均每分钟连接数",
Params: []*nodeValueItemParamDefinition{
{
Code: "total",
Name: "总数",
Description: "连接总数",
},
},
},
{
Code: NodeValueItemRequests,
Name: "请求数",
Description: "平均每分钟请求数",
Params: []*nodeValueItemParamDefinition{
{
Code: "total",
Name: "总数",
Description: "请求总数",
},
},
},
{
Code: NodeValueItemAttackRequests,
Name: "攻击请求数",
Description: "平均每分钟攻击请求数",
Params: []*nodeValueItemParamDefinition{
{
Code: "total",
Name: "总数",
Description: "攻击请求总数",
},
},
},
{
Code: NodeValueItemDisk,
Name: "硬盘空间",
Params: []*nodeValueItemParamDefinition{
{
Code: "usage",
Name: "使用比例",
Description: "0到100之间的数字",
IsPercent: true,
},
},
},
{
Code: NodeValueItemNetworkPackets,
Name: "网络数据包",
Params: []*nodeValueItemParamDefinition{
{
Code: "tcpInPPS",
Name: "TCP入口包速率pps",
},
{
Code: "udpInPPS",
Name: "UDP入口包速率pps",
},
{
Code: "icmpInPPS",
Name: "ICMP入口包速率pps",
},
},
},
}
// FindAllNodeValueItemDefinitions 获取所有监控项信息
func FindAllNodeValueItemDefinitions() []*nodeValueItemDefinition {
return nodeValueItemDefinitions
}
// FindNodeValueItemName 获取监控项名称
func FindNodeValueItemName(code NodeValueItem) string {
for _, def := range nodeValueItemDefinitions {
if def.Code == code {
return def.Name
}
}
return ""
}
// FindNodeValueItemParamName 获取监控项某个参数的名称
func FindNodeValueItemParamName(nodeCode NodeValueItem, paramCode string) string {
for _, def := range nodeValueItemDefinitions {
if def.Code == nodeCode {
for _, p := range def.Params {
if p.Code == paramCode {
return p.Name
}
}
return ""
}
}
return ""
}
// CheckNodeValueItemParamIsPercent 判断监控项某个参数是否支持百分比
func CheckNodeValueItemParamIsPercent(nodeCode NodeValueItem, paramCode string) bool {
for _, def := range nodeValueItemDefinitions {
if def.Code == nodeCode {
for _, p := range def.Params {
if p.Code == paramCode {
return p.IsPercent
}
}
return false
}
}
return false
}
// NodeValueRange 值范围
type NodeValueRange = string
const (
NodeValueRangeMinute NodeValueRange = "minute"
)
// NodeValueOperator 操作符
type NodeValueOperator = string
const (
NodeValueOperatorGt NodeValueOperator = "gt" // 大于
NodeValueOperatorGte NodeValueOperator = "gte" // 大于等于
NodeValueOperatorLt NodeValueOperator = "lt" // 小于
NodeValueOperatorLte NodeValueOperator = "lte" // 小于等于
NodeValueOperatorEq NodeValueOperator = "eq" // 等于
NodeValueOperatorNeq NodeValueOperator = "neq" // 不等于
)
type nodeValueOperatorDefinition struct {
Code string `json:"code"`
Name string `json:"name"`
}
var nodeValueOperatorDefinitions = []*nodeValueOperatorDefinition{
{
Code: NodeValueOperatorGt,
Name: "大于",
},
{
Code: NodeValueOperatorGte,
Name: "大于等于",
},
{
Code: NodeValueOperatorLt,
Name: "小于",
},
{
Code: NodeValueOperatorLte,
Name: "小于等于",
},
{
Code: NodeValueOperatorEq,
Name: "等于",
},
{
Code: NodeValueOperatorNeq,
Name: "不等于",
},
}
// FindNodeValueOperatorName 操作符名称
func FindNodeValueOperatorName(operator NodeValueOperator) string {
for _, def := range nodeValueOperatorDefinitions {
if def.Code == operator {
return def.Name
}
}
return ""
}
// FindAllNodeValueOperatorDefinitions 获取所有操作符定义
func FindAllNodeValueOperatorDefinitions() []*nodeValueOperatorDefinition {
return nodeValueOperatorDefinitions
}
// CompareNodeValue 对比值
func CompareNodeValue(operator NodeValueOperator, value1 float64, value2 float64) bool {
switch operator {
case NodeValueOperatorGt:
return value1 > value2
case NodeValueOperatorGte:
return value1 >= value2
case NodeValueOperatorLt:
return value1 < value2
case NodeValueOperatorLte:
return value1 <= value2
case NodeValueOperatorEq:
return value1 == value2
case NodeValueOperatorNeq:
return value1 != value2
}
return false
}
// NodeValueSumMethod 聚合方法
type NodeValueSumMethod = string
const (
NodeValueSumMethodSum NodeValueSumMethod = "sum" // 相加
NodeValueSumMethodAvg NodeValueSumMethod = "avg" // 平均
)
// FindNodeValueSumMethodName 聚合方法名称
func FindNodeValueSumMethodName(method NodeValueSumMethod) string {
switch method {
case NodeValueSumMethodSum:
return "和"
case NodeValueSumMethodAvg:
return "平均"
}
return ""
}
// NodeValueDurationUnit 时间单位
type NodeValueDurationUnit = string
const (
NodeValueDurationUnitMinute NodeValueDurationUnit = "minute"
)
// FindNodeValueDurationUnitName 时间单位名称
func FindNodeValueDurationUnitName(unit NodeValueDurationUnit) string {
switch unit {
case NodeValueDurationUnitMinute:
return "分钟"
}
return ""
}
// UnmarshalNodeValue 对值进行解码
func UnmarshalNodeValue(valueJSON []byte) string {
var result = ""
err := json.Unmarshal(valueJSON, &result)
if err != nil {
// 暂时不提示错误
}
return result
}

View File

@@ -0,0 +1,160 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
import "github.com/iwind/TeaGo/maps"
type IPAddressThresholdItem = string
const (
IPAddressThresholdItemNodeAvgRequests IPAddressThresholdItem = "nodeAvgRequests" // 个
IPAddressThresholdItemNodeAvgTrafficOut IPAddressThresholdItem = "nodeAvgTrafficOut" // 节点下行流量 M
IPAddressThresholdItemNodeAvgTrafficIn IPAddressThresholdItem = "nodeAvgTrafficIn" // 节点上行流量 M
IPAddressThresholdItemNodeHealthCheck IPAddressThresholdItem = "nodeHealthCheck" // 节点健康检查结果
IPAddressThresholdItemGroupAvgRequests IPAddressThresholdItem = "groupAvgRequests" // 个
IPAddressThresholdItemGroupAvgTrafficIn IPAddressThresholdItem = "groupAvgTrafficIn" // 分组上行流量 M
IPAddressThresholdItemGroupAvgTrafficOut IPAddressThresholdItem = "groupAvgTrafficOut" // 分组下行流量 M
IPAddressThresholdItemClusterAvgRequests IPAddressThresholdItem = "clusterAvgRequests" // 个
IPAddressThresholdItemClusterAvgTrafficIn IPAddressThresholdItem = "clusterAvgTrafficIn" // 集群上行流量 M
IPAddressThresholdItemClusterAvgTrafficOut IPAddressThresholdItem = "clusterAvgTrafficOut" // 集群下行流量 M
IPAddressThresholdItemConnectivity IPAddressThresholdItem = "connectivity" // 0-100
)
// FindAllIPAddressThresholdItems IP相关阈值项目
func FindAllIPAddressThresholdItems() []maps.Map {
return []maps.Map{
{
"name": "节点平均请求数",
"code": IPAddressThresholdItemNodeAvgRequests,
"description": "当前节点在单位时间内接收到的平均请求数。",
"unit": "个",
},
{
"name": "节点平均下行流量",
"code": IPAddressThresholdItemNodeAvgTrafficOut,
"description": "当前节点在单位时间内发送的下行流量。",
"unit": "M",
},
{
"name": "节点平均上行流量",
"code": IPAddressThresholdItemNodeAvgTrafficIn,
"description": "当前节点在单位时间内接收的上行流量。",
"unit": "M",
},
{
"name": "节点健康检查结果",
"code": IPAddressThresholdItemNodeHealthCheck,
"description": "当前节点健康检查结果。",
"unit": "",
},
{
"name": "IP连通性",
"code": IPAddressThresholdItemConnectivity,
"description": "通过区域监控得到的当前IP地址的连通性数值取值在0和100之间。",
"unit": "%",
},
{
"name": "分组平均请求数",
"code": IPAddressThresholdItemGroupAvgRequests,
"description": "当前节点所在分组在单位时间内接收到的平均请求数。",
"unit": "个",
},
{
"name": "分组平均下行流量",
"code": IPAddressThresholdItemGroupAvgTrafficOut,
"description": "当前节点所在分组在单位时间内发送的下行流量。",
"unit": "M",
},
{
"name": "分组平均上行流量",
"code": IPAddressThresholdItemGroupAvgTrafficIn,
"description": "当前节点所在分组在单位时间内接收的上行流量。",
"unit": "M",
},
{
"name": "集群平均请求数",
"code": IPAddressThresholdItemClusterAvgRequests,
"description": "当前节点所在集群在单位时间内接收到的平均请求数。",
"unit": "个",
},
{
"name": "集群平均下行流量",
"code": IPAddressThresholdItemClusterAvgTrafficOut,
"description": "当前节点所在集群在单位时间内发送的下行流量。",
"unit": "M",
},
{
"name": "集群平均上行流量",
"code": IPAddressThresholdItemClusterAvgTrafficIn,
"description": "当前节点所在集群在单位时间内接收的上行流量。",
"unit": "M",
},
}
}
// IPAddressThresholdConfig 阈值列表
type IPAddressThresholdConfig struct {
Id int64 `json:"id"`
Items []*IPAddressThresholdItemConfig `json:"items"`
Actions []*IPAddressThresholdActionConfig `json:"actions"`
}
// IPAddressThresholdItemConfig 阈值项目
type IPAddressThresholdItemConfig struct {
Item IPAddressThresholdItem `json:"item"`
Operator NodeValueOperator `json:"operator"`
Value float64 `json:"value"`
Duration int `json:"duration"`
DurationUnit NodeValueDurationUnit `json:"durationUnit"`
Options maps.Map `json:"options"` // 附加选项
}
type IPAddressThresholdActionConfig struct {
Action string `json:"action"`
Options maps.Map `json:"options"`
}
// IPAddressThresholdAction 动作
type IPAddressThresholdAction = string
const (
IPAddressThresholdActionUp IPAddressThresholdAction = "up" // 上线
IPAddressThresholdActionDown IPAddressThresholdAction = "down" // 下线
IPAddressThresholdActionNotify IPAddressThresholdAction = "notify" // 通知
IPAddressThresholdActionSwitch IPAddressThresholdAction = "switch" // 切换到备用IP
IPAddressThresholdActionWebHook IPAddressThresholdAction = "webHook" // 调用外部Webhook
)
// FindAllIPAddressThresholdActions IP相关阈值动作
func FindAllIPAddressThresholdActions() []maps.Map {
return []maps.Map{
{
"name": "上线",
"code": IPAddressThresholdActionUp,
"description": "上线当前IP。",
},
{
"name": "下线",
"code": IPAddressThresholdActionDown,
"description": "下线当前IP。",
},
{
"name": "通知",
"code": IPAddressThresholdActionNotify,
"description": "发送已达到阈值通知。",
},
{
"name": "切换",
"code": IPAddressThresholdActionSwitch,
"description": "在DNS中记录中将IP切换到指定的备用IP。",
},
{
"name": "WebHook",
"code": IPAddressThresholdActionWebHook,
"description": "调用外部的WebHook。",
},
}
}

View File

@@ -0,0 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
const DefaultProductName = "GoEdge"
// ProductConfig 产品相关设置
type ProductConfig struct {
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
}

View File

@@ -0,0 +1,19 @@
package nodeconfigs
type (
SystemServiceType = string
)
const (
// TODO 需要支持supervisor等常用daemon管理工具
SystemServiceTypeSystemd SystemServiceType = "systemd"
)
// Systemd配置
type SystemdServiceConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
Provides string `yaml:"provides" json:"provides"` // 提供者,可以是服务名
ShortDescription string `yaml:"shortDescription" json:"shortDescription"` // 短描述
Description string `yaml:"description" json:"description"` // 长描述
ExecPath string `yaml:"execPath" json:"execPath"` // 可执行文件的路径
}

View File

@@ -0,0 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeconfigs
func DefaultSSHParams() *SSHParams {
return &SSHParams{Port: 22}
}
type SSHParams struct {
Port int `json:"port"`
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package nodeconfigs
import (
"github.com/iwind/TeaGo/logs"
"testing"
"time"
)
func TestFindAllTimeZoneLocations(t *testing.T) {
var before = time.Now()
var locations = FindAllTimeZoneLocations()
t.Log(len(locations), "locations")
t.Logf("%.2f %s", time.Since(before).Seconds()*1000, "ms")
logs.PrintAsJSON(locations, t)
}

View File

@@ -0,0 +1,22 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package nodeconfigs
// NewTOAConfig 默认的TOA配置
func NewTOAConfig() *TOAConfig {
return &TOAConfig{}
}
// TOAConfig TOA相关配置
type TOAConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"`
}
func (this *TOAConfig) Init() error {
return nil
}
func (this *TOAConfig) RandLocalPort() uint16 {
return 0
}

View File

@@ -0,0 +1,110 @@
//go:build plus
package nodeconfigs
import (
"fmt"
"github.com/iwind/TeaGo/rands"
"net"
"runtime"
)
// NewTOAConfig 默认的TOA配置
func NewTOAConfig() *TOAConfig {
return &TOAConfig{
IsOn: false,
Debug: false,
OptionTypeV4: 0xfe,
OptionTypeV6: 0xfe,
MinQueueId: 100,
AutoSetup: true,
}
}
// TOAConfig TOA相关配置
type TOAConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
Debug bool `yaml:"debug" json:"debug"`
OldOptionType uint8 `yaml:"optionType" json:"optionType"` // Deprecated 已过期,使用 OptionTypeV4 和 OptionTypeV6 代替
OptionTypeV4 uint8 `yaml:"optionTypeV4" json:"optionTypeV4"` // IPv4的类型
OptionTypeV6 uint8 `yaml:"OptionTypeV6" json:"optionTypeV6"`
MinQueueId uint8 `yaml:"minQueueId" json:"minQueueId"`
AutoSetup bool `yaml:"autoSetup" json:"autoSetup"`
MinLocalPort uint16 `yaml:"minLocalPort" json:"minLocalPort"` // 本地可使用的最小端口 TODO
MaxLocalPort uint16 `yaml:"maxLocalPort" json:"maxLocalPort"` // 本地可使用的最大端口 TODO
SockPath string `yaml:"sockPath" json:"sockPath"` // Sock文件路径 TODO
ByPassPorts []uint16 `yaml:"byPassPorts" json:"byPassPorts"` // 忽略的端口 TODO
minLocalPort int
maxLocalPort int
}
func (this *TOAConfig) Init() error {
// LocalPort
minPort := this.MinLocalPort
maxPort := this.MaxLocalPort
if minPort == 0 {
minPort = 1025
}
if maxPort == 0 {
maxPort = 65534
}
if minPort > maxPort {
minPort, maxPort = maxPort, minPort
}
this.minLocalPort = int(minPort)
this.maxLocalPort = int(maxPort)
// 兼容
if this.OptionTypeV4 == 0 && this.OldOptionType > 0 {
this.OptionTypeV4 = this.OldOptionType
}
if this.OptionTypeV6 == 0 && this.OldOptionType > 0 {
this.OptionTypeV6 = this.OldOptionType
}
return nil
}
// SockFile Sock路径
func (this *TOAConfig) SockFile() string {
if len(this.SockPath) == 0 {
return "/tmp/edge-toa.sock"
}
return this.SockPath
}
// RandLocalPort 获取随机端口
func (this *TOAConfig) RandLocalPort() uint16 {
listener, err := net.Listen("tcp", ":0")
if err != nil {
return uint16(rands.Int(this.minLocalPort, this.maxLocalPort))
}
_ = listener.Close()
return uint16(listener.Addr().(*net.TCPAddr).Port)
}
// AsArgs 转换为参数的形式
func (this *TOAConfig) AsArgs() (args []string) {
args = append(args, "run")
args = append(args, "-option-type-v4="+fmt.Sprintf("%d", this.OptionTypeV4))
args = append(args, "-option-type-v6="+fmt.Sprintf("%d", this.OptionTypeV6))
args = append(args, "-min-queue-id="+fmt.Sprintf("%d", this.MinQueueId))
args = append(args, "-max-queue-id="+fmt.Sprintf("%d", this.MaxQueueId()))
if this.AutoSetup {
args = append(args, "-auto-setup")
}
if this.Debug {
args = append(args, "-debug")
}
return
}
// MaxQueueId 获取队列ID最大值
func (this *TOAConfig) MaxQueueId() uint8 {
var maxQueueId = int(this.MinQueueId) + runtime.NumCPU() - 1
if maxQueueId > 255 {
maxQueueId = 255
}
return uint8(maxQueueId)
}

View File

@@ -0,0 +1,78 @@
//go:build plus
package nodeconfigs
import (
"net"
"runtime"
"testing"
"time"
)
func TestTOAConfig_RandLocalPort(t *testing.T) {
{
toa := &TOAConfig{}
err := toa.Init()
if err != nil {
t.Fatal(err)
}
t.Log(toa.RandLocalPort())
}
{
toa := &TOAConfig{
MinLocalPort: 1,
MaxLocalPort: 2,
}
err := toa.Init()
if err != nil {
t.Fatal(err)
}
t.Log(toa.RandLocalPort())
}
}
func TestTOAConfig_FreePort(t *testing.T) {
before := time.Now()
listener, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatal(err)
}
t.Log(listener.Addr())
_ = listener.Close()
t.Log(time.Since(before).Seconds()*1000, "ms")
time.Sleep(30 * time.Second)
}
func TestTOAConfig_AsArgs(t *testing.T) {
toa := &TOAConfig{
IsOn: false,
Debug: true,
OptionTypeV4: 0xfe,
OptionTypeV6: 0xfe,
MinQueueId: 10,
AutoSetup: true,
MinLocalPort: 0,
MaxLocalPort: 0,
SockPath: "",
ByPassPorts: nil,
}
err := toa.Init()
if err != nil {
t.Fatal(err)
}
t.Log(toa.AsArgs())
}
func BenchmarkTOAConfig_RandLocalPort(b *testing.B) {
runtime.GOMAXPROCS(1)
toa := &TOAConfig{
MinLocalPort: 1,
MaxLocalPort: 2,
}
_ = toa.Init()
for i := 0; i < b.N; i++ {
_ = toa.RandLocalPort()
}
}

View File

@@ -0,0 +1,16 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package nodeconfigs
func NewUAMPolicy() *UAMPolicy {
return &UAMPolicy{}
}
type UAMPolicy struct {
IsOn bool `yaml:"isOn" json:"isOn"`
}
func (this *UAMPolicy) Init() error {
return nil
}

View File

@@ -0,0 +1,46 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package nodeconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
func NewUAMPolicy() *UAMPolicy {
var policy = &UAMPolicy{
IsOn: true,
AllowSearchEngines: true,
IncludeSubdomains: true,
DenySpiders: true,
MaxFails: 30,
BlockSeconds: 1800,
UITitle: "",
UIBody: "",
KeyLife: 3600,
}
policy.Firewall.Scope = firewallconfigs.FirewallScopeGlobal
return policy
}
type UAMPolicy struct {
IsOn bool `yaml:"isOn" json:"isOn"`
AllowSearchEngines bool `yaml:"allowSearchEngines" json:"allowSearchEngines"` // 直接跳过常见搜索引擎
DenySpiders bool `yaml:"denySpiders" json:"denySpiders"` // 拦截常见爬虫
MaxFails int `yaml:"maxFails" json:"maxFails"` // 失败尝试次数
BlockSeconds int `yaml:"blockSeconds" json:"blockSeconds"` // 失败拦截秒数
IncludeSubdomains bool `yaml:"includeSubdomains" json:"includeSubdomains"` // 是否包含子域名
UITitle string `yaml:"uiTitle" json:"uiTitle"` // 页面标题
UIBody string `yaml:"uiBody" json:"uiBody"` // 页面内容
KeyLife int `yaml:"keyLife" json:"keyLife"` // Key有效期
// 防火墙策略
Firewall struct {
Scope firewallconfigs.FirewallScope `json:"scope" yaml:"scope"`
} `json:"firewall" yaml:"firewall"`
}
func (this *UAMPolicy) Init() error {
return nil
}