diff --git a/internal/nodes/node.go b/internal/nodes/node.go index 900d4f0..8f9220f 100644 --- a/internal/nodes/node.go +++ b/internal/nodes/node.go @@ -10,6 +10,7 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" "github.com/TeaOSLab/EdgeNode/internal/caches" "github.com/TeaOSLab/EdgeNode/internal/configs" "github.com/TeaOSLab/EdgeNode/internal/conns" @@ -25,6 +26,7 @@ import ( "github.com/TeaOSLab/EdgeNode/internal/trackers" "github.com/TeaOSLab/EdgeNode/internal/utils" _ "github.com/TeaOSLab/EdgeNode/internal/utils/clock" // 触发时钟更新 + "github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils" "github.com/TeaOSLab/EdgeNode/internal/waf" "github.com/andybalholm/brotli" "github.com/iwind/TeaGo/Tea" @@ -59,9 +61,13 @@ type Node struct { sock *gosock.Sock locker sync.Mutex - maxCPU int32 - maxThreads int - timezone string + oldMaxCPU int32 + oldMaxThreads int + oldTimezone string + oldHTTPCachePolicies []*serverconfigs.HTTPCachePolicy + oldHTTPFirewallPolicies []*firewallconfigs.HTTPFirewallPolicy + oldFirewallActions []*firewallconfigs.FirewallActionConfig + oldMetricItems []*serverconfigs.MetricItemConfig updatingServerMap map[int64]*serverconfigs.ServerConfig @@ -74,8 +80,8 @@ type Node struct { func NewNode() *Node { return &Node{ sock: gosock.NewTmpSock(teaconst.ProcessName), - maxThreads: -1, - maxCPU: -1, + oldMaxThreads: -1, + oldMaxCPU: -1, updatingServerMap: map[int64]*serverconfigs.ServerConfig{}, } } @@ -195,7 +201,7 @@ func (this *Node) Start() { } } sharedNodeConfig = nodeConfig - this.onReload(nodeConfig) + this.onReload(nodeConfig, true) // 发送事件 events.Notify(events.EventLoaded) @@ -601,7 +607,7 @@ func (this *Node) syncConfig(taskVersion int64) error { remotelogs.Println("NODE", "loading config ...") } - this.onReload(nodeConfig) + this.onReload(nodeConfig, true) // 发送事件 events.Notify(events.EventReload) @@ -977,15 +983,16 @@ func (this *Node) listenSock() error { } // 重载配置调用 -func (this *Node) onReload(config *nodeconfigs.NodeConfig) { +func (this *Node) onReload(config *nodeconfigs.NodeConfig, reloadAll bool) { nodeconfigs.ResetNodeConfig(config) sharedNodeConfig = config - // 缓存策略 - caches.SharedManager.MaxDiskCapacity = config.MaxCacheDiskCapacity - caches.SharedManager.MaxMemoryCapacity = config.MaxCacheMemoryCapacity - caches.SharedManager.MainDiskDir = config.CacheDiskDir + // 不需要每次都全部重新加载 + if !reloadAll { + return + } + // 缓存策略 var subDirs = config.CacheDiskSubDirs for _, subDir := range subDirs { subDir.Path = filepath.Clean(subDir.Path) @@ -995,23 +1002,75 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) { return subDirs[i].Path < subDirs[j].Path }) } + + var cachePoliciesChanged = !jsonutils.Equal(caches.SharedManager.MaxDiskCapacity, config.MaxCacheDiskCapacity) || + !jsonutils.Equal(caches.SharedManager.MaxMemoryCapacity, config.MaxCacheMemoryCapacity) || + !jsonutils.Equal(caches.SharedManager.MainDiskDir, config.CacheDiskDir) || + !jsonutils.Equal(caches.SharedManager.SubDiskDirs, subDirs) || + !jsonutils.Equal(this.oldHTTPCachePolicies, config.HTTPCachePolicies) + + caches.SharedManager.MaxDiskCapacity = config.MaxCacheDiskCapacity + caches.SharedManager.MaxMemoryCapacity = config.MaxCacheMemoryCapacity + caches.SharedManager.MainDiskDir = config.CacheDiskDir caches.SharedManager.SubDiskDirs = subDirs - if len(config.HTTPCachePolicies) > 0 { - caches.SharedManager.UpdatePolicies(config.HTTPCachePolicies) - } else { - caches.SharedManager.UpdatePolicies([]*serverconfigs.HTTPCachePolicy{}) + if cachePoliciesChanged { + // copy + this.oldHTTPCachePolicies = []*serverconfigs.HTTPCachePolicy{} + err := jsonutils.Copy(&this.oldHTTPCachePolicies, config.HTTPCachePolicies) + if err != nil { + remotelogs.Error("NODE", "onReload: copy HTTPCachePolicies failed: "+err.Error()) + } + + // update + if len(config.HTTPCachePolicies) > 0 { + caches.SharedManager.UpdatePolicies(config.HTTPCachePolicies) + } else { + caches.SharedManager.UpdatePolicies([]*serverconfigs.HTTPCachePolicy{}) + } } // WAF策略 - waf.SharedWAFManager.UpdatePolicies(config.FindAllFirewallPolicies()) - iplibrary.SharedActionManager.UpdateActions(config.FirewallActions) + var allFirewallPolicies = config.FindAllFirewallPolicies() + if !jsonutils.Equal(allFirewallPolicies, this.oldHTTPFirewallPolicies) { + // copy + this.oldHTTPFirewallPolicies = []*firewallconfigs.HTTPFirewallPolicy{} + err := jsonutils.Copy(&this.oldHTTPFirewallPolicies, allFirewallPolicies) + if err != nil { + remotelogs.Error("NODE", "onReload: copy HTTPFirewallPolicies failed: "+err.Error()) + } + + // update + waf.SharedWAFManager.UpdatePolicies(allFirewallPolicies) + } + + if !jsonutils.Equal(config.FirewallActions, this.oldFirewallActions) { + // copy + this.oldFirewallActions = []*firewallconfigs.FirewallActionConfig{} + err := jsonutils.Copy(&this.oldFirewallActions, config.FirewallActions) + if err != nil { + remotelogs.Error("NODE", "onReload: copy FirewallActionConfigs failed: "+err.Error()) + } + + // update + iplibrary.SharedActionManager.UpdateActions(config.FirewallActions) + } // 统计指标 - metrics.SharedManager.Update(config.MetricItems) + if !jsonutils.Equal(this.oldMetricItems, config.MetricItems) { + // copy + this.oldMetricItems = []*serverconfigs.MetricItemConfig{} + err := jsonutils.Copy(&this.oldMetricItems, config.MetricItems) + if err != nil { + remotelogs.Error("NODE", "onReload: copy MetricItemConfigs failed: "+err.Error()) + } + + // update + metrics.SharedManager.Update(config.MetricItems) + } // max cpu - if config.MaxCPU != this.maxCPU { + if config.MaxCPU != this.oldMaxCPU { if config.MaxCPU > 0 && config.MaxCPU < int32(runtime.NumCPU()) { runtime.GOMAXPROCS(int(config.MaxCPU)) remotelogs.Println("NODE", "[CPU]set max cpu to '"+types.String(config.MaxCPU)+"'") @@ -1021,11 +1080,11 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) { remotelogs.Println("NODE", "[CPU]set max cpu to '"+types.String(threads)+"'") } - this.maxCPU = config.MaxCPU + this.oldMaxCPU = config.MaxCPU } // max threads - if config.MaxThreads != this.maxThreads { + if config.MaxThreads != this.oldMaxThreads { if config.MaxThreads > 0 { debug.SetMaxThreads(config.MaxThreads) remotelogs.Println("NODE", "[THREADS]set max threads to '"+types.String(config.MaxThreads)+"'") @@ -1033,7 +1092,7 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) { debug.SetMaxThreads(nodeconfigs.DefaultMaxThreads) remotelogs.Println("NODE", "[THREADS]set max threads to '"+types.String(nodeconfigs.DefaultMaxThreads)+"'") } - this.maxThreads = config.MaxThreads + this.oldMaxThreads = config.MaxThreads } // timezone @@ -1042,7 +1101,7 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) { timeZone = "Asia/Shanghai" } - if this.timezone != timeZone { + if this.oldTimezone != timeZone { location, err := time.LoadLocation(timeZone) if err != nil { remotelogs.Error("NODE", "[TIMEZONE]change time zone failed: "+err.Error()) @@ -1051,7 +1110,7 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) { remotelogs.Println("NODE", "[TIMEZONE]change time zone to '"+timeZone+"'") time.Local = location - this.timezone = timeZone + this.oldTimezone = timeZone } // product information @@ -1118,7 +1177,7 @@ func (this *Node) reloadServer() { } } - this.onReload(newNodeConfig) + this.onReload(newNodeConfig, false) err = sharedListenerManager.Start(newNodeConfig) if err != nil { diff --git a/internal/utils/jsonutils/map.go b/internal/utils/jsonutils/map.go index 4986f3e..d4c4bcb 100644 --- a/internal/utils/jsonutils/map.go +++ b/internal/utils/jsonutils/map.go @@ -7,7 +7,7 @@ import ( "github.com/iwind/TeaGo/maps" ) -func MapToObject(m maps.Map, ptr interface{}) error { +func MapToObject(m maps.Map, ptr any) error { if m == nil { return nil } @@ -18,7 +18,7 @@ func MapToObject(m maps.Map, ptr interface{}) error { return json.Unmarshal(mJSON, ptr) } -func ObjectToMap(ptr interface{}) (maps.Map, error) { +func ObjectToMap(ptr any) (maps.Map, error) { if ptr == nil { return maps.Map{}, nil } @@ -33,3 +33,12 @@ func ObjectToMap(ptr interface{}) (maps.Map, error) { } return result, nil } + +func Copy(destPtr any, srcPtr any) error { + data, err := json.Marshal(srcPtr) + if err != nil { + return err + } + err = json.Unmarshal(data, destPtr) + return err +} diff --git a/internal/utils/jsonutils/utils.go b/internal/utils/jsonutils/utils.go index 5c37dfd..b955d28 100644 --- a/internal/utils/jsonutils/utils.go +++ b/internal/utils/jsonutils/utils.go @@ -3,11 +3,12 @@ package jsonutils import ( + "bytes" "encoding/json" "testing" ) -func PrintT(obj interface{}, t *testing.T) { +func PrintT(obj any, t *testing.T) { data, err := json.MarshalIndent(obj, "", " ") if err != nil { t.Log(err) @@ -15,3 +16,17 @@ func PrintT(obj interface{}, t *testing.T) { t.Log(string(data)) } } + +func Equal(obj1 any, obj2 any) bool { + data1, err := json.Marshal(obj1) + if err != nil { + return false + } + + data2, err := json.Marshal(obj2) + if err != nil { + return false + } + + return bytes.Equal(data1, data2) +} diff --git a/internal/utils/jsonutils/utils_test.go b/internal/utils/jsonutils/utils_test.go new file mode 100644 index 0000000..de4f061 --- /dev/null +++ b/internal/utils/jsonutils/utils_test.go @@ -0,0 +1,26 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package jsonutils_test + +import ( + "github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils" + "github.com/iwind/TeaGo/assert" + "github.com/iwind/TeaGo/maps" + "testing" +) + +func TestEqual(t *testing.T) { + var a = assert.NewAssertion(t) + + { + var m1 = maps.Map{"a": 1, "b2": true} + var m2 = maps.Map{"b2": true, "a": 1} + a.IsTrue(jsonutils.Equal(m1, m2)) + } + + { + var m1 = maps.Map{"a": 1, "b2": true, "c": nil} + var m2 = maps.Map{"b2": true, "a": 1} + a.IsFalse(jsonutils.Equal(m1, m2)) + } +}