Files
2025-04-29 00:34:58 +08:00

378 lines
9.4 KiB
Go

package router
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/APIParkLab/APIPark/service/universally/commit"
"github.com/APIParkLab/APIPark/service/service"
"github.com/APIParkLab/APIPark/service/upstream"
"gorm.io/gorm"
"github.com/APIParkLab/APIPark/service/team"
"github.com/google/uuid"
"github.com/eolinker/go-common/auto"
"github.com/eolinker/go-common/utils"
"github.com/eolinker/go-common/store"
"github.com/APIParkLab/APIPark/service/api"
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
)
var (
_ IRouterModule = (*imlRouterModule)(nil)
_ IExportRouterModule = (*imlRouterModule)(nil)
)
var (
asServer = map[string]bool{
"as_server": true,
}
)
type imlRouterModule struct {
teamService team.ITeamService `autowired:""`
serviceService service.IServiceService `autowired:""`
apiService api.IAPIService `autowired:""`
upstreamService upstream.IUpstreamService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlRouterModule) SimpleAPIs(ctx context.Context, input *router_dto.InputSimpleAPI) ([]*router_dto.SimpleItem, error) {
list, err := i.apiService.ListForServices(ctx, input.Services...)
if err != nil {
return nil, err
}
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
return s.UUID
})...)
if err != nil {
return nil, err
}
return utils.SliceToSlice(apiInfos, func(item *api.Info) *router_dto.SimpleItem {
return &router_dto.SimpleItem{
Id: item.UUID,
Name: item.Name,
Methods: item.Methods,
Path: item.Path,
}
}), nil
}
func (i *imlRouterModule) ExportAll(ctx context.Context) ([]*router_dto.Export, error) {
apiList, err := i.apiService.ListInfo(ctx)
if err != nil {
return nil, err
}
apiIds := utils.SliceToSlice(apiList, func(a *api.Info) string {
return a.UUID
})
proxyCommits, err := i.apiService.ListLatestCommitProxy(ctx, apiIds...)
if err != nil {
return nil, err
}
proxyCommitMap := utils.SliceToMap(proxyCommits, func(c *commit.Commit[api.Proxy]) string {
return c.Target
})
return utils.SliceToSlice(apiList, func(a *api.Info) *router_dto.Export {
match := make([]router_dto.Match, 0)
if a.Match == "" {
a.Match = "[]"
}
json.Unmarshal([]byte(a.Match), &match)
info := &router_dto.Export{
Id: a.UUID,
Name: a.Name,
Description: a.Description,
Path: a.Path,
MatchRules: match,
Service: a.Service,
Team: a.Team,
}
if v, ok := proxyCommitMap[a.UUID]; ok {
info.Proxy = router_dto.FromServiceProxy(v.Data)
}
return info
}), nil
}
func (i *imlRouterModule) SimpleList(ctx context.Context, serviceId string) ([]*router_dto.SimpleItem, error) {
list, err := i.apiService.ListForService(ctx, serviceId)
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
return s.UUID
})...)
if err != nil {
return nil, err
}
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *router_dto.SimpleItem {
return &router_dto.SimpleItem{
Id: item.UUID,
Path: item.Path,
}
})
return out, nil
}
func (i *imlRouterModule) Detail(ctx context.Context, serviceId string, apiId string) (*router_dto.Detail, error) {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
detail, err := i.apiService.GetInfo(ctx, apiId)
if err != nil {
return nil, err
}
protocols := []string{"HTTP", "HTTPS"}
if len(detail.Protocols) > 0 {
protocols = detail.Protocols
}
apiDetail := &router_dto.Detail{
SimpleDetail: *router_dto.GenSimpleDetail(detail),
Protocols: protocols,
Disable: detail.Disable,
}
proxy, err := i.apiService.LatestProxy(ctx, apiId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
}
if proxy != nil {
apiDetail.Proxy = router_dto.FromServiceProxy(proxy.Data)
}
return apiDetail, nil
}
func (i *imlRouterModule) SimpleDetail(ctx context.Context, serviceId string, apiId string) (*router_dto.SimpleDetail, error) {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
detail, err := i.apiService.GetInfo(ctx, apiId)
if err != nil {
return nil, err
}
return router_dto.GenSimpleDetail(detail), nil
}
func (i *imlRouterModule) Search(ctx context.Context, keyword string, serviceId string) ([]*router_dto.Item, error) {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
list, err := i.apiService.Search(ctx, keyword, map[string]interface{}{
"service": serviceId,
})
if err != nil {
return nil, err
}
if len(list) == 0 {
return []*router_dto.Item{}, nil
}
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
return s.UUID
})...)
if err != nil {
return nil, err
}
utils.Sort(apiInfos, func(a, b *api.Info) bool {
return a.UpdateAt.After(b.UpdateAt)
})
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *router_dto.Item {
protocols := []string{"HTTP", "HTTPS"}
if len(item.Protocols) > 0 {
protocols = item.Protocols
}
return &router_dto.Item{
Id: item.UUID,
Name: item.Name,
Methods: item.Methods,
Protocols: protocols,
Path: item.Path,
Description: item.Description,
Disable: item.Disable,
Creator: auto.UUID(item.Creator),
Updater: auto.UUID(item.Updater),
CreateTime: auto.TimeLabel(item.CreateAt),
UpdateTime: auto.TimeLabel(item.UpdateAt),
CanDelete: true,
}
})
return out, nil
}
func (i *imlRouterModule) SimpleSearch(ctx context.Context, keyword string, serviceId string) ([]*router_dto.SimpleItem, error) {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
list, err := i.apiService.Search(ctx, keyword, map[string]interface{}{
"service": serviceId,
})
if err != nil {
return nil, err
}
apiInfos, err := i.apiService.ListInfo(ctx, utils.SliceToSlice(list, func(s *api.API) string {
return s.UUID
})...)
if err != nil {
return nil, err
}
out := utils.SliceToSlice(apiInfos, func(item *api.Info) *router_dto.SimpleItem {
return &router_dto.SimpleItem{
Id: item.UUID,
Methods: item.Methods,
Path: item.Path,
}
})
return out, nil
}
func (i *imlRouterModule) Create(ctx context.Context, serviceId string, dto *router_dto.Create) (*router_dto.SimpleDetail, error) {
info, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
if dto.Id == "" {
dto.Id = uuid.New().String()
}
err = dto.Validate()
if err != nil {
return err
}
err = i.apiService.Exist(ctx, "", &api.Exist{Path: dto.Path, Methods: dto.Methods})
if err != nil {
return err
}
proxy := router_dto.ToServiceProxy(dto.Proxy)
err = i.apiService.SaveProxy(ctx, dto.Id, proxy)
if err != nil {
return err
}
name := dto.Name
if name == "" {
name = dto.Id
}
match, _ := json.Marshal(dto.MatchRules)
return i.apiService.Create(ctx, &api.Create{
UUID: dto.Id,
Name: name,
Description: dto.Description,
Service: serviceId,
Team: info.Team,
Methods: dto.Methods,
Protocols: dto.Protocols,
Path: dto.Path,
Match: string(match),
Upstream: dto.Upstream,
})
})
if err != nil {
return nil, err
}
return i.SimpleDetail(ctx, serviceId, dto.Id)
}
func (i *imlRouterModule) Edit(ctx context.Context, serviceId string, apiId string, dto *router_dto.Edit) (*router_dto.SimpleDetail, error) {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return nil, err
}
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
if dto.Path != nil {
err = i.apiService.Exist(ctx, apiId, &api.Exist{Path: *dto.Path, Methods: *dto.Methods})
if err != nil {
return err
}
}
if dto.Proxy != nil {
err = i.apiService.SaveProxy(ctx, apiId, router_dto.ToServiceProxy(dto.Proxy))
if err != nil {
return err
}
}
var match *string
if dto.MatchRules != nil {
ml, _ := json.Marshal(dto.MatchRules)
m := string(ml)
match = &m
}
err = i.apiService.Save(ctx, apiId, &api.Edit{
Name: dto.Name,
Description: dto.Description,
Methods: dto.Methods,
Protocols: dto.Protocols,
Disable: dto.Disable,
Path: dto.Path,
Upstream: dto.Upstream,
Match: match,
})
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return i.SimpleDetail(ctx, serviceId, apiId)
}
func (i *imlRouterModule) Delete(ctx context.Context, serviceId string, apiId string) error {
_, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return err
}
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
err = i.apiService.Delete(ctx, apiId)
if err != nil {
return err
}
return i.apiService.DeleteAPIInfo(ctx, apiId)
})
}
func (i *imlRouterModule) Prefix(ctx context.Context, serviceId string) (string, error) {
pInfo, err := i.serviceService.Check(ctx, serviceId, asServer)
if err != nil {
return "", err
}
if pInfo.Prefix != "" {
if pInfo.Prefix[0] != '/' {
pInfo.Prefix = fmt.Sprintf("/%s", strings.TrimSuffix(pInfo.Prefix, "/"))
}
}
return strings.TrimSuffix(pInfo.Prefix, "/"), nil
}