Files
APIPark/strategy-filter/filter.go
T
2024-11-26 23:44:00 +08:00

193 lines
4.3 KiB
Go

package strategy_filter
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/eolinker/eosc"
strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto"
)
var (
filterHandler = NewHandler()
)
type Option struct {
Name string
Title string
Type string
Pattern *regexp.Regexp
Options []string
}
const (
TypeRemote = "remote"
TypePattern = "pattern"
TypeStatic = "static"
ValuesALL = "ALL"
ScopeGlobal = "global"
ScopeTeam = "team"
ScopeService = "service"
)
const (
HttpALL = "ALL"
)
func CheckFilters(name string, scope strategy_dto.Scope, filters []*strategy_dto.Filter) error {
fs, ok := filterHandler.Options(scope.String())
if !ok {
return fmt.Errorf("unknown scope %s", scope)
}
filterNameSet := make(map[string]struct{})
for _, filter := range filters {
op, ok := fs[filter.Name]
if !ok {
return fmt.Errorf("%s filter %s not found", name, filter.Name)
}
for _, value := range filter.Values {
if op.Pattern != nil && !op.Pattern.MatchString(value) {
return fmt.Errorf("%s filter %s value %s not match pattern", name, filter.Name, value)
}
}
if len(filter.Values) == 0 {
return fmt.Errorf("%s.Options can't be null. filter.Name:%s ", name, filter.Name)
}
if _, has := filterNameSet[filter.Name]; has {
return fmt.Errorf("%s.Name %s is reduplicative. ", name, filter.Name)
}
filterNameSet[filter.Name] = struct{}{}
}
return nil
}
type OptionTitle struct {
Field string `json:"field"`
Title string `json:"title" aoi18n:""`
}
type IRemoteFilter interface {
IFilter
Titles() []OptionTitle
Key() string
Target() string
RemoteList(ctx context.Context, keyword string, condition map[string]interface{}, page int, pageSize int) ([]any, int64, error)
}
type IFilter interface {
Name() string
Title() string
Labels(values ...string) []string
Type() string
Scopes() []string
Option() *Option
}
type IFilterHandler interface {
RemoteFilter(name string) (IRemoteFilter, bool)
Options(scope string) (map[string]*Option, bool)
FilterLabel(name string, values []string) (*Info, error)
}
type Info struct {
Title string
Label string
}
type ScopeFilterOption eosc.Untyped[string, *Option]
type Handler struct {
filters eosc.Untyped[string, IFilter]
remoteFilters eosc.Untyped[string, IRemoteFilter]
options eosc.Untyped[string, ScopeFilterOption]
}
func NewHandler() *Handler {
return &Handler{
filters: eosc.BuildUntyped[string, IFilter](),
remoteFilters: eosc.BuildUntyped[string, IRemoteFilter](),
options: eosc.BuildUntyped[string, ScopeFilterOption](),
}
}
func (f *Handler) RemoteFilter(name string) (IRemoteFilter, bool) {
return f.remoteFilters.Get(name)
}
func (f *Handler) RegisterRemoteFilter(filter IRemoteFilter) {
f.remoteFilters.Set(filter.Name(), filter)
f.setScopes(filter)
}
func (f *Handler) RegisterFilter(filter IFilter) {
f.filters.Set(filter.Name(), filter)
f.setScopes(filter)
}
func (f *Handler) setScopes(filter IFilter) {
for _, scope := range filter.Scopes() {
tmp, has := f.options.Get(scope)
if !has {
tmp = eosc.BuildUntyped[string, *Option]()
f.options.Set(scope, tmp)
}
tmp.Set(filter.Name(), filter.Option())
}
}
func (f *Handler) Options(scope string) (map[string]*Option, bool) {
options, has := f.options.Get(scope)
if !has {
return nil, false
}
return options.All(), true
}
func (f *Handler) FilterLabel(name string, values []string) (*Info, error) {
if tmp, has := f.remoteFilters.Get(name); has {
return &Info{
Title: tmp.Title(),
Label: strings.Join(tmp.Labels(values...), ","),
}, nil
}
if tmp, has := f.filters.Get(name); has {
return &Info{
Title: tmp.Title(),
Label: strings.Join(tmp.Labels(values...), ","),
}, nil
}
return nil, fmt.Errorf("filter %s not found", name)
}
func RegisterRemoteFilter(filter IRemoteFilter) {
filterHandler.RegisterRemoteFilter(filter)
}
func RemoteFilter(name string) (IRemoteFilter, bool) {
return filterHandler.RemoteFilter(name)
}
func Options(scope string) (map[string]*Option, bool) {
return filterHandler.Options(scope)
}
func FilterLabel(name string, values []string) (*Info, error) {
return filterHandler.FilterLabel(name, values)
}
func FilterGet(name string) (IFilter, bool) {
f, has := filterHandler.remoteFilters.Get(name)
if has {
return f, true
}
return filterHandler.filters.Get(name)
}