Merge branch 'feature/data-mask' into 'main'

Feature/data mask

See merge request apipark/APIPark!87
This commit is contained in:
刘健
2024-11-26 23:50:14 +08:00
53 changed files with 2597 additions and 123 deletions
+64
View File
@@ -17,6 +17,70 @@ type imlMonitorStatisticController struct {
module monitor.IMonitorStatisticModule `autowired:""`
}
func (i *imlMonitorStatisticController) Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error) {
switch dataType {
case monitor_dto.DataTypeApi:
return i.module.ApiStatistics(ctx, input)
case monitor_dto.DataTypeProvider:
return i.module.ProviderStatistics(ctx, input)
case monitor_dto.DataTypeSubscriber:
return i.module.SubscriberStatistics(ctx, input)
default:
return nil, fmt.Errorf("unsupported data type: %s", dataType)
}
}
func (i *imlMonitorStatisticController) InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
switch dataType {
case monitor_dto.DataTypeApi:
return i.module.APITrend(ctx, id, input)
case monitor_dto.DataTypeProvider:
return i.module.ProviderTrend(ctx, id, input)
case monitor_dto.DataTypeSubscriber:
return i.module.SubscriberTrend(ctx, id, input)
default:
return nil, "", fmt.Errorf("unsupported data type: %s", dataType)
}
}
func (i *imlMonitorStatisticController) InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeSubscriber || dataType == monitor_dto.DataTypeSubscriber && typ == monitor_dto.DataTypeApi {
return i.module.InvokeTrendWithSubscriberAndApi(ctx, api, subscriber, input)
} else if dataType == monitor_dto.DataTypeApi && typ == monitor_dto.DataTypeProvider || dataType == monitor_dto.DataTypeProvider && typ == monitor_dto.DataTypeApi {
return i.module.InvokeTrendWithProviderAndApi(ctx, provider, api, input)
}
return nil, "", fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
}
func (i *imlMonitorStatisticController) StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error) {
switch dataType {
case monitor_dto.DataTypeApi:
switch typ {
case monitor_dto.DataTypeProvider:
return i.module.ProviderStatisticsOnApi(ctx, id, input)
case monitor_dto.DataTypeSubscriber:
return i.module.SubscriberStatisticsOnApi(ctx, id, input)
default:
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
}
case monitor_dto.DataTypeProvider:
switch typ {
case monitor_dto.DataTypeApi:
return i.module.ApiStatisticsOnProvider(ctx, id, input)
default:
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
}
case monitor_dto.DataTypeSubscriber:
switch typ {
case monitor_dto.DataTypeApi:
return i.module.ApiStatisticsOnSubscriber(ctx, id, input)
default:
return nil, fmt.Errorf("unsupported detail type: %s, data type is %s", typ, dataType)
}
}
return nil, fmt.Errorf("unsupported data type: %s", dataType)
}
func (i *imlMonitorStatisticController) OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error) {
trend, timeInterval, err := i.module.MessageTrend(ctx, input)
if err != nil {
+6 -1
View File
@@ -16,7 +16,12 @@ type IMonitorStatisticController interface {
OverviewInvokeTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []int64, []int64, []int64, []int64, []float64, []float64, string, error)
OverviewMessageTrend(ctx *gin.Context, input *monitor_dto.CommonInput) ([]time.Time, []float64, []float64, string, error)
//Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
Statistics(ctx *gin.Context, dataType string, input *monitor_dto.StatisticInput) (interface{}, error)
InvokeTrend(ctx *gin.Context, dataType string, id string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
InvokeTrendInner(ctx *gin.Context, dataType string, typ string, api string, provider string, subscriber string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
StatisticsInner(ctx *gin.Context, dataType string, typ string, id string, input *monitor_dto.StatisticInput) (interface{}, error)
}
type IMonitorConfigController interface {
+28 -28
View File
@@ -7,6 +7,8 @@ import (
"strings"
"time"
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
"github.com/eolinker/eosc/log"
application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
@@ -25,7 +27,6 @@ import (
"github.com/APIParkLab/APIPark/module/service"
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
"github.com/APIParkLab/APIPark/module/upstream"
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
"github.com/eolinker/go-common/store"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
@@ -47,24 +48,12 @@ type imlServiceController struct {
transaction store.ITransaction `autowired:""`
}
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
return &upstream_dto.Upstream{
Type: "http",
Balance: "round-robin",
Timeout: 300000,
Retry: 0,
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
LimitPeerSecond: 0,
ProxyHeaders: nil,
Scheme: uri.Scheme(),
PassHost: "node",
Nodes: []*upstream_dto.NodeConfig{
{
Address: uri.Host(),
Weight: 100,
},
},
}
func (i *imlServiceController) Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
return i.module.Simple(ctx)
}
func (i *imlServiceController) MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error) {
return i.module.MySimple(ctx)
}
func (i *imlServiceController) editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error) {
@@ -228,21 +217,12 @@ func (i *imlServiceController) SearchMyServices(ctx *gin.Context, teamId string,
return i.module.SearchMyServices(ctx, teamId, keyword)
}
//func (i *imlServiceController) Simple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
// return i.module.Simple(ctx, keyword)
//}
//
//func (i *imlServiceController) MySimple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
// return i.module.MySimple(ctx, keyword)
//}
func (i *imlServiceController) Get(ctx *gin.Context, id string) (*service_dto.Service, error) {
now := time.Now()
defer func() {
log.Infof("get service %s cost %d ms", id, time.Since(now).Milliseconds())
}()
return i.module.Get(ctx, id)
}
func (i *imlServiceController) Search(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error) {
@@ -336,3 +316,23 @@ func (i *imlAppController) GetApp(ctx *gin.Context, appId string) (*service_dto.
func (i *imlAppController) DeleteApp(ctx *gin.Context, appId string) error {
return i.module.DeleteApp(ctx, appId)
}
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
return &upstream_dto.Upstream{
Type: "http",
Balance: "round-robin",
Timeout: 300000,
Retry: 0,
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
LimitPeerSecond: 0,
ProxyHeaders: nil,
Scheme: uri.Scheme(),
PassHost: "node",
Nodes: []*upstream_dto.NodeConfig{
{
Address: uri.Host(),
Weight: 100,
},
},
}
}
+2 -6
View File
@@ -24,12 +24,8 @@ type IServiceController interface {
Delete(ctx *gin.Context, id string) error
ServiceDoc(ctx *gin.Context, id string) (*service_dto.ServiceDoc, error)
SaveServiceDoc(ctx *gin.Context, id string, input *service_dto.SaveServiceDoc) error
//createAIService(ctx *gin.Context, teamID string, input *service_dto.CreateService) (*service_dto.Service, error)
//editAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
//DeleteAIService(ctx *gin.Context, id string) error
//SearchMyAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
//SearchAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
Simple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
MySimple(ctx *gin.Context) ([]*service_dto.SimpleServiceItem, error)
}
type IAppController interface {
+205
View File
@@ -0,0 +1,205 @@
package strategy
import (
"encoding/base64"
"encoding/json"
"fmt"
"sort"
"strconv"
"time"
"github.com/eolinker/go-common/utils"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
"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) ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error) {
list, err := i.strategyModule.ToPublish(ctx, driver)
if err != nil {
return nil, "", "", false, err
}
data, _ := json.Marshal(list)
source := base64.StdEncoding.EncodeToString(data)
return list, source, time.Now().Format("20060102150405") + "-release", len(list) > 0, nil
}
func (i *imlStrategyController) FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
f, has := strategy_filter.RemoteFilter(name)
if !has {
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
}
scopeAllow := false
for _, s := range f.Scopes() {
if s == strategy_filter.ScopeGlobal {
scopeAllow = true
break
}
}
if !scopeAllow {
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
}
list, total, err := f.RemoteList(ctx, "", nil, -1, -1)
if err != nil {
return nil, nil, 0, "", "", err
}
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
return &strategy_dto.Title{
Field: l.Field,
Title: l.Title,
}
}), list, total, f.Key(), f.Key(), nil
}
func (i *imlStrategyController) FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error) {
f, has := strategy_filter.RemoteFilter(name)
if !has {
return nil, nil, 0, "", "", fmt.Errorf("filter not found: %s", name)
}
scopeAllow := false
for _, s := range f.Scopes() {
if s == strategy_filter.ScopeService {
scopeAllow = true
break
}
}
if !scopeAllow {
return nil, nil, 0, "", "", fmt.Errorf("scope not allowed: %s", name)
}
list, total, err := f.RemoteList(ctx, "", map[string]interface{}{"service": serviceId}, -1, -1)
if err != nil {
return nil, nil, 0, "", "", err
}
return utils.SliceToSlice(f.Titles(), func(l strategy_filter.OptionTitle) *strategy_dto.Title {
return &strategy_dto.Title{
Field: l.Field,
Title: l.Title,
}
}), list, total, f.Key(), "list", nil
}
func (i *imlStrategyController) filterOptions(ctx *gin.Context, scope string) ([]*strategy_dto.FilterOption, error) {
m, has := strategy_filter.Options(scope)
if !has {
return nil, fmt.Errorf("scope not found: %s", scope)
}
list := utils.MapToSlice(m, func(key string, value *strategy_filter.Option) *strategy_dto.FilterOption {
pattern := ""
if value.Pattern != nil {
pattern = value.Pattern.String()
}
return &strategy_dto.FilterOption{
Name: value.Name,
Title: value.Title,
Type: value.Type,
Pattern: pattern,
Options: value.Options,
}
})
sort.Slice(list, func(i, j int) bool {
return list[i].Name < list[j].Name
})
return list, nil
}
func (i *imlStrategyController) FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
return i.filterOptions(ctx, strategy_filter.ScopeService)
}
func (i *imlStrategyController) FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error) {
return i.filterOptions(ctx, strategy_filter.ScopeGlobal)
}
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.ScopeGlobal), "", 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.ScopeGlobal)
return i.strategyModule.Create(ctx, input)
}
func (i *imlStrategyController) PublishGlobalStrategy(ctx *gin.Context, driver string) error {
return i.strategyModule.Publish(ctx, driver, strategy_dto.ScopeGlobal, "")
}
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.strategyModule.Enable(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)
}
+42
View File
@@ -0,0 +1,42 @@
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, driver string) 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
FilterGlobalOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
FilterServiceOptions(ctx *gin.Context) ([]*strategy_dto.FilterOption, error)
FilterGlobalRemote(ctx *gin.Context, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
FilterServiceRemote(ctx *gin.Context, serviceId string, name string) ([]*strategy_dto.Title, []any, int64, string, string, error)
ToPublish(ctx *gin.Context, driver string) ([]*strategy_dto.ToPublishItem, string, string, bool, error)
}
type IStrategyCommonController interface {
}
func init() {
autowire.Auto[IStrategyController](func() reflect.Value {
return reflect.ValueOf(&imlStrategyController{})
})
}
+1
View File
@@ -41,6 +41,7 @@ type ServiceBasic struct {
ApprovalType string `json:"approval_type"`
ServiceKind string `json:"service_kind"`
InvokeAddress string `json:"invoke_address"`
SitePrefix string `json:"site_prefix"`
}
type ServiceApiBasic struct {
+2
View File
@@ -284,6 +284,7 @@ func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*ca
serviceDoc = commit.Data.Content
}
invokeAddress, _ := i.settingService.Get(ctx, setting.KeyInvokeAddress)
sitePrefix, _ := i.settingService.Get(ctx, setting.KeySitePrefix)
return &catalogue_dto.ServiceDetail{
Name: s.Name,
@@ -301,6 +302,7 @@ func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*ca
ApprovalType: s.ApprovalType.String(),
ServiceKind: s.Kind.String(),
InvokeAddress: invokeAddress,
SitePrefix: sitePrefix,
},
APIDoc: apiDoc,
}, nil
+1 -1
View File
@@ -24,7 +24,7 @@ type CommonInput struct {
type StatisticInput struct {
Apis []string `json:"apis"`
Projects []string `json:"projects"`
Services []string `json:"services"`
Path string `json:"path"`
*CommonInput
}
+3 -3
View File
@@ -21,12 +21,12 @@ type ApiStatisticBasicItem struct {
*MonCommonData
}
type ProjectStatisticItem struct {
*ProjectStatisticBasicItem
type ServiceStatisticItem struct {
*ServiceStatisticBasicItem
IsRed bool `json:"is_red"` //是否标红
}
type ProjectStatisticBasicItem struct {
type ServiceStatisticBasicItem struct {
Id string `json:"id"` //订阅方ID
Name string `json:"name"` //订阅方名称
*MonCommonData
+447 -11
View File
@@ -5,14 +5,15 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"time"
"github.com/APIParkLab/APIPark/gateway"
"github.com/eolinker/eosc/log"
"github.com/eolinker/go-common/auto"
"github.com/eolinker/go-common/store"
"github.com/eolinker/go-common/utils"
"gorm.io/gorm"
"sort"
"time"
"github.com/APIParkLab/APIPark/service/service"
@@ -42,6 +43,442 @@ type imlMonitorStatisticModule struct {
apiService api.IAPIService `autowired:""`
}
func (i *imlMonitorStatisticModule) ApiStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
wm := make(map[string]interface{})
if len(input.Apis) > 0 {
wm["uuid"] = input.Apis
wheres = append(wheres, monitor.MonWhereItem{
Key: "api",
Operation: "in",
Values: input.Apis,
})
}
if len(input.Services) > 0 {
wm["service"] = input.Services
wheres = append(wheres, monitor.MonWhereItem{
Key: "project",
Operation: "in",
Values: input.Services,
})
}
// 查询符合条件的API
apis, err := i.apiService.Search(ctx, input.Path, wm)
if err != nil {
return nil, err
}
if len(apis) < 1 {
// 没有符合条件的API
return make([]*monitor_dto.ApiStatisticBasicItem, 0), nil
}
apiIds := utils.SliceToSlice(apis, func(t *api.API) string {
return t.UUID
})
apiInfos, err := i.apiService.ListInfo(ctx, apiIds...)
if err != nil {
return nil, err
}
return i.apiStatistics(ctx, clusterId, apiInfos, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
}
func (i *imlMonitorStatisticModule) apiStatistics(ctx context.Context, clusterId string, apiInfos []*api.Info, start time.Time, end time.Time, wheres []monitor.MonWhereItem, limit int) ([]*monitor_dto.ApiStatisticBasicItem, error) {
statisticMap, err := i.statistics(ctx, clusterId, "api", start, end, wheres, limit)
if err != nil {
return nil, err
}
result := make([]*monitor_dto.ApiStatisticBasicItem, 0, len(statisticMap))
for _, item := range apiInfos {
statisticItem := &monitor_dto.ApiStatisticBasicItem{
Id: item.UUID,
Name: item.Name,
Path: item.Path,
Service: auto.UUID(item.Service),
MonCommonData: new(monitor_dto.MonCommonData),
}
if val, ok := statisticMap[item.UUID]; ok {
statisticItem.MonCommonData = monitor_dto.ToMonCommonData(val)
delete(statisticMap, item.UUID)
}
result = append(result, statisticItem)
}
for key, item := range statisticMap {
statisticItem := &monitor_dto.ApiStatisticBasicItem{
Id: key,
Name: "未知API-" + key,
MonCommonData: monitor_dto.ToMonCommonData(item),
}
if key == "-" {
statisticItem.Name = "无API"
}
result = append(result, statisticItem)
}
sort.Slice(result, func(i, j int) bool {
return result[i].RequestTotal > result[j].RequestTotal
})
return result, nil
}
func (i *imlMonitorStatisticModule) SubscriberStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
apps, err := i.serviceService.AppList(ctx, input.Services...)
if err != nil {
return nil, err
}
appIds := utils.SliceToSlice(apps, func(p *service.Service) string {
return p.Id
})
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
if len(appIds) > 0 {
wheres = append(wheres, monitor.MonWhereItem{
Key: "app",
Operation: "in",
Values: appIds,
})
}
return i.serviceStatistics(ctx, clusterId, apps, "app", formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
}
func (i *imlMonitorStatisticModule) serviceStatistics(ctx context.Context, clusterId string, services []*service.Service, groupBy string, start time.Time, end time.Time, wheres []monitor.MonWhereItem, limit int) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
statisticMap, err := i.statistics(ctx, clusterId, groupBy, start, end, wheres, limit)
if err != nil {
return nil, err
}
result := make([]*monitor_dto.ServiceStatisticBasicItem, 0, len(statisticMap))
for _, item := range services {
statisticItem := &monitor_dto.ServiceStatisticBasicItem{
Id: item.Id,
Name: item.Name,
MonCommonData: new(monitor_dto.MonCommonData),
}
if val, ok := statisticMap[item.Id]; ok {
statisticItem.MonCommonData = monitor_dto.ToMonCommonData(val)
delete(statisticMap, item.Id)
}
result = append(result, statisticItem)
}
for key, item := range statisticMap {
statisticItem := &monitor_dto.ServiceStatisticBasicItem{
Id: key,
Name: "未知-" + key,
MonCommonData: monitor_dto.ToMonCommonData(item),
}
if key == "-" {
statisticItem.Name = "-"
}
result = append(result, statisticItem)
}
sort.Slice(result, func(i, j int) bool {
return result[i].RequestTotal > result[j].RequestTotal
})
return result, nil
}
func (i *imlMonitorStatisticModule) ProviderStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
services, err := i.serviceService.ServiceList(ctx, input.Services...)
if err != nil {
return nil, err
}
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
if len(input.Services) > 0 {
wheres = append(wheres, monitor.MonWhereItem{
Key: "provider",
Operation: "in",
Values: input.Services,
})
}
return i.serviceStatistics(ctx, clusterId, services, "provider", formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
}
func (i *imlMonitorStatisticModule) APITrend(ctx context.Context, apiId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, "", err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "api",
Operation: "=",
Values: []string{apiId},
})
executor, err := i.getExecutor(ctx, clusterId)
if err != nil {
return nil, "", err
}
result, timeInterval, err := executor.InvokeTrend(ctx, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres)
if err != nil {
return nil, "", err
}
return monitor_dto.ToMonInvokeCountTrend(result), timeInterval, nil
}
func (i *imlMonitorStatisticModule) ProviderTrend(ctx context.Context, providerId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, "", err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "provider",
Operation: "=",
Values: []string{providerId},
})
executor, err := i.getExecutor(ctx, clusterId)
if err != nil {
return nil, "", err
}
result, timeInterval, err := executor.InvokeTrend(ctx, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres)
if err != nil {
return nil, "", err
}
return monitor_dto.ToMonInvokeCountTrend(result), timeInterval, nil
}
func (i *imlMonitorStatisticModule) SubscriberTrend(ctx context.Context, subscriberId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, "", err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "app",
Operation: "=",
Values: []string{subscriberId},
})
executor, err := i.getExecutor(ctx, clusterId)
if err != nil {
return nil, "", err
}
result, timeInterval, err := executor.InvokeTrend(ctx, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres)
if err != nil {
return nil, "", err
}
return monitor_dto.ToMonInvokeCountTrend(result), timeInterval, nil
}
func (i *imlMonitorStatisticModule) InvokeTrendWithSubscriberAndApi(ctx context.Context, apiId string, subscriberId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, "", err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "api",
Operation: "=",
Values: []string{apiId},
}, monitor.MonWhereItem{
Key: "app",
Operation: "=",
Values: []string{subscriberId},
})
executor, err := i.getExecutor(ctx, clusterId)
if err != nil {
return nil, "", err
}
result, timeInterval, err := executor.InvokeTrend(ctx, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres)
if err != nil {
return nil, "", err
}
return monitor_dto.ToMonInvokeCountTrend(result), timeInterval, nil
}
func (i *imlMonitorStatisticModule) InvokeTrendWithProviderAndApi(ctx context.Context, providerId string, apiId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, "", err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "api",
Operation: "=",
Values: []string{apiId},
}, monitor.MonWhereItem{
Key: "provider",
Operation: "=",
Values: []string{providerId},
})
executor, err := i.getExecutor(ctx, clusterId)
if err != nil {
return nil, "", err
}
result, timeInterval, err := executor.InvokeTrend(ctx, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres)
if err != nil {
return nil, "", err
}
return monitor_dto.ToMonInvokeCountTrend(result), timeInterval, nil
}
func (i *imlMonitorStatisticModule) statisticOnApi(ctx context.Context, clusterId string, apiId string, groupBy string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
var service []*service.Service
switch groupBy {
case "app":
service, err = i.serviceService.AppList(ctx)
case "provider":
service, err = i.serviceService.ServiceList(ctx)
default:
return nil, errors.New("invalid group by")
}
if err != nil {
return nil, err
}
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "api",
Operation: "=",
Values: []string{apiId},
})
statisticMap, err := i.statistics(ctx, clusterId, groupBy, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
if err != nil {
return nil, err
}
result := make([]*monitor_dto.ServiceStatisticBasicItem, 0, len(statisticMap))
for _, item := range service {
statisticItem := &monitor_dto.ServiceStatisticBasicItem{
Id: item.Id,
Name: item.Name,
MonCommonData: new(monitor_dto.MonCommonData),
}
if val, ok := statisticMap[item.Id]; ok {
statisticItem.MonCommonData = monitor_dto.ToMonCommonData(val)
delete(statisticMap, item.Id)
}
result = append(result, statisticItem)
}
for key, item := range statisticMap {
statisticItem := &monitor_dto.ServiceStatisticBasicItem{
Id: key,
Name: "未知-" + key,
MonCommonData: monitor_dto.ToMonCommonData(item),
}
if key == "-" {
statisticItem.Name = "-"
}
result = append(result, statisticItem)
}
sort.Slice(result, func(i, j int) bool {
return result[i].RequestTotal > result[j].RequestTotal
})
return result, nil
}
func (i *imlMonitorStatisticModule) ProviderStatisticsOnApi(ctx context.Context, apiId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
return i.statisticOnApi(ctx, clusterId, apiId, "provider", input)
}
func (i *imlMonitorStatisticModule) ApiStatisticsOnProvider(ctx context.Context, providerId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
apiInfos, err := i.apiService.ListInfoForService(ctx, providerId)
if err != nil {
return nil, err
}
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "provider",
Operation: "=",
Values: []string{providerId},
})
return i.apiStatistics(ctx, clusterId, apiInfos, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
}
func (i *imlMonitorStatisticModule) ApiStatisticsOnSubscriber(ctx context.Context, subscriberId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
return nil, err
}
// 根据订阅ID查询订阅的服务列表
subscriptions, err := i.subscribeService.MySubscribeServices(ctx, subscriberId, nil)
if err != nil {
return nil, err
}
serviceIds := utils.SliceToSlice(subscriptions, func(t *subscribe.Subscribe) string {
return t.Service
})
if len(serviceIds) < 1 {
return nil, nil
}
apiInfos, err := i.apiService.ListInfoForServices(ctx, serviceIds...)
if err != nil {
return nil, err
}
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
wheres = append(wheres, monitor.MonWhereItem{
Key: "app",
Operation: "=",
Values: []string{subscriberId},
})
return i.apiStatistics(ctx, clusterId, apiInfos, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, 0)
}
func (i *imlMonitorStatisticModule) SubscriberStatisticsOnApi(ctx context.Context, apiId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error) {
clusterId := cluster.DefaultClusterID
return i.statisticOnApi(ctx, clusterId, apiId, "app", input)
}
func (i *imlMonitorStatisticModule) MessageTrend(ctx context.Context, input *monitor_dto.CommonInput) (*monitor_dto.MonMessageTrend, string, error) {
clusterId := cluster.DefaultClusterID
wheres, err := i.genCommonWheres(ctx, clusterId)
@@ -173,7 +610,7 @@ func (i *imlMonitorStatisticModule) TopAPIStatistics(ctx context.Context, limit
}
func (i *imlMonitorStatisticModule) TopSubscriberStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ProjectStatisticItem, error) {
func (i *imlMonitorStatisticModule) TopSubscriberStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ServiceStatisticItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
@@ -182,7 +619,7 @@ func (i *imlMonitorStatisticModule) TopSubscriberStatistics(ctx context.Context,
return i.topProjectStatistics(ctx, clusterId, "app", input, limit)
}
func (i *imlMonitorStatisticModule) TopProviderStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ProjectStatisticItem, error) {
func (i *imlMonitorStatisticModule) TopProviderStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ServiceStatisticItem, error) {
clusterId := cluster.DefaultClusterID
_, err := i.clusterService.Get(ctx, clusterId)
if err != nil {
@@ -191,12 +628,12 @@ func (i *imlMonitorStatisticModule) TopProviderStatistics(ctx context.Context, l
return i.topProjectStatistics(ctx, clusterId, "provider", input, limit)
}
func (i *imlMonitorStatisticModule) topProjectStatistics(ctx context.Context, partitionId string, groupBy string, input *monitor_dto.CommonInput, limit int) ([]*monitor_dto.ProjectStatisticItem, error) {
wheres, err := i.genCommonWheres(ctx, partitionId)
func (i *imlMonitorStatisticModule) topProjectStatistics(ctx context.Context, clusterId string, groupBy string, input *monitor_dto.CommonInput, limit int) ([]*monitor_dto.ServiceStatisticItem, error) {
wheres, err := i.genCommonWheres(ctx, clusterId)
if err != nil {
return nil, err
}
statisticMap, err := i.statistics(ctx, partitionId, groupBy, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, limit)
statisticMap, err := i.statistics(ctx, clusterId, groupBy, formatTimeByMinute(input.Start), formatTimeByMinute(input.End), wheres, limit)
if err != nil {
return nil, err
}
@@ -216,10 +653,10 @@ func (i *imlMonitorStatisticModule) topProjectStatistics(ctx context.Context, pa
return t.Id
})
result := make([]*monitor_dto.ProjectStatisticItem, 0, len(statisticMap))
result := make([]*monitor_dto.ServiceStatisticItem, 0, len(statisticMap))
for key, item := range statisticMap {
statisticItem := &monitor_dto.ProjectStatisticItem{
ProjectStatisticBasicItem: &monitor_dto.ProjectStatisticBasicItem{
statisticItem := &monitor_dto.ServiceStatisticItem{
ServiceStatisticBasicItem: &monitor_dto.ServiceStatisticBasicItem{
Id: key,
MonCommonData: monitor_dto.ToMonCommonData(item),
},
@@ -407,7 +844,6 @@ func (m *imlMonitorConfig) GetMonitorConfig(ctx context.Context) (*monitor_dto.M
Driver: info.Driver,
Config: cfg,
}, nil
return nil, nil
}
func (m *imlMonitorConfig) GetMonitorCluster(ctx context.Context) ([]*monitor_dto.MonitorCluster, error) {
+22 -4
View File
@@ -13,18 +13,36 @@ import (
type IMonitorStatisticModule interface {
TopAPIStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ApiStatisticItem, error)
TopProviderStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ProjectStatisticItem, error)
TopSubscriberStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ProjectStatisticItem, error)
TopProviderStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ServiceStatisticItem, error)
TopSubscriberStatistics(ctx context.Context, limit int, input *monitor_dto.CommonInput) ([]*monitor_dto.ServiceStatisticItem, error)
// RequestSummary 请求概况
RequestSummary(ctx context.Context, input *monitor_dto.CommonInput) (*monitor_dto.MonSummaryOutput, error)
// ProxySummary 转发概况
ProxySummary(ctx context.Context, input *monitor_dto.CommonInput) (*monitor_dto.MonSummaryOutput, error)
// InvokeTrend 调用次数趋势
InvokeTrend(ctx context.Context, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
// MessageTrend 消息趋势
MessageTrend(ctx context.Context, input *monitor_dto.CommonInput) (*monitor_dto.MonMessageTrend, string, error)
ApiStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error)
SubscriberStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error)
ProviderStatistics(ctx context.Context, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error)
APITrend(ctx context.Context, apiId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
ProviderTrend(ctx context.Context, providerId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
SubscriberTrend(ctx context.Context, subscriberId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
InvokeTrendWithSubscriberAndApi(ctx context.Context, apiId string, subscriberId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
InvokeTrendWithProviderAndApi(ctx context.Context, providerId string, apiId string, input *monitor_dto.CommonInput) (*monitor_dto.MonInvokeCountTrend, string, error)
ProviderStatisticsOnApi(ctx context.Context, apiId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error)
ApiStatisticsOnProvider(ctx context.Context, providerId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error)
ApiStatisticsOnSubscriber(ctx context.Context, subscriberId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ApiStatisticBasicItem, error)
SubscriberStatisticsOnApi(ctx context.Context, apiId string, input *monitor_dto.StatisticInput) ([]*monitor_dto.ServiceStatisticBasicItem, error)
}
type IMonitorConfigModule interface {
+2 -1
View File
@@ -26,7 +26,8 @@ type Item struct {
type SimpleItem struct {
Id string `json:"id"`
Methods []string `json:"methods"`
Path string `json:"request_path"`
//Name string `json:"name"`
Path string `json:"request_path"`
}
type Detail struct {
+112
View File
@@ -0,0 +1,112 @@
package router
import (
"context"
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
"github.com/eolinker/go-common/utils"
"github.com/eolinker/eosc/log"
"github.com/APIParkLab/APIPark/service/api"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
)
var _ strategy_filter.IRemoteFilter = (*imlRouterFilter)(nil)
type imlRouterFilter struct {
service api.IAPIService `autowired:""`
}
func (i *imlRouterFilter) Name() string {
return "api"
}
func (i *imlRouterFilter) Title() string {
return "API"
}
func (i *imlRouterFilter) Labels(values ...string) []string {
list, err := i.service.ListInfo(context.Background(), values...)
if err != nil {
log.Errorf("get api labels error: %v", err)
return nil
}
return utils.SliceToSlice(list, func(a *api.Info) string {
return a.Name
})
}
func (i *imlRouterFilter) Type() string {
return strategy_filter.TypeRemote
}
func (i *imlRouterFilter) Scopes() []string {
return []string{
//strategy_filter.ScopeGlobal,
strategy_filter.ScopeService,
}
}
func (i *imlRouterFilter) Option() *strategy_filter.Option {
return &strategy_filter.Option{
Name: i.Name(),
Title: i.Title(),
Type: i.Type(),
}
}
func (i *imlRouterFilter) Titles() []strategy_filter.OptionTitle {
return []strategy_filter.OptionTitle{
{
Field: "name",
Title: "api name",
},
{
Field: "methods",
Title: "methods",
},
{
Field: "request_path",
Title: "request path",
},
}
}
func (i *imlRouterFilter) Key() string {
return "id"
}
func (i *imlRouterFilter) Target() string {
return "list"
}
func (i *imlRouterFilter) RemoteList(ctx context.Context, keyword string, condition map[string]interface{}, page int, pageSize int) ([]any, int64, error) {
if pageSize == -1 {
// 获取全部
list, err := i.service.Search(ctx, keyword, condition)
if err != nil {
return nil, 0, err
}
return utils.SliceToSlice(list, func(s *api.API) any {
return &router_dto.SimpleItem{
Id: s.UUID,
Path: s.Path,
Methods: s.Method,
}
}), int64(len(list)), nil
}
list, total, err := i.service.SearchByPage(ctx, keyword, condition, page, pageSize, "update_at")
if err != nil {
return nil, 0, err
}
return utils.SliceToSlice(list, func(s *api.API) any {
return &router_dto.SimpleItem{
Id: s.UUID,
Path: s.Path,
Methods: s.Method,
}
}), total, nil
}
+7 -1
View File
@@ -2,9 +2,11 @@ package router
import (
"context"
"github.com/APIParkLab/APIPark/module/system"
"reflect"
"github.com/APIParkLab/APIPark/module/system"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
"github.com/eolinker/go-common/autowire"
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
@@ -45,4 +47,8 @@ func init() {
autowire.Auto[IExportRouterModule](func() reflect.Value {
return reflect.ValueOf(apiModule)
})
filter := new(imlRouterFilter)
autowire.Autowired(filter)
strategy_filter.RegisterRemoteFilter(filter)
}
+125
View File
@@ -0,0 +1,125 @@
package service
import (
"context"
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
"github.com/eolinker/go-common/auto"
"github.com/APIParkLab/APIPark/service/service"
"github.com/eolinker/eosc/log"
"github.com/eolinker/go-common/utils"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
)
var _ strategy_filter.IRemoteFilter = (*imlAppFilter)(nil)
type imlAppFilter struct {
service service.IServiceService `autowired:""`
}
func (i *imlAppFilter) Name() string {
return "application"
}
func (i *imlAppFilter) Title() string {
return "消费者"
}
func (i *imlAppFilter) Labels(values ...string) []string {
if len(values) == 0 {
return nil
}
if values[0] == strategy_filter.ValuesALL {
return []string{
"全部消费者",
}
}
apps, err := i.service.AppList(context.Background(), values...)
if err != nil {
log.Error(err)
return nil
}
return utils.SliceToSlice(apps, func(a *service.Service) string {
return a.Name
})
}
func (i *imlAppFilter) Type() string {
return strategy_filter.TypeRemote
}
func (i *imlAppFilter) Scopes() []string {
return []string{
strategy_filter.ScopeGlobal,
strategy_filter.ScopeService,
}
}
func (i *imlAppFilter) Option() *strategy_filter.Option {
return &strategy_filter.Option{
Name: i.Name(),
Title: i.Title(),
Type: i.Type(),
}
}
func (i *imlAppFilter) Titles() []strategy_filter.OptionTitle {
return []strategy_filter.OptionTitle{
{
Field: "name",
Title: "consumer",
},
{
Field: "id",
Title: "consumer id",
},
{
Field: "description",
Title: "description",
},
}
}
func (i *imlAppFilter) Key() string {
return "id"
}
func (i *imlAppFilter) Target() string {
return "list"
}
func (i *imlAppFilter) RemoteList(ctx context.Context, keyword string, condition map[string]interface{}, page int, pageSize int) ([]any, int64, error) {
if condition == nil {
condition = make(map[string]interface{})
}
condition["as_app"] = true
if pageSize == -1 {
// 获取全部
list, err := i.service.Search(ctx, keyword, condition, "update_at")
if err != nil {
return nil, 0, err
}
return utils.SliceToSlice(list, func(s *service.Service) any {
return &service_dto.SimpleAppItem{
Id: s.Id,
Name: s.Name,
Team: auto.UUID(s.Team),
Description: s.Description,
}
}), int64(len(list)), nil
}
list, total, err := i.service.SearchByPage(ctx, keyword, condition, page, pageSize, "update_at")
if err != nil {
return nil, 0, err
}
return utils.SliceToSlice(list, func(s *service.Service) any {
return &service_dto.SimpleAppItem{
Id: s.Id,
Name: s.Name,
Team: auto.UUID(s.Team),
Description: s.Description,
}
}), total, nil
}
+42 -44
View File
@@ -109,9 +109,7 @@ func (i *imlServiceModule) ExportAll(ctx context.Context) ([]*service_dto.Export
Catalogue: s.Catalogue,
Logo: s.Logo,
}
//if v, ok := docMap[s.Id]; ok {
// info.Doc = v.Doc
//}
if tags, ok := serviceTagMap[s.Id]; ok {
info.Tags = tags
}
@@ -191,47 +189,47 @@ func (i *imlServiceModule) SearchMyServices(ctx context.Context, teamId string,
// }), nil
//}
//func (i *imlServiceModule) Simple(ctx context.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
// w := make(map[string]interface{})
// w["as_server"] = true
//
// services, err := i.serviceService.Search(ctx, keyword, w)
// if err != nil {
// return nil, err
// }
//
// items := make([]*service_dto.SimpleServiceItem, 0, len(services))
// for _, p := range services {
//
// items = append(items, &service_dto.SimpleServiceItem{
// Id: p.Id,
// Name: p.Name,
// Description: p.Description,
// Team: auto.UUID(p.Team),
// })
// }
// return items, nil
//}
//
//func (i *imlServiceModule) MySimple(ctx context.Context, keyword string) ([]*service_dto.SimpleServiceItem, error) {
// services, err := i.searchMyServices(ctx, "", keyword)
//
// if err != nil {
// return nil, err
// }
//
// items := make([]*service_dto.SimpleServiceItem, 0, len(services))
// for _, p := range services {
//
// items = append(items, &service_dto.SimpleServiceItem{
// Id: p.Id,
// Name: p.Name,
// Description: p.Description,
// Team: auto.UUID(p.Team),
// })
// }
// return items, nil
//}
func (i *imlServiceModule) Simple(ctx context.Context) ([]*service_dto.SimpleServiceItem, error) {
w := make(map[string]interface{})
w["as_server"] = true
services, err := i.serviceService.Search(ctx, "", w)
if err != nil {
return nil, err
}
items := make([]*service_dto.SimpleServiceItem, 0, len(services))
for _, p := range services {
items = append(items, &service_dto.SimpleServiceItem{
Id: p.Id,
Name: p.Name,
Description: p.Description,
Team: auto.UUID(p.Team),
})
}
return items, nil
}
func (i *imlServiceModule) MySimple(ctx context.Context) ([]*service_dto.SimpleServiceItem, error) {
services, err := i.searchMyServices(ctx, "", "")
if err != nil {
return nil, err
}
items := make([]*service_dto.SimpleServiceItem, 0, len(services))
for _, p := range services {
items = append(items, &service_dto.SimpleServiceItem{
Id: p.Id,
Name: p.Name,
Description: p.Description,
Team: auto.UUID(p.Team),
})
}
return items, nil
}
func (i *imlServiceModule) Get(ctx context.Context, id string) (*service_dto.Service, error) {
now := time.Now()
+10 -4
View File
@@ -4,6 +4,8 @@ import (
"context"
"reflect"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
"github.com/APIParkLab/APIPark/module/system"
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
@@ -25,11 +27,11 @@ type IServiceModule interface {
// Delete 删除项目
Delete(ctx context.Context, id string) error
// Simple 获取简易项目列表
//Simple(ctx context.Context, keyword string) ([]*service_dto.SimpleServiceItem, error)
//Simple 获取简易项目列表
Simple(ctx context.Context) ([]*service_dto.SimpleServiceItem, error)
// MySimple 获取我的简易项目列表
//MySimple(ctx context.Context, keyword string) ([]*service_dto.SimpleServiceItem, error)
//MySimple 获取我的简易项目列表
MySimple(ctx context.Context) ([]*service_dto.SimpleServiceItem, error)
}
type IServiceDocModule interface {
@@ -83,4 +85,8 @@ func init() {
return reflect.ValueOf(serviceDocModule)
})
filter := new(imlAppFilter)
autowire.Autowired(filter)
strategy_filter.RegisterRemoteFilter(filter)
}
@@ -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"`
}
@@ -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
}
@@ -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": {},
}
+11
View File
@@ -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
}
+52
View File
@@ -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)
}
+44
View File
@@ -0,0 +1,44 @@
package strategy_dto
const (
ScopeGlobal = "global"
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 ScopeGlobal
case 1:
return ScopeTeam
case 2:
return ScopeService
default:
return ScopeGlobal
}
}
func (s Scope) Int() int {
return int(s)
}
func ToScope(s string) Scope {
switch s {
case ScopeGlobal:
return 0
case ScopeTeam:
return 1
case ScopeService:
return 2
default:
return 0
}
}
+29
View File
@@ -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"`
}
+114
View File
@@ -0,0 +1,114 @@
package strategy_dto
import (
"encoding/json"
"time"
"github.com/APIParkLab/APIPark/service/strategy"
"github.com/eolinker/go-common/auto"
)
func StrategyStatus(s *strategy.Strategy, publishVersion string) string {
publishStatus := PublishStatusOffline
if publishVersion != "" {
if s.IsDelete {
publishStatus = PublishStatusDelete
} else {
version := s.UpdateAt.Format("20060102150405")
if version != publishVersion {
publishStatus = PublishStatusUpdate
} else {
publishStatus = PublishStatusOnline
}
}
}
return publishStatus
}
func ToStrategyItem(s *strategy.Strategy, publishVersion string, filters 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: s.Priority,
Desc: s.Desc,
Filters: filters,
Updater: auto.UUID(s.Updater),
UpdateTime: auto.TimeLabel(s.UpdateAt),
ProcessedTotal: 0,
PublishStatus: publishStatus,
IsStop: s.IsStop,
IsDelete: s.IsDelete,
}
}
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"`
IsDelete bool `json:"is_delete"`
}
type FilterOption struct {
Name string `json:"name"`
Title string `json:"title"`
Type string `json:"type"`
Pattern string `json:"pattern"`
Options []string `json:"options"`
}
type Title struct {
Field string `json:"field"`
Title string `json:"title" aoi18n:""`
}
type ToPublishItem struct {
Name string `json:"name"`
Priority int `json:"priority"`
Status string `json:"status"`
OptTime time.Time `json:"opt_time"`
}
+232
View File
@@ -0,0 +1,232 @@
package strategy
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"gorm.io/gorm"
"github.com/eolinker/eosc/log"
strategy_filter "github.com/APIParkLab/APIPark/strategy-filter"
"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) ToPublish(ctx context.Context, driver string) ([]*strategy_dto.ToPublishItem, error) {
scope := strategy_dto.ToScope(strategy_dto.ScopeGlobal)
list, err := i.strategyService.SearchAll(ctx, "", driver, scope.Int(), "")
if err != nil {
return nil, err
}
strategyIds := utils.SliceToSlice(list, func(l *strategy.Strategy) string { return l.Id })
commits, err := i.strategyService.ListLatestStrategyCommit(ctx, scope.String(), "", strategyIds...)
if err != nil {
return nil, err
}
commitMap := utils.SliceToMapO(commits, func(c *commit.Commit[strategy.StrategyCommit]) (string, string) { return c.Key, c.Data.Version })
items := make([]*strategy_dto.ToPublishItem, 0, len(list))
for _, l := range list {
status := strategy_dto.StrategyStatus(l, commitMap[l.Id])
if status == strategy_dto.PublishStatusOnline {
continue
}
items = append(items, &strategy_dto.ToPublishItem{
Name: l.Name,
Priority: l.Priority,
Status: status,
OptTime: l.UpdateAt,
})
}
return items, nil
}
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 {
fs := make([]*strategy_dto.Filter, 0)
json.Unmarshal([]byte(l.Filters), &fs)
filterList := make([]string, 0, len(fs))
for _, f := range fs {
info, err := strategy_filter.FilterLabel(f.Name, f.Values)
if err != nil {
log.Errorf("get filter label error: %v", err)
continue
}
filterList = append(filterList, fmt.Sprintf("[%s:%s]", info.Title, info.Label))
}
item := strategy_dto.ToStrategyItem(l, commitMap[l.Id], strings.Join(filterList, ";"))
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
}
s := strategy_dto.ToStrategy(info)
for _, f := range s.Filters {
ff, has := strategy_filter.FilterGet(f.Name)
if !has {
return nil, fmt.Errorf("filter not found: %s", f.Name)
}
f.Title = ff.Title()
f.Type = ff.Type()
f.Label = strings.Join(ff.Labels(f.Values...), ",")
}
return s, 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_filter.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_filter.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, driver string, scope string, target string) error {
list, err := i.strategyService.AllByScope(ctx, driver, 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 {
_, err := i.strategyService.LatestStrategyCommit(ctx, strategy_dto.ScopeGlobal, "", id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return i.strategyService.Delete(ctx, id)
}
return i.strategyService.SortDelete(ctx, id)
}
+30
View File
@@ -0,0 +1,30 @@
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, driver string, scope string, target string) error
Delete(ctx context.Context, id string) error
ToPublish(ctx context.Context, driver string) ([]*strategy_dto.ToPublishItem, error)
}
func init() {
strategyModule := new(imlStrategyModule)
autowire.Auto[IStrategyModule](func() reflect.Value {
return reflect.ValueOf(strategyModule)
})
}
+1
View File
@@ -7,6 +7,7 @@ import (
type InputSetting struct {
InvokeAddress string `json:"invoke_address" key:"system.node.invoke_address"`
SitePrefix string `json:"site_prefix" key:"system.setting.site_prefix"`
}
func (i *InputSetting) Validate() error {
+1
View File
@@ -7,6 +7,7 @@ import (
type Setting struct {
InvokeAddress string `json:"invoke_address" key:"system.node.invoke_address"`
SitePrefix string `json:"site_prefix" key:"system.setting.site_prefix"`
}
func MapStringToStruct[T any](m map[string]string) *T {
+2 -1
View File
@@ -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
}
+1 -1
View File
@@ -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),
+4
View File
@@ -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 {
+5
View File
@@ -17,5 +17,10 @@ func (p *plugin) monitorStatisticApis() []pm3.Api {
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/monitor/config", []string{"context", "body"}, []string{"info"}, p.monitorConfigController.SaveMonitorConfig, access.SystemSettingsDataSourceManager),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/monitor/config", []string{"context"}, []string{"info"}, p.monitorConfigController.GetMonitorConfig, access.SystemSettingsDataSourceView),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/monitor/clusters", []string{"context"}, []string{"clusters"}, p.monitorConfigController.GetMonitorCluster),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/monitor/:data_type", []string{"context", "rest:data_type", "body"}, []string{"statistics"}, p.monitorStatisticController.Statistics),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/monitor/:data_type/trend", []string{"context", "rest:data_type", "query:id", "body"}, []string{"tendency", "time_interval"}, p.monitorStatisticController.InvokeTrend),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/monitor/:data_type/trend/:typ", []string{"context", "rest:data_type", "rest:typ", "query:api", "query:provider", "query:subscriber", "body"}, []string{"tendency", "time_interval"}, p.monitorStatisticController.InvokeTrendInner),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/monitor/:data_type/statistics/:typ", []string{"context", "rest:data_type", "rest:typ", "query:id", "body"}, []string{"statistics"}, p.monitorStatisticController.StatisticsInner),
}
}
+2
View File
@@ -15,6 +15,8 @@ func (p *plugin) ServiceApis() []pm3.Api {
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/service/info", []string{"context", "query:service"}, nil, p.serviceController.Delete, access.SystemWorkspaceServiceManagerAll, access.TeamTeamServiceManager),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/my_services", []string{"context", "query:team", "query:keyword"}, []string{"services"}, p.serviceController.SearchMyServices),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/services", []string{"context", "query:team", "query:keyword"}, []string{"services"}, p.serviceController.Search, access.SystemWorkspaceServiceViewAll, access.TeamTeamServiceView),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/services", []string{"context"}, []string{"services"}, p.serviceController.Simple),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/services/mine", []string{"context"}, []string{"services"}, p.serviceController.MySimple),
// 应用相关
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/app/info", []string{"context", "query:app"}, []string{"app"}, p.appController.GetApp, access.SystemWorkspaceApplicationViewAll, access.TeamTeamConsumerView),
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/app", []string{"context", "query:app"}, nil, p.appController.DeleteApp, access.SystemWorkspaceApplicationManagerAll, access.TeamTeamConsumerManager),
+33
View File
@@ -0,0 +1,33 @@
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.MethodPatch, "/api/v1/strategy/global/:driver/enable", []string{"context", "query:strategy"}, nil, p.strategyController.EnableStrategy),
pm3.CreateApiWidthDoc(http.MethodPatch, "/api/v1/strategy/global/:driver/disable", []string{"context", "query:strategy"}, nil, p.strategyController.DisableStrategy),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/strategy/global/:driver/publish", []string{"context", "rest:driver"}, nil, p.strategyController.PublishGlobalStrategy),
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.MethodPatch, "/api/v1/strategy/service/:driver/enable", []string{"context", "query:strategy"}, nil, p.strategyController.EnableStrategy),
pm3.CreateApiWidthDoc(http.MethodPatch, "/api/v1/strategy/service/:driver/disable", []string{"context", "query:strategy"}, nil, p.strategyController.DisableStrategy),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/global/filter-options", []string{"context"}, []string{"options"}, p.strategyController.FilterGlobalOptions),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/service/filter-options", []string{"context"}, []string{"options"}, p.strategyController.FilterServiceOptions),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/filter-remote/:name", []string{"context", "rest:name"}, []string{"titles", "list", "total", "key", "value"}, p.strategyController.FilterGlobalRemote),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/service/filter-remote/:name", []string{"context", "query:service", "rest:name"}, []string{"titles", "list", "total", "key", "value"}, p.strategyController.FilterServiceRemote),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/strategy/global/:driver/to-publishs", []string{"context", "rest:driver"}, []string{"strategies", "source", "version_name", "is_publish"}, p.strategyController.ToPublish),
}
}
+9 -1
View File
@@ -5,12 +5,18 @@
"api": "API",
"api doc": "API文档",
"api gateway": "API网关",
"api method": "API请求方法",
"api name": "API名称",
"api path": "API路径",
"all method": "全部请求方式",
"api portal": "API门户",
"authorization": "访问授权",
"consumer": "消费者",
"consumer id": "消费者ID",
"consumer admin": "消费者管理员",
"consumer developer": "消费者开发者",
"create": "创建",
"description": "描述",
"data source": "数据源",
"devops admin": "运维管理员",
"general": "常规设置",
@@ -42,5 +48,7 @@
"view all service": "查看所有服务",
"view all team": "查看所有团队",
"view subscribed services": "查看已经订阅的服务",
"workspace": "工作空间"
"workspace": "工作空间",
"request path": "请求路径",
"methods": "请求方法"
}
+24
View File
@@ -41,6 +41,30 @@ type imlAPIService struct {
universally.IServiceDelete
}
func (i *imlAPIService) ListForServices(ctx context.Context, serviceIds ...string) ([]*API, error) {
w := map[string]interface{}{}
if len(serviceIds) > 0 {
w["service"] = serviceIds
}
list, err := i.store.List(ctx, w)
if err != nil {
return nil, err
}
return utils.SliceToSlice(list, FromEntity), nil
}
func (i *imlAPIService) ListInfoForServices(ctx context.Context, serviceIds ...string) ([]*Info, error) {
w := map[string]interface{}{}
if len(serviceIds) > 0 {
w["service"] = serviceIds
}
list, err := i.apiInfoStore.List(ctx, w)
if err != nil {
return nil, err
}
return utils.SliceToSlice(list, FromEntityInfo), nil
}
func (i *imlAPIService) ListLatestCommitRequest(ctx context.Context, aid ...string) ([]*commit.Commit[Request], error) {
return i.requestCommitService.ListLatest(ctx, aid...)
}
+2
View File
@@ -17,9 +17,11 @@ type IAPIService interface {
CountMapByService(ctx context.Context, service ...string) (map[string]int64, error)
Exist(ctx context.Context, aid string, api *Exist) error
ListForService(ctx context.Context, serviceId string) ([]*API, error)
ListForServices(ctx context.Context, serviceIds ...string) ([]*API, error)
GetInfo(ctx context.Context, aid string) (*Info, error)
ListInfo(ctx context.Context, aids ...string) ([]*Info, error)
ListInfoForService(ctx context.Context, serviceId string) ([]*Info, error)
ListInfoForServices(ctx context.Context, serviceIds ...string) ([]*Info, error)
ListLatestCommitProxy(ctx context.Context, aid ...string) ([]*commit.Commit[Proxy], error)
LatestProxy(ctx context.Context, aid string) (*commit.Commit[Proxy], error)
+1
View File
@@ -14,6 +14,7 @@ var (
const (
KeyInvokeAddress = "system.node.invoke_address"
KeySitePrefix = "system.setting.site_prefix"
)
type imlSettingService struct {
+198
View File
@@ -0,0 +1,198 @@
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) SearchAll(ctx context.Context, keyword string, driver string, scope int, target string) ([]*Strategy, error) {
w := make(map[string]interface{})
w["scope"] = scope
if target != "" {
w["target"] = target
}
list, err := i.store.Search(ctx, keyword, w, "update_at")
if err != nil {
return nil, err
}
return utils.SliceToSlice(list, FromEntity), nil
}
func (i *imlStrategyService) AllByScope(ctx context.Context, driver string, scope int, target string) ([]*Strategy, error) {
w := make(map[string]interface{})
w["scope"] = scope
if target != "" {
w["target"] = target
}
w["driver"] = driver
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,
Driver: i.Driver,
Scope: i.Scope,
Target: i.Target,
CreateAt: now,
UpdateAt: now,
IsStop: false,
IsDelete: false,
}
}
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
}
}
+77
View File
@@ -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
}
+36
View File
@@ -0,0 +1,36 @@
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, driver string, 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)
SearchAll(ctx context.Context, keyword string, driver string, scope int, target string) ([]*Strategy, 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")
}
+11 -10
View File
@@ -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
}
+3 -3
View File
@@ -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)
+2 -2
View File
@@ -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...)
}
+1 -1
View File
@@ -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)
+30
View File
@@ -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:int(11);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
}
+20
View File
@@ -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))
})
}
+192
View File
@@ -0,0 +1,192 @@
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)
}
+58
View File
@@ -0,0 +1,58 @@
package strategy_filter
import "regexp"
var (
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]))?$`
)
var _ IFilter = &ipFilter{}
func init() {
filterHandler.RegisterFilter(newIpFilter())
}
type ipFilter struct {
name string
title string
typ string
pattern *regexp.Regexp
}
func newIpFilter() *ipFilter {
return &ipFilter{
name: "ip",
title: "IP",
typ: TypePattern,
pattern: regexp.MustCompile(CIDRIpv4Exp),
}
}
func (i *ipFilter) Name() string {
return i.name
}
func (i *ipFilter) Title() string {
return i.title
}
func (i *ipFilter) Labels(values ...string) []string {
return values
}
func (i *ipFilter) Type() string {
return i.typ
}
func (i *ipFilter) Scopes() []string {
return []string{ScopeGlobal, ScopeService}
}
func (i *ipFilter) Option() *Option {
return &Option{
Name: i.name,
Title: i.title,
Type: i.typ,
Pattern: i.pattern,
}
}
+60
View File
@@ -0,0 +1,60 @@
package strategy_filter
import "net/http"
var _ IFilter = &methodFilter{}
func init() {
filterHandler.RegisterFilter(newMethodFilter())
}
type methodFilter struct {
name string
title string
typ string
options []string
}
func newMethodFilter() *methodFilter {
return &methodFilter{
name: "method",
title: "api method",
typ: TypeStatic,
options: []string{HttpALL, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch, http.MethodHead, http.MethodOptions},
}
}
func (m *methodFilter) Name() string {
return m.name
}
func (m *methodFilter) Title() string {
return m.title
}
func (m *methodFilter) Labels(values ...string) []string {
if len(values) > 0 && values[0] != ValuesALL {
return []string{"all method"}
}
if len(values) == 0 {
return []string{"-"}
}
return values
}
func (m *methodFilter) Type() string {
return m.typ
}
func (m *methodFilter) Scopes() []string {
return []string{ScopeGlobal, ScopeService}
}
func (m *methodFilter) Option() *Option {
return &Option{
Name: m.name,
Title: m.title,
Type: m.typ,
Options: m.options,
}
}
+58
View File
@@ -0,0 +1,58 @@
package strategy_filter
import "regexp"
var _ IFilter = &pathFilter{}
var (
ApiPathRegexp = `^\*?[\w-/]+\*?$`
)
type pathFilter struct {
name string
title string
typ string
pattern *regexp.Regexp
}
func init() {
filterHandler.RegisterFilter(newPathFilter())
}
func newPathFilter() *pathFilter {
return &pathFilter{
name: "path",
title: "api path",
typ: TypePattern,
pattern: regexp.MustCompile(ApiPathRegexp),
}
}
func (p *pathFilter) Name() string {
return p.name
}
func (p *pathFilter) Title() string {
return p.title
}
func (p *pathFilter) Labels(values ...string) []string {
return values
}
func (p *pathFilter) Type() string {
return p.typ
}
func (p *pathFilter) Scopes() []string {
return []string{ScopeGlobal, ScopeService}
}
func (p *pathFilter) Option() *Option {
return &Option{
Name: p.name,
Title: p.title,
Type: p.typ,
Pattern: p.pattern,
}
}