From 201edf2de5676299dc2c4a1d1c60ae6ca0a39b56 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Fri, 2 Sep 2022 11:52:29 +0800 Subject: [PATCH] add backup filter --- chain/selector.go | 36 ++++++++++- metadata/util/util.go | 139 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 metadata/util/util.go diff --git a/chain/selector.go b/chain/selector.go index 1ca334a..6021c11 100644 --- a/chain/selector.go +++ b/chain/selector.go @@ -7,6 +7,7 @@ import ( "time" "github.com/go-gost/core/metadata" + mdutil "github.com/go-gost/core/metadata/util" ) // default options for FailFilter @@ -131,8 +132,8 @@ type failFilter[T Selectable] struct { failTimeout time.Duration } -// FailFilter filters the dead node. -// A node is marked as dead if its failed count is greater than MaxFails. +// FailFilter filters the dead objects. +// An object is marked as dead if its failed count is greater than MaxFails. func FailFilter[T Selectable](maxFails int, timeout time.Duration) Filter[T] { return &failFilter[T]{ maxFails: maxFails, @@ -140,7 +141,7 @@ func FailFilter[T Selectable](maxFails int, timeout time.Duration) Filter[T] { } } -// Filter filters dead nodes. +// Filter filters dead objects. func (f *failFilter[T]) Filter(vs ...T) []T { maxFails := f.maxFails failTimeout := f.failTimeout @@ -165,6 +166,35 @@ func (f *failFilter[T]) Filter(vs ...T) []T { return l } +type backupFilter[T Selectable] struct{} + +// BackupFilter filters the backup objects. +// An object is marked as backup if its metadata has backup flag. +func BackupFilter[T Selectable]() Filter[T] { + return &backupFilter[T]{} +} + +// Filter filters backup objects. +func (f *backupFilter[T]) Filter(vs ...T) []T { + if len(vs) <= 1 { + return vs + } + + var l, backups []T + for _, v := range vs { + if mdutil.GetBool(v.Metadata(), "backup") { + backups = append(backups, v) + } else { + l = append(l, v) + } + } + + if len(l) == 0 { + return backups + } + return l +} + type Marker interface { Time() time.Time Count() int64 diff --git a/metadata/util/util.go b/metadata/util/util.go new file mode 100644 index 0000000..c45dd21 --- /dev/null +++ b/metadata/util/util.go @@ -0,0 +1,139 @@ +package util + +import ( + "fmt" + "strconv" + "time" + + "github.com/go-gost/core/metadata" +) + +func GetBool(md metadata.Metadata, key string) (v bool) { + if md == nil || !md.IsExists(key) { + return + } + switch vv := md.Get(key).(type) { + case bool: + return vv + case int: + return vv != 0 + case string: + v, _ = strconv.ParseBool(vv) + return + } + return +} + +func GetInt(md metadata.Metadata, key string) (v int) { + if md == nil || !md.IsExists(key) { + return + } + + switch vv := md.Get(key).(type) { + case bool: + if vv { + v = 1 + } + case int: + return vv + case string: + v, _ = strconv.Atoi(vv) + return + } + return +} + +func GetFloat(md metadata.Metadata, key string) (v float64) { + if md == nil || !md.IsExists(key) { + return + } + + switch vv := md.Get(key).(type) { + case int: + return float64(vv) + case string: + v, _ = strconv.ParseFloat(vv, 64) + return + } + return +} + +func GetDuration(md metadata.Metadata, key string) (v time.Duration) { + if md == nil || !md.IsExists(key) { + return + } + + switch vv := md.Get(key).(type) { + case int: + return time.Duration(vv) * time.Second + case string: + v, _ = time.ParseDuration(vv) + if v == 0 { + n, _ := strconv.Atoi(vv) + v = time.Duration(n) * time.Second + } + } + return +} + +func GetString(md metadata.Metadata, key string) (v string) { + if md != nil { + v, _ = md.Get(key).(string) + } + return +} + +func GetStrings(md metadata.Metadata, key string) (ss []string) { + if md == nil || !md.IsExists(key) { + return + } + + switch v := md.Get(key).(type) { + case []string: + ss = v + case []any: + for _, vv := range v { + if s, ok := vv.(string); ok { + ss = append(ss, s) + } + } + } + return +} + +func GetStringMap(md metadata.Metadata, key string) (m map[string]any) { + if md == nil || !md.IsExists(key) { + return + } + + switch vv := md.Get(key).(type) { + case map[string]any: + return vv + case map[any]any: + m = make(map[string]any) + for k, v := range vv { + m[fmt.Sprintf("%v", k)] = v + } + } + return +} + +func GetStringMapString(md metadata.Metadata, key string) (m map[string]string) { + if md == nil || !md.IsExists(key) { + return + } + + switch vv := md.Get(key).(type) { + case map[string]any: + m = make(map[string]string) + for k, v := range vv { + m[k] = fmt.Sprintf("%v", v) + } + case map[any]any: + m = make(map[string]string) + for k, v := range vv { + m[fmt.Sprintf("%v", k)] = fmt.Sprintf("%v", v) + } + } + return +}