From ce53bb2d47fad5eee20281ddccd162c9c2c45d2a Mon Sep 17 00:00:00 2001 From: Liujian <824010343@qq.com> Date: Thu, 21 Nov 2024 17:36:13 +0800 Subject: [PATCH] Initial submission of data desensitization strategy backend --- controller/strategy/iml.go | 99 ++++++++++ controller/strategy/strategy.go | 34 ++++ module/strategy/driver/data-masking/config.go | 22 +++ module/strategy/driver/data-masking/driver.go | 81 ++++++++ module/strategy/driver/data-masking/valid.go | 30 +++ module/strategy/driver/driver.go | 11 ++ module/strategy/driver/filter.go | 132 +++++++++++++ module/strategy/driver/manager.go | 52 +++++ module/strategy/dto/enum.go | 44 +++++ module/strategy/dto/input.go | 29 +++ module/strategy/dto/output.go | 73 +++++++ module/strategy/iml.go | 167 ++++++++++++++++ module/strategy/module.go | 29 +++ module/upstream/iml.go | 3 +- plugins/core/ai.go | 2 +- plugins/core/core.go | 4 + plugins/core/strategy.go | 25 +++ service/strategy/iml.go | 182 ++++++++++++++++++ service/strategy/model.go | 77 ++++++++ service/strategy/service.go | 35 ++++ service/universally/commit/iml.go | 21 +- service/universally/commit/service.go | 6 +- service/upstream/iml.go | 4 +- service/upstream/service.go | 2 +- stores/strategy/model.go | 30 +++ stores/strategy/store.go | 20 ++ 26 files changed, 1196 insertions(+), 18 deletions(-) create mode 100644 controller/strategy/iml.go create mode 100644 controller/strategy/strategy.go create mode 100644 module/strategy/driver/data-masking/config.go create mode 100644 module/strategy/driver/data-masking/driver.go create mode 100644 module/strategy/driver/data-masking/valid.go create mode 100644 module/strategy/driver/driver.go create mode 100644 module/strategy/driver/filter.go create mode 100644 module/strategy/driver/manager.go create mode 100644 module/strategy/dto/enum.go create mode 100644 module/strategy/dto/input.go create mode 100644 module/strategy/dto/output.go create mode 100644 module/strategy/iml.go create mode 100644 module/strategy/module.go create mode 100644 plugins/core/strategy.go create mode 100644 service/strategy/iml.go create mode 100644 service/strategy/model.go create mode 100644 service/strategy/service.go create mode 100644 stores/strategy/model.go create mode 100644 stores/strategy/store.go diff --git a/controller/strategy/iml.go b/controller/strategy/iml.go new file mode 100644 index 00000000..c8ed8c59 --- /dev/null +++ b/controller/strategy/iml.go @@ -0,0 +1,99 @@ +package strategy + +import ( + "encoding/json" + "fmt" + "strconv" + + "github.com/APIParkLab/APIPark/module/service" + "github.com/APIParkLab/APIPark/module/strategy" + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" + "github.com/gin-gonic/gin" +) + +var _ IStrategyController = (*imlStrategyController)(nil) + +type imlStrategyController struct { + strategyModule strategy.IStrategyModule `autowired:""` + serviceModule service.IServiceModule `autowired:""` +} + +func (i *imlStrategyController) GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error) { + return i.strategyModule.Get(ctx, id) +} + +func (i *imlStrategyController) search(ctx *gin.Context, keyword string, scope strategy_dto.Scope, target string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) { + p, err := strconv.Atoi(page) + if err != nil { + if page != "" { + return nil, 0, fmt.Errorf("page error: %s", err) + } + p = 1 + } + ps, err := strconv.Atoi(pageSize) + if err != nil { + if pageSize != "" { + return nil, 0, fmt.Errorf("page size error: %s", err) + } + ps = 20 + } + ss := make([]string, 0) + json.Unmarshal([]byte(sort), &ss) + fs := make([]string, 0) + json.Unmarshal([]byte(filters), &fs) + list, total, err := i.strategyModule.Search(ctx, keyword, driver, scope, target, p, ps, fs, ss...) + if err != nil { + return nil, 0, err + } + + return list, total, nil +} + +func (i *imlStrategyController) GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) { + + return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeSystem), "", driver, page, pageSize, order, sort, filters) +} + +func (i *imlStrategyController) CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error { + input.Driver = driver + input.Scope = strategy_dto.ToScope(strategy_dto.ScopeSystem) + + return i.strategyModule.Create(ctx, input) +} + +func (i *imlStrategyController) PublishGlobalStrategy(ctx *gin.Context) error { + return i.strategyModule.Publish(ctx, strategy_dto.ScopeSystem, "") +} + +func (i *imlStrategyController) ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) { + + return i.search(ctx, keyword, strategy_dto.ToScope(strategy_dto.ScopeService), serviceId, driver, page, pageSize, order, sort, filters) +} + +func (i *imlStrategyController) CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error { + _, err := i.serviceModule.Get(ctx, serviceId) + if err != nil { + return fmt.Errorf("create service strategy error: %s", err) + } + input.Driver = driver + input.Scope = strategy_dto.ToScope(strategy_dto.ScopeService) + input.Target = serviceId + + return i.strategyModule.Create(ctx, input) +} + +func (i *imlStrategyController) EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error { + return i.EditStrategy(ctx, id, input) +} + +func (i *imlStrategyController) EnableStrategy(ctx *gin.Context, id string) error { + return i.EnableStrategy(ctx, id) +} + +func (i *imlStrategyController) DisableStrategy(ctx *gin.Context, id string) error { + return i.strategyModule.Disable(ctx, id) +} + +func (i *imlStrategyController) DeleteStrategy(ctx *gin.Context, id string) error { + return i.strategyModule.Delete(ctx, id) +} diff --git a/controller/strategy/strategy.go b/controller/strategy/strategy.go new file mode 100644 index 00000000..8dbb04fb --- /dev/null +++ b/controller/strategy/strategy.go @@ -0,0 +1,34 @@ +package strategy + +import ( + "reflect" + + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" + "github.com/eolinker/go-common/autowire" + "github.com/gin-gonic/gin" +) + +type IStrategyController interface { + GlobalStrategyList(ctx *gin.Context, keyword string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) + CreateGlobalStrategy(ctx *gin.Context, driver string, input *strategy_dto.Create) error + PublishGlobalStrategy(ctx *gin.Context) error + + ServiceStrategyList(ctx *gin.Context, keyword string, serviceId string, driver string, page string, pageSize string, order string, sort string, filters string) ([]*strategy_dto.StrategyItem, int64, error) + CreateServiceStrategy(ctx *gin.Context, serviceId string, driver string, input *strategy_dto.Create) error + + EditStrategy(ctx *gin.Context, id string, input *strategy_dto.Edit) error + GetStrategy(ctx *gin.Context, id string) (*strategy_dto.Strategy, error) + EnableStrategy(ctx *gin.Context, id string) error + DisableStrategy(ctx *gin.Context, id string) error + + DeleteStrategy(ctx *gin.Context, id string) error +} + +type IStrategyCommonController interface { +} + +func init() { + autowire.Auto[IStrategyController](func() reflect.Value { + return reflect.ValueOf(&imlStrategyController{}) + }) +} diff --git a/module/strategy/driver/data-masking/config.go b/module/strategy/driver/data-masking/config.go new file mode 100644 index 00000000..7aa0df12 --- /dev/null +++ b/module/strategy/driver/data-masking/config.go @@ -0,0 +1,22 @@ +package data_masking + +type Config struct { + Rules []*Rule `json:"rules"` +} + +type Rule struct { + Match *BasicItem `json:"match"` + Mask *Mask `json:"mask"` +} + +type BasicItem struct { + Type string `json:"type"` + Value string `json:"value"` +} + +type Mask struct { + Type string `json:"type"` + Begin int `json:"begin"` + Length int `json:"length"` + Replace *BasicItem `json:"replace"` +} diff --git a/module/strategy/driver/data-masking/driver.go b/module/strategy/driver/data-masking/driver.go new file mode 100644 index 00000000..f3608d82 --- /dev/null +++ b/module/strategy/driver/data-masking/driver.go @@ -0,0 +1,81 @@ +package data_masking + +import ( + "encoding/json" + "errors" + "fmt" + + strategy_driver "github.com/APIParkLab/APIPark/module/strategy/driver" + + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" +) + +func init() { + strategy_driver.Register(&strategyDriver{confName: "data_mask"}) +} + +type strategyDriver struct { + confName string +} + +func (d *strategyDriver) Driver() string { + return "data-masking" +} + +func (d *strategyDriver) ToApinto(s strategy_dto.Strategy) interface{} { + filters := make(map[string][]string) + + for _, f := range s.Filters { + filters[f.Name] = f.Values + } + + return map[string]interface{}{ + "name": s.Filters, + "description": s.Desc, + "priority": s.Priority, + "filters": filters, + d.confName: s.Config, + } +} + +func (d *strategyDriver) Check(config interface{}) error { + if config == nil { + return nil + } + data, err := json.Marshal(config) + if err != nil { + return err + } + var cfg Config + err = json.Unmarshal(data, &cfg) + if err != nil { + return err + } + for _, r := range cfg.Rules { + if r.Match == nil { + return errors.New("match can't be null. ") + } + if r.Mask == nil { + return errors.New("mask can't be null. ") + } + + if _, ok := validMatchTypes[r.Match.Type]; !ok { + return fmt.Errorf("match type %s is illegal. ", r.Match.Type) + } + + if r.Match.Type == "inner" { + if _, ok := validMatchInnerValues[r.Match.Value]; !ok { + return fmt.Errorf("match value %s is illegal. ", r.Match.Value) + } + } + if _, ok := validMaskTypes[r.Mask.Type]; !ok { + return fmt.Errorf("mask type %s is illegal. ", r.Mask.Type) + } + if r.Mask.Replace != nil { + if _, ok := validReplaceTypes[r.Mask.Replace.Type]; !ok { + return fmt.Errorf("replace type %s is illegal. ", r.Mask.Replace.Type) + } + } + } + return nil +} diff --git a/module/strategy/driver/data-masking/valid.go b/module/strategy/driver/data-masking/valid.go new file mode 100644 index 00000000..1f018c93 --- /dev/null +++ b/module/strategy/driver/data-masking/valid.go @@ -0,0 +1,30 @@ +package data_masking + +var validMatchInnerValues = map[string]struct{}{ + "name": {}, + "phone": {}, + "email": {}, + "id-card": {}, + "bank-card": {}, + "date": {}, + "amount": {}, +} +var validMatchTypes = map[string]struct{}{ + "inner": {}, + "keyword": {}, + "regex": {}, + "json_path": {}, +} + +var validMaskTypes = map[string]struct{}{ + "partial-display": {}, + "partial-masking": {}, + "truncation": {}, + "replacement": {}, + "shuffling": {}, +} + +var validReplaceTypes = map[string]struct{}{ + "random": {}, + "custom": {}, +} diff --git a/module/strategy/driver/driver.go b/module/strategy/driver/driver.go new file mode 100644 index 00000000..1bb5e4a2 --- /dev/null +++ b/module/strategy/driver/driver.go @@ -0,0 +1,11 @@ +package strategy_driver + +import ( + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" +) + +type IStrategyDriver interface { + Driver() string + ToApinto(strategy strategy_dto.Strategy) interface{} + Check(config interface{}) error +} diff --git a/module/strategy/driver/filter.go b/module/strategy/driver/filter.go new file mode 100644 index 00000000..0fdd9b6a --- /dev/null +++ b/module/strategy/driver/filter.go @@ -0,0 +1,132 @@ +package strategy_driver + +import ( + "fmt" + "regexp" + + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" +) + +type FilterOptionsItem struct { + Name string + Title string + Type string + Pattern *regexp.Regexp + Options []string +} + +const ( + FilterMethod = "method" + FilterPath = "path" + FilterIP = "ip" + FilterApplication = "application" + FilterApi = "api" + FilterService = "service" + FilterAppKey = "appkey" + + FilterTypeRemote = "remote" + FilterTypePattern = "pattern" + FilterTypeStatic = "static" + + FilterValuesALL = "ALL" +) + +const ( + ApiPathRegexp = `^\*?[\w-/]+\*?$` + CIDRIpv4Exp = `^(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([1-9]|[1-2]\d|3[0-2]))?$` +) + +const ( + HttpALL = "ALL" + HttpGET = "GET" + HttpPOST = "POST" + HttpPUT = "PUT" + HttpDELETE = "DELETE" + HttpPATCH = "PATCH" + HttpHEADER = "HEADER" + HttpOPTIONS = "OPTIONS" +) + +var ( + staticOptions = []*FilterOptionsItem{ + { + Name: FilterMethod, + Title: "API请求方式", + Type: FilterTypeStatic, + Options: []string{HttpALL, HttpGET, HttpPOST, HttpPUT, HttpDELETE, HttpPATCH, HttpHEADER, HttpOPTIONS}, + }, { + Name: FilterPath, + Title: "API路径", + Type: FilterTypePattern, + Pattern: regexp.MustCompile(ApiPathRegexp), + }, { + Name: FilterIP, + Title: "IP", + Type: FilterTypePattern, + Pattern: regexp.MustCompile(CIDRIpv4Exp), + }, + } + globalFilters = map[string]struct{}{} + serviceFilters = map[string]struct{}{} +) + +func init() { + for _, option := range staticOptions { + globalFilters[option.Name] = struct{}{} + } + for _, option := range staticOptions { + serviceFilters[option.Name] = struct{}{} + } +} + +func CheckFilters(name string, scope strategy_dto.Scope, filters []*strategy_dto.Filter) error { + var fs map[string]struct{} + switch scope.String() { + case strategy_dto.ScopeSystem: + fs = globalFilters + case strategy_dto.ScopeService: + fs = serviceFilters + default: + return fmt.Errorf("unknown scope %s", scope) + } + filterNameSet := make(map[string]struct{}) + for _, filter := range filters { + _, ok := fs[filter.Name] + if !ok { + return fmt.Errorf("%s filter %s not found", name, filter.Name) + } + 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 FilterOptionConfig struct { + Title string + Titles []OptionTitle + Key string +} + +type IFilterOptionHandler interface { + Name() string + Config() FilterOptionConfig + GetOptions(keyword, conditions map[string]interface{}, pageNum, pageSize int) ([]any, int) + Labels(values ...string) []string + Label(value string) string +} + +type IFilterFactory interface { + GetHandler(name string) IFilterOptionHandler +} diff --git a/module/strategy/driver/manager.go b/module/strategy/driver/manager.go new file mode 100644 index 00000000..80e04187 --- /dev/null +++ b/module/strategy/driver/manager.go @@ -0,0 +1,52 @@ +package strategy_driver + +import ( + "fmt" + + "github.com/eolinker/eosc" +) + +var manager = newManager() + +func newManager() *Manager { + return &Manager{ + drivers: eosc.BuildUntyped[string, IStrategyDriver](), + } +} + +type Manager struct { + drivers eosc.Untyped[string, IStrategyDriver] +} + +func (m *Manager) AddDriver(driver IStrategyDriver) { + m.drivers.Set(driver.Driver(), driver) +} + +func (m *Manager) GetDriver(driver string) (IStrategyDriver, bool) { + return m.drivers.Get(driver) +} + +func (m *Manager) GetDrivers() []string { + return m.drivers.Keys() +} + +func (m *Manager) Delete(name string) { + m.drivers.Del(name) +} + +func GetDriver(name string) (IStrategyDriver, bool) { + return manager.GetDriver(name) +} + +func Register(driver IStrategyDriver) { + manager.AddDriver(driver) +} + +func CheckConfig(name string, config interface{}) error { + driver, has := manager.GetDriver(name) + if !has { + return fmt.Errorf("driver %s not found", name) + } + + return driver.Check(config) +} diff --git a/module/strategy/dto/enum.go b/module/strategy/dto/enum.go new file mode 100644 index 00000000..9ba86462 --- /dev/null +++ b/module/strategy/dto/enum.go @@ -0,0 +1,44 @@ +package strategy_dto + +const ( + ScopeSystem = "system" + ScopeTeam = "team" + ScopeService = "service" + + PublishStatusOnline = "online" + PublishStatusOffline = "offline" + PublishStatusUpdate = "update" + PublishStatusDelete = "delete" +) + +type Scope int + +func (s Scope) String() string { + switch s { + case 0: + return ScopeSystem + case 1: + return ScopeTeam + case 2: + return ScopeService + default: + return ScopeSystem + } +} + +func (s Scope) Int() int { + return int(s) +} + +func ToScope(s string) Scope { + switch s { + case ScopeSystem: + return 0 + case ScopeTeam: + return 1 + case ScopeService: + return 2 + default: + return 0 + } +} diff --git a/module/strategy/dto/input.go b/module/strategy/dto/input.go new file mode 100644 index 00000000..45bbd09e --- /dev/null +++ b/module/strategy/dto/input.go @@ -0,0 +1,29 @@ +package strategy_dto + +type Create struct { + Scope Scope `json:"-"` + Target string `json:"-"` + Driver string `json:"-"` + ID string `json:"id"` + Name string `json:"name"` + Priority int `json:"priority"` + Desc string `json:"desc"` + Filters []*Filter `json:"filters"` + Config interface{} `json:"config"` +} + +type Edit struct { + Name *string `json:"name"` + Priority *int `json:"priority"` + Desc *string `json:"desc"` + Filters *[]*Filter `json:"filters"` + Config *interface{} `json:"config"` +} + +type Filter struct { + Name string `json:"name"` + Values []string `json:"values"` + Type string `json:"type"` + Label string `json:"label"` + Title string `json:"title"` +} diff --git a/module/strategy/dto/output.go b/module/strategy/dto/output.go new file mode 100644 index 00000000..5c4727de --- /dev/null +++ b/module/strategy/dto/output.go @@ -0,0 +1,73 @@ +package strategy_dto + +import ( + "encoding/json" + + "github.com/APIParkLab/APIPark/service/strategy" + "github.com/eolinker/go-common/auto" +) + +func ToStrategyItem(s *strategy.Strategy, publishVersion string) *StrategyItem { + publishStatus := PublishStatusOffline + if publishVersion != "" { + if s.IsDelete { + publishStatus = PublishStatusDelete + } else { + version := s.UpdateAt.Format("20060102150405") + if version != publishVersion { + publishStatus = PublishStatusUpdate + } else { + publishStatus = PublishStatusOnline + } + } + } + return &StrategyItem{ + Id: s.Id, + Name: s.Name, + Priority: 0, + Desc: s.Desc, + Filters: "", + Updater: auto.UUID(s.Updater), + UpdateTime: auto.TimeLabel(s.UpdateAt), + ProcessedTotal: 0, + PublishStatus: publishStatus, + IsStop: s.IsStop, + } +} + +func ToStrategy(s *strategy.Strategy) *Strategy { + filters := make([]*Filter, 0) + json.Unmarshal([]byte(s.Filters), &filters) + var cfg interface{} + json.Unmarshal([]byte(s.Config), &cfg) + return &Strategy{ + Id: s.Id, + Name: s.Name, + Priority: s.Priority, + Desc: s.Desc, + Filters: filters, + Config: cfg, + } +} + +type Strategy struct { + Id string `json:"id"` + Name string `json:"name"` + Priority int `json:"priority"` + Desc string `json:"desc"` + Filters []*Filter `json:"filters"` + Config interface{} `json:"config"` +} + +type StrategyItem struct { + Id string `json:"id"` + Name string `json:"name"` + Priority int `json:"priority"` + Desc string `json:"desc"` + Filters string `json:"filters"` + Updater auto.Label `json:"updater" aolabel:"user"` + UpdateTime auto.TimeLabel `json:"update_time"` + ProcessedTotal int `json:"processed_total"` + PublishStatus string `json:"publish_status"` + IsStop bool `json:"is_stop"` +} diff --git a/module/strategy/iml.go b/module/strategy/iml.go new file mode 100644 index 00000000..c6e7c756 --- /dev/null +++ b/module/strategy/iml.go @@ -0,0 +1,167 @@ +package strategy + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/eolinker/go-common/store" + + "github.com/APIParkLab/APIPark/service/universally/commit" + + "github.com/eolinker/go-common/utils" + + "github.com/google/uuid" + + strategy_driver "github.com/APIParkLab/APIPark/module/strategy/driver" + + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" + + "github.com/APIParkLab/APIPark/service/strategy" +) + +var _ IStrategyModule = (*imlStrategyModule)(nil) + +type imlStrategyModule struct { + strategyService strategy.IStrategyService `autowired:""` + transaction store.ITransaction `autowired:""` +} + +func (i *imlStrategyModule) Search(ctx context.Context, keyword string, driver string, scope strategy_dto.Scope, target string, page int, pageSize int, filters []string, order ...string) ([]*strategy_dto.StrategyItem, int64, error) { + list, total, err := i.strategyService.Search(ctx, keyword, driver, scope.Int(), target, page, pageSize, filters, order...) + if err != nil { + return nil, 0, err + } + strategyIds := utils.SliceToSlice(list, func(l *strategy.Strategy) string { return l.Id }) + commits, err := i.strategyService.ListLatestStrategyCommit(ctx, scope.String(), target, strategyIds...) + if err != nil { + return nil, 0, err + } + commitMap := utils.SliceToMapO(commits, func(c *commit.Commit[strategy.StrategyCommit]) (string, string) { return c.Key, c.Data.Version }) + items := make([]*strategy_dto.StrategyItem, 0, len(list)) + for _, l := range list { + item := strategy_dto.ToStrategyItem(l, commitMap[l.Id]) + items = append(items, item) + } + return items, total, nil +} + +func (i *imlStrategyModule) Get(ctx context.Context, id string) (*strategy_dto.Strategy, error) { + info, err := i.strategyService.Get(ctx, id) + if err != nil { + return nil, err + } + return strategy_dto.ToStrategy(info), nil +} + +func (i *imlStrategyModule) Create(ctx context.Context, input *strategy_dto.Create) error { + if input.Name == "" { + return fmt.Errorf("name required") + } + if input.ID == "" { + input.ID = uuid.NewString() + } + + if input.Priority < 1 { + input.Priority = 1000 + } + err := strategy_driver.CheckFilters(input.Driver, input.Scope, input.Filters) + if err != nil { + return err + } + + err = strategy_driver.CheckConfig(input.Driver, input.Config) + if err != nil { + return err + } + filters, _ := json.Marshal(input.Filters) + cfg, _ := json.Marshal(input.Config) + return i.strategyService.Create(ctx, &strategy.Create{ + Id: input.ID, + Name: input.Name, + Priority: input.Priority, + Desc: input.Desc, + Filters: string(filters), + Config: string(cfg), + Scope: input.Scope.Int(), + Target: input.Target, + Driver: input.Driver, + }) +} + +func (i *imlStrategyModule) Edit(ctx context.Context, id string, input *strategy_dto.Edit) error { + if input.Name != nil && *input.Name == "" { + return fmt.Errorf("name required") + } + info, err := i.strategyService.Get(ctx, id) + if err != nil { + return err + } + if input.Priority != nil && *input.Priority < 1 { + *input.Priority = 1000 + } + filters := info.Filters + if input.Filters != nil { + err = strategy_driver.CheckFilters(info.Driver, strategy_dto.Scope(info.Scope), *input.Filters) + if err != nil { + return err + } + data, _ := json.Marshal(input.Filters) + filters = string(data) + } + cfg := info.Config + if input.Config != nil { + err = strategy_driver.CheckConfig(info.Driver, input.Config) + if err != nil { + return err + } + data, _ := json.Marshal(input.Config) + cfg = string(data) + } + + return i.strategyService.Save(ctx, id, &strategy.Edit{ + Name: input.Name, + Priority: input.Priority, + Desc: input.Desc, + Filters: &filters, + Config: &cfg, + }) +} + +func (i *imlStrategyModule) Enable(ctx context.Context, id string) error { + stop := false + return i.strategyService.Save(ctx, id, &strategy.Edit{IsStop: &stop}) +} + +func (i *imlStrategyModule) Disable(ctx context.Context, id string) error { + stop := true + return i.strategyService.Save(ctx, id, &strategy.Edit{IsStop: &stop}) +} + +func (i *imlStrategyModule) Publish(ctx context.Context, scope string, target string) error { + list, err := i.strategyService.AllByScope(ctx, strategy_dto.ToScope(scope).Int(), target) + if err != nil { + return err + } + return i.transaction.Transaction(ctx, func(txCtx context.Context) error { + for _, l := range list { + if l.IsDelete { + err = i.strategyService.Delete(ctx, l.Id) + if err != nil { + return err + } + } + + // TODO:同步到网关 + err = i.strategyService.CommitStrategy(txCtx, scope, target, l.Id, l) + if err != nil { + return err + } + } + return nil + }) +} + +func (i *imlStrategyModule) Delete(ctx context.Context, id string) error { + return i.strategyService.SortDelete(ctx, id) +} diff --git a/module/strategy/module.go b/module/strategy/module.go new file mode 100644 index 00000000..fde3e317 --- /dev/null +++ b/module/strategy/module.go @@ -0,0 +1,29 @@ +package strategy + +import ( + "context" + "reflect" + + "github.com/eolinker/go-common/autowire" + + _ "github.com/APIParkLab/APIPark/module/strategy/driver/data-masking" + strategy_dto "github.com/APIParkLab/APIPark/module/strategy/dto" +) + +type IStrategyModule interface { + Search(ctx context.Context, keyword string, driver string, scope strategy_dto.Scope, target string, page int, pageSize int, filters []string, order ...string) ([]*strategy_dto.StrategyItem, int64, error) + Get(ctx context.Context, id string) (*strategy_dto.Strategy, error) + Create(ctx context.Context, i *strategy_dto.Create) error + Edit(ctx context.Context, id string, i *strategy_dto.Edit) error + Enable(ctx context.Context, id string) error + Disable(ctx context.Context, id string) error + Publish(ctx context.Context, scope string, target string) error + Delete(ctx context.Context, id string) error +} + +func init() { + strategyModule := new(imlStrategyModule) + autowire.Auto[IStrategyModule](func() reflect.Value { + return reflect.ValueOf(strategyModule) + }) +} diff --git a/module/upstream/iml.go b/module/upstream/iml.go index 67a9a03b..ec00d397 100644 --- a/module/upstream/iml.go +++ b/module/upstream/iml.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/APIParkLab/APIPark/service/universally/commit" "github.com/eolinker/go-common/utils" @@ -34,7 +35,7 @@ type imlUpstreamModule struct { } func (i *imlUpstreamModule) ExportAll(ctx context.Context) ([]*upstream_dto.ExportUpstream, error) { - latestCommits, err := i.upstreamService.ListLatestCommit(ctx) + latestCommits, err := i.upstreamService.ListLatestCommit(ctx, cluster.DefaultClusterID) if err != nil { return nil, err } diff --git a/plugins/core/ai.go b/plugins/core/ai.go index 7cae2840..c73e8173 100644 --- a/plugins/core/ai.go +++ b/plugins/core/ai.go @@ -14,7 +14,7 @@ func (p *plugin) aiAPIs() []pm3.Api { pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.SimpleProviders), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/config", []string{"context", "query:provider"}, []string{"provider"}, p.aiProviderController.Provider, access.SystemSettingsAiProviderView), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/llms", []string{"context", "query:provider"}, []string{"llms", "provider"}, p.aiProviderController.LLMs), - //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/enable", []string{"context", "query:provider"}, nil, p.aiProviderController.Enable), + //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/enable", []string{"context", "query:provider"}, nil, p.aiProviderController.isStop), //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/disable", []string{"context", "query:provider"}, nil, p.aiProviderController.Disable), pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/config", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderConfig, access.SystemSettingsAiProviderManager), //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/default-llm", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderDefaultLLM), diff --git a/plugins/core/core.go b/plugins/core/core.go index 8d7168ca..1049006d 100644 --- a/plugins/core/core.go +++ b/plugins/core/core.go @@ -3,6 +3,8 @@ package core import ( "net/http" + "github.com/APIParkLab/APIPark/controller/strategy" + "github.com/APIParkLab/APIPark/controller/ai" ai_api "github.com/APIParkLab/APIPark/controller/ai-api" "github.com/APIParkLab/APIPark/controller/monitor" @@ -72,6 +74,7 @@ type plugin struct { aiAPIController ai_api.IAPIController `autowired:""` apiDocController router.IAPIDocController `autowired:""` subscribeController subscribe.ISubscribeController `autowired:""` + strategyController strategy.IStrategyController `autowired:""` appAuthorizationController application_authorization.IAuthorizationController `autowired:""` releaseController release.IReleaseController `autowired:""` roleController role.IRoleController `autowired:""` @@ -105,6 +108,7 @@ func (p *plugin) OnComplete() { p.apis = append(p.apis, p.commonApis()...) p.apis = append(p.apis, p.systemApis()...) p.apis = append(p.apis, p.aiAPIs()...) + p.apis = append(p.apis, p.strategyApis()...) } func (p *plugin) Name() string { diff --git a/plugins/core/strategy.go b/plugins/core/strategy.go new file mode 100644 index 00000000..aa811063 --- /dev/null +++ b/plugins/core/strategy.go @@ -0,0 +1,25 @@ +package core + +import ( + "net/http" + + "github.com/eolinker/go-common/pm3" +) + +func (p *plugin) strategyApis() []pm3.Api { + return []pm3.Api{ + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/global/:driver/list", []string{"context", "query:keyword", "rest:driver", "query:page", "query:page_size", "query:order", "query:sort", "query:filters"}, []string{"list", "total"}, p.strategyController.GlobalStrategyList), + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/global/:driver", []string{"context", "query:strategy"}, []string{"strategy"}, p.strategyController.GetStrategy), + pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/strategy/global/:driver", []string{"context", "rest:driver", "body"}, nil, p.strategyController.CreateGlobalStrategy), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/strategy/global/:driver", []string{"context", "query:strategy", "body"}, nil, p.strategyController.EditStrategy), + pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/strategy/global/:driver", []string{"context", "query:strategy"}, nil, p.strategyController.DeleteStrategy), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/strategy/global/:driver/enable", []string{"context", "query:strategy"}, nil, p.strategyController.EnableStrategy), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/strategy/global/:driver/disable", []string{"context", "query:strategy"}, nil, p.strategyController.DisableStrategy), + + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/service/:driver/list", []string{"context", "query:keyword", "query:service", "rest:driver", "query:page", "query:page_size", "query:order", "query:sort", "query:filters"}, []string{"list", "total"}, p.strategyController.ServiceStrategyList), + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/service/:driver", []string{"context", "query:strategy"}, []string{"strategy"}, p.strategyController.GetStrategy), + pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/strategy/service/:driver", []string{"context", "query:service", "rest:driver", "body"}, nil, p.strategyController.CreateServiceStrategy), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/strategy/service/:driver/enable", []string{"context", "query:strategy"}, nil, p.strategyController.EnableStrategy), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/strategy/service/:driver/disable", []string{"context", "query:strategy"}, nil, p.strategyController.DisableStrategy), + } +} diff --git a/service/strategy/iml.go b/service/strategy/iml.go new file mode 100644 index 00000000..5831d7a9 --- /dev/null +++ b/service/strategy/iml.go @@ -0,0 +1,182 @@ +package strategy + +import ( + "context" + "fmt" + "time" + + "github.com/APIParkLab/APIPark/service/universally/commit" + + "github.com/eolinker/go-common/utils" + + "github.com/APIParkLab/APIPark/service/universally" + "github.com/APIParkLab/APIPark/stores/strategy" +) + +var _ IStrategyService = (*imlStrategyService)(nil) + +type imlStrategyService struct { + store strategy.IStrategyStore `autowired:""` + commitService commit.ICommitService[StrategyCommit] `autowired:""` + universally.IServiceCreate[Create] + universally.IServiceEdit[Edit] +} + +func (i *imlStrategyService) AllByScope(ctx context.Context, scope int, target string) ([]*Strategy, error) { + w := make(map[string]interface{}) + w["scope"] = scope + if target != "" { + w["target"] = target + } + list, err := i.store.List(ctx, w) + if err != nil { + return nil, err + } + return utils.SliceToSlice(list, FromEntity), nil +} + +func (i *imlStrategyService) CommitStrategy(ctx context.Context, scope string, target string, strategyId string, data *Strategy) error { + key := scope + if target != "" { + key = fmt.Sprintf("%s-%s", scope, target) + } + + return i.commitService.Save(ctx, strategyId, key, &StrategyCommit{ + Id: data.Id, + Name: data.Name, + Priority: data.Priority, + Filters: data.Filters, + Config: data.Config, + Driver: data.Driver, + IsStop: data.IsStop, + Version: data.UpdateAt.Format("20060102150405"), + }) +} + +func (i *imlStrategyService) GetStrategyCommit(ctx context.Context, commitId string) (*commit.Commit[StrategyCommit], error) { + return i.commitService.Get(ctx, commitId) +} + +func (i *imlStrategyService) LatestStrategyCommit(ctx context.Context, scope string, target string, strategyId string) (*commit.Commit[StrategyCommit], error) { + key := scope + if target != "" { + key = fmt.Sprintf("%s-%s", scope, target) + } + return i.commitService.Latest(ctx, strategyId, key) +} + +func (i *imlStrategyService) ListLatestStrategyCommit(ctx context.Context, scope string, target string, strategyIds ...string) ([]*commit.Commit[StrategyCommit], error) { + key := scope + if target != "" { + key = fmt.Sprintf("%s-%s", scope, target) + } + return i.commitService.ListLatest(ctx, key, strategyIds...) +} + +func (i *imlStrategyService) ListStrategyCommit(ctx context.Context, commitIds ...string) ([]*commit.Commit[StrategyCommit], error) { + if len(commitIds) < 1 { + return nil, fmt.Errorf("commit ids is empty") + } + + return i.commitService.List(ctx, commitIds...) +} + +func (i *imlStrategyService) Search(ctx context.Context, keyword string, driver string, scope int, target string, page int, pageSize int, filters []string, order ...string) ([]*Strategy, int64, error) { + w := map[string]interface{}{ + "scope": scope, + "driver": driver, + } + if target != "" { + w["target"] = target + } + for _, f := range filters { + switch f { + case "enable": + w["enable"] = true + case "disable": + w["enable"] = false + } + } + if len(order) < 1 { + order = []string{"update_at desc"} + } + list, total, err := i.store.SearchByPage(ctx, keyword, w, page, pageSize, order...) + if err != nil { + return nil, 0, err + } + return utils.SliceToSlice(list, FromEntity), total, nil +} + +func (i *imlStrategyService) Get(ctx context.Context, id string) (*Strategy, error) { + info, err := i.store.GetByUUID(ctx, id) + if err != nil { + return nil, err + } + return FromEntity(info), nil +} + +func (i *imlStrategyService) SortDelete(ctx context.Context, id string) error { + return i.store.SoftDelete(ctx, map[string]interface{}{"uuid": id}) +} + +func (i *imlStrategyService) Delete(ctx context.Context, id ...string) error { + if len(id) == 0 { + return nil + } + _, err := i.store.DeleteWhere(ctx, map[string]interface{}{"uuid": id}) + if err != nil { + return err + } + return nil +} + +func (i *imlStrategyService) OnComplete() { + + i.IServiceCreate = universally.NewCreator[Create, strategy.Strategy](i.store, "strategy", createEntityHandler, uniquestHandler, labelHandler) + + i.IServiceEdit = universally.NewEdit[Edit, strategy.Strategy](i.store, updateHandler, labelHandler) +} + +func labelHandler(e *strategy.Strategy) []string { + return []string{e.Name, e.UUID, e.Desc} +} +func uniquestHandler(i *Create) []map[string]interface{} { + return []map[string]interface{}{{"uuid": i.Id}} +} +func createEntityHandler(i *Create) *strategy.Strategy { + now := time.Now() + return &strategy.Strategy{ + UUID: i.Id, + Name: i.Name, + Priority: i.Priority, + Desc: i.Desc, + Filters: i.Filters, + Config: i.Config, + Scope: i.Scope, + Target: i.Target, + CreateAt: now, + UpdateAt: now, + IsStop: true, + } +} +func updateHandler(e *strategy.Strategy, i *Edit) { + if i.Name != nil { + e.Name = *i.Name + } + if i.Priority != nil { + e.Priority = *i.Priority + } + if i.Desc != nil { + e.Desc = *i.Desc + } + if i.Filters != nil { + e.Filters = *i.Filters + } + if i.Config != nil { + e.Config = *i.Config + } + if i.IsStop != nil { + e.IsStop = *i.IsStop + } + +} diff --git a/service/strategy/model.go b/service/strategy/model.go new file mode 100644 index 00000000..b6217850 --- /dev/null +++ b/service/strategy/model.go @@ -0,0 +1,77 @@ +package strategy + +import ( + "time" + + "github.com/APIParkLab/APIPark/stores/strategy" +) + +type Strategy struct { + Id string + Name string + Priority int + Desc string + Filters string + Config string + Driver string + Scope int + Target string + Creator string + Updater string + CreateAt time.Time + UpdateAt time.Time + IsStop bool + IsDelete bool +} + +func FromEntity(e *strategy.Strategy) *Strategy { + return &Strategy{ + Id: e.UUID, + Name: e.Name, + Priority: e.Priority, + Driver: e.Driver, + Desc: e.Desc, + Filters: e.Filters, + Config: e.Config, + Scope: e.Scope, + Target: e.Target, + Creator: e.Creator, + Updater: e.Updater, + CreateAt: e.CreateAt, + UpdateAt: e.UpdateAt, + IsStop: e.IsStop, + IsDelete: e.IsDelete, + } +} + +type Create struct { + Id string + Name string + Priority int + Desc string + Filters string + Config string + Scope int + Target string + Driver string +} + +type Edit struct { + Name *string + Priority *int + Desc *string + Filters *string + Config *string + IsStop *bool +} + +type StrategyCommit struct { + Id string + Name string + Priority int + Filters string + Config string + Driver string + IsStop bool + Version string +} diff --git a/service/strategy/service.go b/service/strategy/service.go new file mode 100644 index 00000000..557aeb51 --- /dev/null +++ b/service/strategy/service.go @@ -0,0 +1,35 @@ +package strategy + +import ( + "context" + "reflect" + + "github.com/APIParkLab/APIPark/service/universally/commit" + + "github.com/eolinker/go-common/autowire" + + "github.com/APIParkLab/APIPark/service/universally" +) + +type IStrategyService interface { + universally.IServiceCreate[Create] + universally.IServiceEdit[Edit] + AllByScope(ctx context.Context, scope int, target string) ([]*Strategy, error) + Search(ctx context.Context, keyword string, driver string, scope int, target string, page int, pageSize int, filters []string, order ...string) ([]*Strategy, int64, error) + Get(ctx context.Context, id string) (*Strategy, error) + SortDelete(ctx context.Context, id string) error + Delete(ctx context.Context, id ...string) error + + CommitStrategy(ctx context.Context, scope string, target string, strategyId string, data *Strategy) error + GetStrategyCommit(ctx context.Context, commitId string) (*commit.Commit[StrategyCommit], error) + LatestStrategyCommit(ctx context.Context, scope string, target string, strategyId string) (*commit.Commit[StrategyCommit], error) + ListLatestStrategyCommit(ctx context.Context, scope string, target string, strategyIds ...string) ([]*commit.Commit[StrategyCommit], error) + ListStrategyCommit(ctx context.Context, commitIds ...string) ([]*commit.Commit[StrategyCommit], error) +} + +func init() { + autowire.Auto[IStrategyService](func() reflect.Value { + return reflect.ValueOf(new(imlStrategyService)) + }) + commit.InitCommitService[StrategyCommit]("strategy") +} diff --git a/service/universally/commit/iml.go b/service/universally/commit/iml.go index fa7c6bcf..a0a542ef 100644 --- a/service/universally/commit/iml.go +++ b/service/universally/commit/iml.go @@ -2,9 +2,10 @@ package commit import ( "context" + "github.com/eolinker/go-common/utils" "gorm.io/gorm" - + "github.com/APIParkLab/APIPark/stores/universally/commit" ) @@ -18,7 +19,7 @@ type imlCommitWithKeyService[T any] struct { } func (i *imlCommitWithKeyService[T]) List(ctx context.Context, uuids ...string) ([]*Commit[T], error) { - + list, err := i.store.List(ctx, uuids...) if err != nil { return nil, err @@ -31,7 +32,7 @@ func (i *imlCommitWithKeyService[T]) ListLatest(ctx context.Context, target ...s if err != nil { return nil, err } - + return utils.SliceToSlice(list, newCommit[T]), nil } @@ -40,7 +41,7 @@ func (i *imlCommitWithKeyService[T]) Get(ctx context.Context, uuid string) (*Com if err != nil { return nil, err } - + return newCommit(r), nil } @@ -52,7 +53,7 @@ func (i *imlCommitWithKeyService[T]) Latest(ctx context.Context, target string) if len(list) == 0 { return nil, gorm.ErrRecordNotFound } - + result := list[0] return result, nil } @@ -70,13 +71,13 @@ func (i *imlCommitService[T]) List(ctx context.Context, uuids ...string) ([]*Com if err != nil { return nil, err } - + return utils.SliceToSlice(list, newCommit[T]), nil - + } -func (i *imlCommitService[T]) ListLatest(ctx context.Context, target ...string) ([]*Commit[T], error) { - list, err := i.store.Latest(ctx, "", target...) +func (i *imlCommitService[T]) ListLatest(ctx context.Context, key string, target ...string) ([]*Commit[T], error) { + list, err := i.store.Latest(ctx, key, target...) if err != nil { return nil, err } @@ -88,7 +89,7 @@ func (i *imlCommitService[T]) Get(ctx context.Context, uuid string) (*Commit[T], if err != nil { return nil, err } - + return newCommit(r), nil } diff --git a/service/universally/commit/service.go b/service/universally/commit/service.go index 5c5cbda4..215dca79 100644 --- a/service/universally/commit/service.go +++ b/service/universally/commit/service.go @@ -3,7 +3,7 @@ package commit import ( "context" "reflect" - + "github.com/APIParkLab/APIPark/stores/universally/commit" "github.com/eolinker/go-common/autowire" ) @@ -18,7 +18,7 @@ type ICommitWithKeyService[T any] interface { func InitCommitWithKeyService[T any](name string, key string) { autowire.Auto[commit.ICommitWKStore[T]](func() reflect.Value { - + return reflect.ValueOf(commit.NewCommitWithKey[T](name, key)) }) autowire.Auto[ICommitWithKeyService[T]](func() reflect.Value { @@ -28,7 +28,7 @@ func InitCommitWithKeyService[T any](name string, key string) { type ICommitService[T any] interface { Latest(ctx context.Context, target string, key string) (*Commit[T], error) - ListLatest(ctx context.Context, target ...string) ([]*Commit[T], error) + ListLatest(ctx context.Context, key string, target ...string) ([]*Commit[T], error) Save(ctx context.Context, target string, key string, data *T) error Get(ctx context.Context, uuid string) (*Commit[T], error) List(ctx context.Context, uuids ...string) ([]*Commit[T], error) diff --git a/service/upstream/iml.go b/service/upstream/iml.go index 18308483..830bd8e4 100644 --- a/service/upstream/iml.go +++ b/service/upstream/iml.go @@ -50,7 +50,7 @@ func (i *imlUpstreamService) ListCommit(ctx context.Context, uuid ...string) ([] return i.commitService.List(ctx, uuid...) } -func (i *imlUpstreamService) ListLatestCommit(ctx context.Context, serviceIds ...string) ([]*commit.Commit[Config], error) { +func (i *imlUpstreamService) ListLatestCommit(ctx context.Context, clusterId string, serviceIds ...string) ([]*commit.Commit[Config], error) { w := make(map[string]interface{}) if len(serviceIds) > 0 { w["service"] = serviceIds @@ -67,7 +67,7 @@ func (i *imlUpstreamService) ListLatestCommit(ctx context.Context, serviceIds .. targetId := utils.SliceToSlice(upstreams, func(u *upstream.Upstream) string { return u.UUID }) - return i.commitService.ListLatest(ctx, targetId...) + return i.commitService.ListLatest(ctx, clusterId, targetId...) } diff --git a/service/upstream/service.go b/service/upstream/service.go index 01e48a9a..0204adc6 100644 --- a/service/upstream/service.go +++ b/service/upstream/service.go @@ -14,7 +14,7 @@ type IUpstreamService interface { Delete(ctx context.Context, id string) error List(ctx context.Context, serviceIds ...string) ([]*Upstream, error) LatestCommit(ctx context.Context, uid string, clusterId string) (*commit.Commit[Config], error) - ListLatestCommit(ctx context.Context, serviceIds ...string) ([]*commit.Commit[Config], error) + ListLatestCommit(ctx context.Context, clusterId string, serviceIds ...string) ([]*commit.Commit[Config], error) SaveCommit(ctx context.Context, uid string, partition string, cfg *Config) error GetCommit(ctx context.Context, uuid string) (*commit.Commit[Config], error) ListCommit(ctx context.Context, uuid ...string) ([]*commit.Commit[Config], error) diff --git a/stores/strategy/model.go b/stores/strategy/model.go new file mode 100644 index 00000000..7be1799a --- /dev/null +++ b/stores/strategy/model.go @@ -0,0 +1,30 @@ +package strategy + +import "time" + +type Strategy struct { + Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"` + UUID string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"` + Name string `gorm:"type:varchar(100);not null;column:name;comment:name"` + Priority int `gorm:"type:tinyint(4);not null;column:priority;comment:优先级"` + Desc string `gorm:"type:text;null;column:desc;comment:描述"` + Filters string `gorm:"type:mediumtext;null;column:filters;comment:筛选条件"` + Config string `gorm:"type:mediumtext;null;column:config;comment:配置"` + Driver string `gorm:"type:varchar(100);not null;column:driver;comment:驱动"` + Scope int `gorm:"type:tinyint(1);not null;column:scope;comment:范围 0:全局 1:团队 2:服务"` + Target string `gorm:"type:varchar(36);null;column:target;comment:目标ID"` + Creator string `gorm:"type:varchar(36);not null;column:creator;comment:创建人" aovalue:"creator"` + Updater string `gorm:"type:varchar(36);null;column:updater;comment:更新人" aovalue:"updater"` + CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"` + UpdateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:update_at;comment:更新时间"` + IsStop bool `gorm:"type:tinyint(1);not null;column:enable;comment:是否禁用 0:否 1:是"` + IsDelete bool `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除 0:未删除 1:已删除"` +} + +func (s *Strategy) TableName() string { + return "strategy" +} + +func (s *Strategy) IdValue() int64 { + return s.Id +} diff --git a/stores/strategy/store.go b/stores/strategy/store.go new file mode 100644 index 00000000..6838c688 --- /dev/null +++ b/stores/strategy/store.go @@ -0,0 +1,20 @@ +package strategy + +import ( + "reflect" + + "github.com/eolinker/go-common/autowire" + "github.com/eolinker/go-common/store" +) + +type IStrategyStore store.ISearchStore[Strategy] + +type imlStrategyStore struct { + store.SearchStore[Strategy] +} + +func init() { + autowire.Auto[IStrategyStore](func() reflect.Value { + return reflect.ValueOf(new(imlStrategyStore)) + }) +}