diff --git a/module/ai-api/iml.go b/module/ai-api/iml.go index 25eda7f7..bc4cac80 100644 --- a/module/ai-api/iml.go +++ b/module/ai-api/iml.go @@ -8,6 +8,8 @@ import ( "net/http" "strings" + service_overview "github.com/APIParkLab/APIPark/service/service-overview" + ai_provider_local "github.com/APIParkLab/APIPark/ai-provider/local" model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime" @@ -35,12 +37,13 @@ var ( ) type imlAPIModule struct { - serviceService service.IServiceService `autowired:""` - apiDocService api_doc.IAPIDocService `autowired:""` - aiAPIService ai_api.IAPIService `autowired:""` - aiModelService ai_model.IProviderModelService `autowired:""` - apiService api.IAPIService `autowired:""` - transaction store.ITransaction `autowired:""` + serviceService service.IServiceService `autowired:""` + serviceOverviewService service_overview.IOverviewService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + aiAPIService ai_api.IAPIService `autowired:""` + aiModelService ai_model.IProviderModelService `autowired:""` + apiService api.IAPIService `autowired:""` + transaction store.ITransaction `autowired:""` } func (i *imlAPIModule) getAPIDoc(ctx context.Context, serviceId string) (*openapi3.T, error) { @@ -77,9 +80,17 @@ func (i *imlAPIModule) updateAPIDoc(ctx context.Context, serviceId, serviceName, if err != nil { return err } - return i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ - ID: uuid.New().String(), - Content: string(result), + return i.transaction.Transaction(ctx, func(ctx context.Context) error { + count, err := i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ + ID: uuid.New().String(), + Content: string(result), + }) + if err != nil { + return fmt.Errorf("update api doc error:%v", err) + } + return i.serviceOverviewService.Update(ctx, serviceId, &service_overview.Update{ + ApiCount: &count, + }) }) } @@ -93,10 +104,19 @@ func (i *imlAPIModule) deleteAPIDoc(ctx context.Context, serviceId string, path if err != nil { return err } - return i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ - ID: uuid.New().String(), - Content: string(result), + return i.transaction.Transaction(ctx, func(ctx context.Context) error { + count, err := i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ + ID: uuid.New().String(), + Content: string(result), + }) + if err != nil { + return fmt.Errorf("update api doc error:%v", err) + } + return i.serviceOverviewService.Update(ctx, serviceId, &service_overview.Update{ + ApiCount: &count, + }) }) + } func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) error { diff --git a/module/api-doc/api_doc.go b/module/api-doc/api_doc.go index d83e74cd..76af1b7d 100644 --- a/module/api-doc/api_doc.go +++ b/module/api-doc/api_doc.go @@ -3,6 +3,11 @@ package api_doc import ( "context" "errors" + "fmt" + + "github.com/eolinker/go-common/store" + + service_overview "github.com/APIParkLab/APIPark/service/service-overview" api_doc_dto "github.com/APIParkLab/APIPark/module/api-doc/dto" api_doc "github.com/APIParkLab/APIPark/service/api-doc" @@ -16,8 +21,10 @@ import ( var _ IAPIDocModule = (*imlAPIDocModule)(nil) type imlAPIDocModule struct { - apiDocService api_doc.IAPIDocService `autowired:""` - serviceService service.IServiceService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + serviceService service.IServiceService `autowired:""` + serviceOverviewService service_overview.IOverviewService `autowired:""` + transaction store.ITransaction `autowired:""` } func (i *imlAPIDocModule) UpdateDoc(ctx context.Context, serviceId string, input *api_doc_dto.UpdateDoc) (*api_doc_dto.ApiDocDetail, error) { @@ -29,11 +36,18 @@ func (i *imlAPIDocModule) UpdateDoc(ctx context.Context, serviceId string, input input.Id = uuid.New().String() } // 每个API加上前缀 - - err = i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ - ID: input.Id, - Content: input.Content, - Prefix: info.Prefix, + err = i.transaction.Transaction(ctx, func(ctx context.Context) error { + count, err := i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{ + ID: input.Id, + Content: input.Content, + Prefix: info.Prefix, + }) + if err != nil { + return fmt.Errorf("update api doc error:%v", err) + } + return i.serviceOverviewService.Update(ctx, serviceId, &service_overview.Update{ + ApiCount: &count, + }) }) if err != nil { return nil, err diff --git a/module/catalogue/iml.go b/module/catalogue/iml.go index cbea8773..39e56a22 100644 --- a/module/catalogue/iml.go +++ b/module/catalogue/iml.go @@ -9,6 +9,8 @@ import ( "strings" "time" + service_overview "github.com/APIParkLab/APIPark/service/service-overview" + mcp_server "github.com/APIParkLab/APIPark/mcp-server" "github.com/APIParkLab/APIPark/module/monitor/driver" @@ -58,23 +60,73 @@ var ( ) type imlCatalogueModule struct { - catalogueService catalogue.ICatalogueService `autowired:""` - apiService api.IAPIService `autowired:""` - apiDocService api_doc.IAPIDocService `autowired:""` - serviceService service.IServiceService `autowired:""` - serviceTagService service_tag.ITagService `autowired:""` - serviceDocService service_doc.IDocService `autowired:""` - tagService tag.ITagService `autowired:""` - releaseService release.IReleaseService `autowired:""` - subscribeService subscribe.ISubscribeService `autowired:""` - subscribeApplyService subscribe.ISubscribeApplyService `autowired:""` - transaction store.ITransaction `autowired:""` - clusterService cluster.IClusterService `autowired:""` - settingService setting.ISettingService `autowired:""` - monitorService monitor.IMonitorService `autowired:""` - root *Root + catalogueService catalogue.ICatalogueService `autowired:""` + apiService api.IAPIService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + serviceService service.IServiceService `autowired:""` + serviceOverviewService service_overview.IOverviewService `autowired:""` + serviceTagService service_tag.ITagService `autowired:""` + serviceDocService service_doc.IDocService `autowired:""` + tagService tag.ITagService `autowired:""` + releaseService release.IReleaseService `autowired:""` + subscribeService subscribe.ISubscribeService `autowired:""` + subscribeApplyService subscribe.ISubscribeApplyService `autowired:""` + transaction store.ITransaction `autowired:""` + clusterService cluster.IClusterService `autowired:""` + settingService setting.ISettingService `autowired:""` + monitorService monitor.IMonitorService `autowired:""` + root *Root } +//func (i *imlCatalogueModule) OnInit() { +// register.Handle(func(v server.Server) { +// ctx := context.Background() +// list, err := i.releaseService.GetRunningList(ctx) +// if err != nil { +// log.Errorf("onInit: get running list failed:%s", err.Error()) +// return +// } +// if len(list) < 1 || list[0].APICount > 0 { +// return +// } +// serviceMap := make(map[string]*release.Release) +// serviceIds := make([]string, 0, len(list)) +// for _, v := range list { +// if _, ok := serviceMap[v.Service]; !ok { +// serviceMap[v.Service] = v +// serviceIds = append(serviceIds, v.Service) +// } +// } +// if len(serviceIds) < 1 { +// return +// } +// commitIds, err := i.releaseService.GetRunningApiDocCommits(ctx, serviceIds...) +// if err != nil { +// log.Errorf("onInit: get running api doc commits failed:%s", err.Error()) +// return +// } +// if len(commitIds) < 1 { +// return +// } +// listCommits, err := i.apiDocService.ListDocCommit(ctx, commitIds...) +// if err != nil { +// log.Error("onInit: list doc commit failed:", err.Error()) +// return +// } +// for _, v := range listCommits { +// m, ok := serviceMap[v.Target] +// if !ok { +// continue +// } +// +// i.releaseService.UpdateRelease(ctx, m.UUID, &release.Update{ +// APICount: &v.Data.APICount, +// }) +// } +// }) +// +//} + func (i *imlCatalogueModule) DefaultCatalogue(ctx context.Context) (*catalogue_dto.Catalogue, error) { catalogues, err := i.catalogueService.List(ctx) if err != nil { @@ -447,25 +499,24 @@ func (i *imlCatalogueModule) Services(ctx context.Context, keyword string) ([]*c if err != nil { return nil, err } - serviceIds := utils.SliceToSlice(items, func(i *service.Service) string { return i.Id - }, func(s *service.Service) bool { - // 未发布的不给展示 - _, err = i.releaseService.GetRunning(ctx, s.Id) - return err == nil }) - if len(serviceIds) < 1 { - return nil, nil - } - - commits, err := i.releaseService.GetRunningApiDocCommits(ctx, serviceIds...) + overviewMap, err := i.serviceOverviewService.Map(ctx, serviceIds...) if err != nil { return nil, err } - apiCountMap, err := i.apiDocService.LatestAPICountByCommits(ctx, commits...) - if err != nil { - return nil, err + serviceIds = utils.SliceToSlice(serviceIds, func(s string) string { + return s + }, func(s string) bool { + // 只展示已发布的服务 + if info, ok := overviewMap[s]; ok && info.IsReleased { + return true + } + return false + }) + if len(serviceIds) < 1 { + return nil, nil } subscriberCountMap, err := i.subscribeService.CountMapByService(ctx, subscribe.ApplyStatusSubscribe, serviceIds...) @@ -479,8 +530,9 @@ func (i *imlCatalogueModule) Services(ctx context.Context, keyword string) ([]*c result := make([]*catalogue_dto.ServiceItem, 0, len(items)) for _, v := range items { - apiNum, ok := apiCountMap[v.Id] - if !ok || apiNum < 1 { + + ov, ok := overviewMap[v.Id] + if !ok || ov.ReleaseApiCount < 1 { continue } @@ -489,8 +541,8 @@ func (i *imlCatalogueModule) Services(ctx context.Context, keyword string) ([]*c Name: v.Name, Tags: auto.List(serviceTagMap[v.Id]), Catalogue: auto.UUID(v.Catalogue), - ApiNum: apiNum, SubscriberNum: subscriberCountMap[v.Id], + ApiNum: ov.ReleaseApiCount, Description: v.Description, Logo: v.Logo, EnableMCP: v.EnableMCP, diff --git a/module/publish/iml.go b/module/publish/iml.go index 05e02899..9855d228 100644 --- a/module/publish/iml.go +++ b/module/publish/iml.go @@ -7,6 +7,12 @@ import ( "fmt" "time" + "github.com/eolinker/go-common/server" + + "github.com/eolinker/go-common/register" + + service_overview "github.com/APIParkLab/APIPark/service/service-overview" + mcp_server "github.com/APIParkLab/APIPark/mcp-server" api_doc "github.com/APIParkLab/APIPark/service/api-doc" "github.com/mark3labs/mcp-go/mcp" @@ -51,22 +57,70 @@ var ( ) type imlPublishModule struct { - projectDiffModule serviceDiff.IServiceDiffModule `autowired:""` - releaseModule releaseModule.IReleaseModule `autowired:""` - publishService publish.IPublishService `autowired:""` - apiService api.IAPIService `autowired:""` - apiDocService api_doc.IAPIDocService `autowired:""` - upstreamService upstream.IUpstreamService `autowired:""` - strategyService strategy.IStrategyService `autowired:""` - releaseService release.IReleaseService `autowired:""` - clusterService cluster.IClusterService `autowired:""` - serviceService service.IServiceService `autowired:""` - transaction store.ITransaction `autowired:""` + projectDiffModule serviceDiff.IServiceDiffModule `autowired:""` + releaseModule releaseModule.IReleaseModule `autowired:""` + publishService publish.IPublishService `autowired:""` + apiService api.IAPIService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + upstreamService upstream.IUpstreamService `autowired:""` + strategyService strategy.IStrategyService `autowired:""` + releaseService release.IReleaseService `autowired:""` + clusterService cluster.IClusterService `autowired:""` + serviceService service.IServiceService `autowired:""` + serviceOverviewService service_overview.IOverviewService `autowired:""` + transaction store.ITransaction `autowired:""` +} + +func (i *imlPublishModule) OnInit() { + register.Handle(func(v server.Server) { + ctx := context.Background() + list, err := i.releaseService.GetRunningList(ctx) + if err != nil { + log.Errorf("onInit: get running list failed:%s", err.Error()) + return + } + if len(list) < 1 { + return + } + + serviceMap := make(map[string]*release.Release) + serviceIds := make([]string, 0, len(list)) + for _, v := range list { + if _, ok := serviceMap[v.Service]; !ok { + serviceMap[v.Service] = v + serviceIds = append(serviceIds, v.Service) + } + } + overviewList, err := i.serviceOverviewService.List(ctx, serviceIds...) + if err != nil { + log.Errorf("onInit: get running list failed:%s", err.Error()) + return + } + for _, v := range overviewList { + if v.IsReleased { + return + } + } + + listCommits, err := i.apiDocService.ListLatestDocCommit(ctx, serviceIds...) + if err != nil { + log.Errorf("onInit: get running api doc commits failed:%s", err.Error()) + return + } + isReleased := true + for _, v := range listCommits { + i.serviceOverviewService.Update(ctx, v.Target, &service_overview.Update{ + ApiCount: nil, + ReleaseApiCount: &v.Data.APICount, + IsReleased: &isReleased, + }) + } + }) } -func (m *imlPublishModule) initGateway(ctx context.Context, partitionId string, clientDriver gateway.IClientDriver) error { +func (i *imlPublishModule) initGateway(ctx context.Context, partitionId string, clientDriver gateway.IClientDriver) error { return nil - //projects, err := m.serviceService.List(ctx) + //projects, err := i.serviceService.List(ctx) //if err != nil { // return err //} @@ -74,7 +128,7 @@ func (m *imlPublishModule) initGateway(ctx context.Context, partitionId string, // return p.Id //}) //for _, projectId := range projectIds { - // releaseInfo, err := m.GetProjectRelease(ctx, projectId, partitionId) + // releaseInfo, err := i.GetProjectRelease(ctx, projectId, partitionId) // if err != nil { // return err // } @@ -90,8 +144,8 @@ func (m *imlPublishModule) initGateway(ctx context.Context, partitionId string, //return nil } -func (m *imlPublishModule) getProjectRelease(ctx context.Context, projectID string, commitId string) (*gateway.ProjectRelease, error) { - commits, err := m.releaseService.GetCommits(ctx, commitId) +func (i *imlPublishModule) getProjectRelease(ctx context.Context, projectID string, commitId string) (*gateway.ProjectRelease, error) { + commits, err := i.releaseService.GetCommits(ctx, commitId) if err != nil { return nil, err } @@ -110,17 +164,17 @@ func (m *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri strategyCommitIds = append(strategyCommitIds, c.Commit) } } - serviceInfo, err := m.serviceService.Get(ctx, projectID) + serviceInfo, err := i.serviceService.Get(ctx, projectID) if err != nil { return nil, err } - apiInfos, err := m.apiService.ListInfo(ctx, apiIds...) + apiInfos, err := i.apiService.ListInfo(ctx, apiIds...) if err != nil { return nil, err } - proxyCommits, err := m.apiService.ListProxyCommit(ctx, apiProxyCommitIds...) + proxyCommits, err := i.apiService.ListProxyCommit(ctx, apiProxyCommitIds...) if err != nil { return nil, err } @@ -177,7 +231,7 @@ func (m *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri r.Apis = apis var upstreamRelease *gateway.UpstreamRelease if len(upstreamCommitIds) > 0 { - upstreamCommits, err := m.upstreamService.ListCommit(ctx, upstreamCommitIds...) + upstreamCommits, err := i.upstreamService.ListCommit(ctx, upstreamCommitIds...) if err != nil { return nil, err } @@ -202,7 +256,7 @@ func (m *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri r.Upstream = upstreamRelease } if len(strategyCommitIds) > 0 { - strategyCommits, err := m.strategyService.ListStrategyCommit(ctx, strategyCommitIds...) + strategyCommits, err := i.strategyService.ListStrategyCommit(ctx, strategyCommitIds...) if err != nil { return nil, err } @@ -234,9 +288,9 @@ func (m *imlPublishModule) getProjectRelease(ctx context.Context, projectID stri return r, nil } -func (m *imlPublishModule) GetProjectRelease(ctx context.Context, projectID string, partitionId string) (*gateway.ProjectRelease, error) { +func (i *imlPublishModule) GetProjectRelease(ctx context.Context, projectID string, partitionId string) (*gateway.ProjectRelease, error) { - releaseInfo, err := m.releaseService.GetRunning(ctx, projectID) + releaseInfo, err := i.releaseService.GetRunning(ctx, projectID) if err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err @@ -244,11 +298,11 @@ func (m *imlPublishModule) GetProjectRelease(ctx context.Context, projectID stri return nil, nil } - return m.getProjectRelease(ctx, projectID, releaseInfo.UUID) + return i.getProjectRelease(ctx, projectID, releaseInfo.UUID) } -func (m *imlPublishModule) getReleaseInfo(ctx context.Context, projectID, releaseId, version string, clusterIds []string) (map[string]*gateway.ProjectRelease, error) { - projectRelease, err := m.getProjectRelease(ctx, projectID, releaseId) +func (i *imlPublishModule) getReleaseInfo(ctx context.Context, projectID, releaseId, version string, clusterIds []string) (map[string]*gateway.ProjectRelease, error) { + projectRelease, err := i.getProjectRelease(ctx, projectID, releaseId) if err != nil { return nil, err } @@ -266,19 +320,19 @@ func (m *imlPublishModule) getReleaseInfo(ctx context.Context, projectID, releas return projectReleaseMap, nil } -func (m *imlPublishModule) PublishStatuses(ctx context.Context, serviceId string, id string) ([]*dto.PublishStatus, error) { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) PublishStatuses(ctx context.Context, serviceId string, id string) ([]*dto.PublishStatus, error) { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return nil, err } - flow, err := m.publishService.Get(ctx, id) + flow, err := i.publishService.Get(ctx, id) if err != nil { return nil, err } if flow.Service != serviceId { return nil, errors.New("服务不一致") } - list, err := m.publishService.GetPublishStatus(ctx, id) + list, err := i.publishService.GetPublishStatus(ctx, id) if err != nil { return nil, err } @@ -302,18 +356,18 @@ func (m *imlPublishModule) PublishStatuses(ctx context.Context, serviceId string // // ctx context.Context, serviceId string, input *dto.ApplyInput // *dto.Publish, error -func (m *imlPublishModule) Apply(ctx context.Context, serviceId string, input *dto.ApplyInput) (*dto.Publish, error) { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Apply(ctx context.Context, serviceId string, input *dto.ApplyInput) (*dto.Publish, error) { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return nil, err } - err = m.checkPublish(ctx, serviceId, input.Release) + err = i.checkPublish(ctx, serviceId, input.Release) if err != nil { return nil, err } previous := "" - running, err := m.releaseService.GetRunning(ctx, serviceId) + running, err := i.releaseService.GetRunning(ctx, serviceId) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err @@ -322,42 +376,42 @@ func (m *imlPublishModule) Apply(ctx context.Context, serviceId string, input *d previous = running.UUID } - releaseToPublish, err := m.releaseService.GetRelease(ctx, input.Release) + releaseToPublish, err := i.releaseService.GetRelease(ctx, input.Release) if err != nil { // 目标版本不存在 return nil, err } newPublishId := uuid.NewString() - diff, ok, err := m.projectDiffModule.DiffForLatest(ctx, serviceId, previous) + diff, ok, err := i.projectDiffModule.DiffForLatest(ctx, serviceId, previous) if err != nil { return nil, err } if !ok { return nil, errors.New("latest completeness check failed") } - err = m.publishService.Create(ctx, newPublishId, serviceId, releaseToPublish.UUID, previous, releaseToPublish.Version, input.Remark, diff) + err = i.publishService.Create(ctx, newPublishId, serviceId, releaseToPublish.UUID, previous, releaseToPublish.Version, input.Remark, diff) if err != nil { return nil, err } - np, err := m.publishService.Get(ctx, newPublishId) + np, err := i.publishService.Get(ctx, newPublishId) if err != nil { return nil, err } return dto.FromModel(np, releaseToPublish.Remark), nil } -func (m *imlPublishModule) CheckPublish(ctx context.Context, serviceId string, releaseId string) (*dto.DiffOut, error) { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) CheckPublish(ctx context.Context, serviceId string, releaseId string) (*dto.DiffOut, error) { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return nil, err } - err = m.checkPublish(ctx, serviceId, releaseId) + err = i.checkPublish(ctx, serviceId, releaseId) if err != nil { return nil, err } - running, err := m.releaseService.GetRunning(ctx, serviceId) + running, err := i.releaseService.GetRunning(ctx, serviceId) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err } @@ -367,30 +421,30 @@ func (m *imlPublishModule) CheckPublish(ctx context.Context, serviceId string, r } if releaseId == "" { // 发布latest 版本 - diff, _, err := m.projectDiffModule.DiffForLatest(ctx, serviceId, runningReleaseId) + diff, _, err := i.projectDiffModule.DiffForLatest(ctx, serviceId, runningReleaseId) if err != nil { return nil, err } - return m.projectDiffModule.Out(ctx, diff) + return i.projectDiffModule.Out(ctx, diff) } else { // 发布 releaseId 版本, 返回 与当前版本的差异 - diff, err := m.projectDiffModule.Diff(ctx, serviceId, runningReleaseId, releaseId) + diff, err := i.projectDiffModule.Diff(ctx, serviceId, runningReleaseId, releaseId) if err != nil { return nil, err } - return m.projectDiffModule.Out(ctx, diff) + return i.projectDiffModule.Out(ctx, diff) } } -func (m *imlPublishModule) checkPublish(ctx context.Context, serviceId string, releaseId string) error { - flows, err := m.publishService.ListForStatus(ctx, serviceId, publish.StatusApply, publish.StatusAccept) +func (i *imlPublishModule) checkPublish(ctx context.Context, serviceId string, releaseId string) error { + flows, err := i.publishService.ListForStatus(ctx, serviceId, publish.StatusApply, publish.StatusAccept) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return err } if len(flows) > 0 { return errors.New("正在发布中") } - running, err := m.releaseService.GetRunning(ctx, serviceId) + running, err := i.releaseService.GetRunning(ctx, serviceId) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return err } @@ -403,8 +457,8 @@ func (m *imlPublishModule) checkPublish(ctx context.Context, serviceId string, r } return nil } -func (m *imlPublishModule) Close(ctx context.Context, serviceId, id string) error { - err := m.publishService.SetStatus(ctx, serviceId, id, publish.StatusClose) +func (i *imlPublishModule) Close(ctx context.Context, serviceId, id string) error { + err := i.publishService.SetStatus(ctx, serviceId, id, publish.StatusClose) if err != nil { return err } @@ -412,12 +466,12 @@ func (m *imlPublishModule) Close(ctx context.Context, serviceId, id string) erro return nil } -func (m *imlPublishModule) Stop(ctx context.Context, serviceId string, id string) error { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Stop(ctx context.Context, serviceId string, id string) error { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return err } - flow, err := m.publishService.Get(ctx, id) + flow, err := i.publishService.Get(ctx, id) if err != nil { return err } @@ -432,44 +486,44 @@ func (m *imlPublishModule) Stop(ctx context.Context, serviceId string, id string if flow.Status == publish.StatusApply { status = publish.StatusClose } - return m.publishService.SetStatus(ctx, serviceId, id, status) + return i.publishService.SetStatus(ctx, serviceId, id, status) } -func (m *imlPublishModule) Refuse(ctx context.Context, serviceId string, id string, commits string) error { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Refuse(ctx context.Context, serviceId string, id string, commits string) error { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return err } - return m.publishService.Refuse(ctx, serviceId, id, commits) + return i.publishService.Refuse(ctx, serviceId, id, commits) } -func (m *imlPublishModule) Accept(ctx context.Context, serviceId string, id string, commits string) error { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Accept(ctx context.Context, serviceId string, id string, commits string) error { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return err } - return m.publishService.Accept(ctx, serviceId, id, commits) + return i.publishService.Accept(ctx, serviceId, id, commits) } -func (m *imlPublishModule) publish(ctx context.Context, id string, clusterId string, projectRelease *gateway.ProjectRelease) error { +func (i *imlPublishModule) publish(ctx context.Context, id string, clusterId string, projectRelease *gateway.ProjectRelease) error { publishStatus := &publish.Status{ Publish: id, Status: publish.StatusPublishing, UpdateAt: time.Now(), } - err := m.publishService.SetPublishStatus(ctx, publishStatus) + err := i.publishService.SetPublishStatus(ctx, publishStatus) if err != nil { return fmt.Errorf("set publishing publishStatus error: %v", err) } defer func() { - err := m.publishService.SetPublishStatus(ctx, publishStatus) + err := i.publishService.SetPublishStatus(ctx, publishStatus) if err != nil { log.Errorf("set publishing publishStatus error: %v", err) } }() - client, err := m.clusterService.GatewayClient(ctx, clusterId) + client, err := i.clusterService.GatewayClient(ctx, clusterId) if err != nil { publishStatus.Status = publish.StatusPublishError publishStatus.Error = err.Error() @@ -501,12 +555,12 @@ func (m *imlPublishModule) publish(ctx context.Context, id string, clusterId str return nil } -func (m *imlPublishModule) Publish(ctx context.Context, serviceId string, id string) error { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Publish(ctx context.Context, serviceId string, id string) error { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return err } - flow, err := m.publishService.Get(ctx, id) + flow, err := i.publishService.Get(ctx, id) if err != nil { return err } @@ -516,7 +570,7 @@ func (m *imlPublishModule) Publish(ctx context.Context, serviceId string, id str if flow.Status != publish.StatusAccept && flow.Status != publish.StatusDone { return errors.New("只有通过状态才能发布") } - clusters, err := m.clusterService.List(ctx) + clusters, err := i.clusterService.List(ctx) if err != nil { return err } @@ -524,21 +578,21 @@ func (m *imlPublishModule) Publish(ctx context.Context, serviceId string, id str return i.Uuid }) - projectReleaseMap, err := m.getReleaseInfo(ctx, serviceId, flow.Release, flow.Release, clusterIds) + projectReleaseMap, err := i.getReleaseInfo(ctx, serviceId, flow.Release, flow.Release, clusterIds) if err != nil { return err } hasError := false - return m.transaction.Transaction(ctx, func(ctx context.Context) error { + return i.transaction.Transaction(ctx, func(ctx context.Context) error { for _, c := range clusters { - err = m.publish(ctx, flow.Id, c.Uuid, projectReleaseMap[c.Uuid]) + err = i.publish(ctx, flow.Id, c.Uuid, projectReleaseMap[c.Uuid]) if err != nil { hasError = true log.Error(err) continue } } - err = m.releaseService.SetRunning(ctx, serviceId, flow.Release) + err = i.releaseService.SetRunning(ctx, serviceId, flow.Release) if err != nil { return err } @@ -547,29 +601,37 @@ func (m *imlPublishModule) Publish(ctx context.Context, serviceId string, id str status = publish.StatusPublishError } if status == publish.StatusDone { - info, err := m.serviceService.Get(ctx, serviceId) + info, err := i.serviceService.Get(ctx, serviceId) if err != nil { return err } if info.EnableMCP { - err = m.updateMCPServer(ctx, serviceId, info.Name, flow.Version) + err = i.updateMCPServer(ctx, serviceId, info.Name, flow.Version) if err != nil { return err } } + apidocCommit, err := i.apiDocService.LatestDocCommit(ctx, serviceId) + if err != nil { + return err + } + isReleased := true + i.serviceOverviewService.Update(ctx, serviceId, &service_overview.Update{ + ReleaseApiCount: &apidocCommit.Data.APICount, + IsReleased: &isReleased, + }) } - - return m.publishService.SetStatus(ctx, serviceId, id, status) + return i.publishService.SetStatus(ctx, serviceId, id, status) }) } -func (m *imlPublishModule) List(ctx context.Context, serviceId string, page, pageSize int) ([]*dto.Publish, int64, error) { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) List(ctx context.Context, serviceId string, page, pageSize int) ([]*dto.Publish, int64, error) { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return nil, 0, err } - list, total, err := m.publishService.ListProjectPage(ctx, serviceId, page, pageSize) + list, total, err := i.publishService.ListProjectPage(ctx, serviceId, page, pageSize) if err != nil { return nil, 0, err } @@ -659,31 +721,31 @@ func (i *imlPublishModule) updateMCPServer(ctx context.Context, sid string, name return nil } -func (m *imlPublishModule) Detail(ctx context.Context, serviceId string, id string) (*dto.PublishDetail, error) { - _, err := m.serviceService.Check(ctx, serviceId, asServer) +func (i *imlPublishModule) Detail(ctx context.Context, serviceId string, id string) (*dto.PublishDetail, error) { + _, err := i.serviceService.Check(ctx, serviceId, asServer) if err != nil { return nil, err } - flow, err := m.publishService.Get(ctx, id) + flow, err := i.publishService.Get(ctx, id) if err != nil { return nil, err } if flow.Service != serviceId { return nil, errors.New("项目不一致") } - diff, err := m.publishService.GetDiff(ctx, id) + diff, err := i.publishService.GetDiff(ctx, id) if err != nil { return nil, err } - out, err := m.projectDiffModule.Out(ctx, diff) + out, err := i.projectDiffModule.Out(ctx, diff) if err != nil { return nil, err } - publishStatuses, err := m.PublishStatuses(ctx, serviceId, id) + publishStatuses, err := i.PublishStatuses(ctx, serviceId, id) if err != nil { return nil, err } - releaseInfo, err := m.releaseService.GetRelease(ctx, flow.Release) + releaseInfo, err := i.releaseService.GetRelease(ctx, flow.Release) if err != nil { return nil, err } diff --git a/module/release/iml.go b/module/release/iml.go index 296c5fa5..053304e6 100644 --- a/module/release/iml.go +++ b/module/release/iml.go @@ -65,7 +65,6 @@ func (m *imlReleaseModule) latestStrategyCommits(ctx context.Context, serviceId } func (m *imlReleaseModule) Create(ctx context.Context, serviceId string, input *dto.CreateInput) (string, error) { - proInfo, err := m.projectService.Check(ctx, serviceId, projectRuleMustServer) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { diff --git a/module/service/iml.go b/module/service/iml.go index 4e783150..5b2cc430 100644 --- a/module/service/iml.go +++ b/module/service/iml.go @@ -10,6 +10,8 @@ import ( "strings" "time" + service_overview "github.com/APIParkLab/APIPark/service/service-overview" + "github.com/APIParkLab/APIPark/common" "github.com/mitchellh/mapstructure" @@ -83,11 +85,12 @@ type imlServiceModule struct { tagService tag.ITagService `autowired:""` localModelService ai_local.ILocalModelService `autowired:""` - serviceTagService service_tag.ITagService `autowired:""` - apiService api.IAPIService `autowired:""` - apiDocService api_doc.IAPIDocService `autowired:""` - clusterService cluster.IClusterService `autowired:""` - subscribeServer subscribe.ISubscribeService `autowired:""` + serviceOverviewService service_overview.IOverviewService `autowired:""` + serviceTagService service_tag.ITagService `autowired:""` + apiService api.IAPIService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + clusterService cluster.IClusterService `autowired:""` + subscribeServer subscribe.ISubscribeService `autowired:""` releaseService release.IReleaseService `autowired:""` serviceModelMappingService service_model_mapping.IServiceModelMappingService `autowired:""` @@ -304,6 +307,7 @@ func (i *imlServiceModule) OnInit() { log.Error(err) return } + for _, s := range services { err = i.updateMCPServer(ctx, s.Id, s.Name, "1.0") if err != nil { @@ -311,6 +315,28 @@ func (i *imlServiceModule) OnInit() { return } } + overviews, err := i.serviceOverviewService.List(ctx) + if err != nil { + log.Error(err) + return + } + if len(overviews) > 0 { + return + } + countMap, err := i.apiDocService.APICountByServices(ctx) + if err != nil { + log.Error(err) + return + } + for k, v := range countMap { + err = i.serviceOverviewService.Update(ctx, k, &service_overview.Update{ + ApiCount: &v, + }) + if err != nil { + log.Error(err) + return + } + } }) } @@ -510,7 +536,14 @@ func (i *imlServiceModule) SearchMyServices(ctx context.Context, teamId string, serviceIds := utils.SliceToSlice(services, func(p *service.Service) string { return p.Id }) - apiCountMap, err := i.apiDocService.APICountByServices(ctx, serviceIds...) + //apiCountMap, err := i.apiDocService.APICountByServices(ctx, serviceIds...) + //if err != nil { + // return nil, err + //} + //serviceIds := utils.SliceToSlice(services, func(s *service.Service) string { + // return s.Id + //}) + overviewMap, err := i.serviceOverviewService.Map(ctx, serviceIds...) if err != nil { return nil, err } @@ -520,10 +553,12 @@ func (i *imlServiceModule) SearchMyServices(ctx context.Context, teamId string, if teamId != "" && model.Team != teamId { continue } - apiCount := apiCountMap[model.Id] item := toServiceItem(model) - item.ApiNum = apiCount - item.CanDelete = apiCount == 0 + if ov, ok := overviewMap[model.Id]; ok { + item.ApiNum = ov.ApiCount + item.CanDelete = ov.ApiCount == 0 + } + items = append(items, item) } @@ -629,22 +664,21 @@ func (i *imlServiceModule) Search(ctx context.Context, teamID string, keyword st if err != nil { return nil, err } - serviceIds := utils.SliceToSlice(list, func(s *service.Service) string { return s.Id }) - - apiCountMap, err := i.apiDocService.APICountByServices(ctx, serviceIds...) + overviewMap, err := i.serviceOverviewService.Map(ctx, serviceIds...) if err != nil { return nil, err } - items := make([]*service_dto.ServiceItem, 0, len(list)) for _, model := range list { - apiCount := apiCountMap[model.Id] item := toServiceItem(model) - item.ApiNum = apiCount - item.CanDelete = apiCount == 0 + if v, ok := overviewMap[model.Id]; ok { + item.ApiNum = v.ApiCount + item.CanDelete = v.ApiCount == 0 + } + items = append(items, item) } return items, nil diff --git a/service/api-doc/iml.go b/service/api-doc/iml.go index b385b90c..734f7768 100644 --- a/service/api-doc/iml.go +++ b/service/api-doc/iml.go @@ -5,6 +5,8 @@ import ( "errors" "time" + "github.com/eolinker/eosc/log" + "github.com/APIParkLab/APIPark/service/universally/commit" "github.com/APIParkLab/APIPark/stores/api" "github.com/eolinker/go-common/utils" @@ -59,7 +61,9 @@ func (i *imlAPIDocService) APICountByServices(ctx context.Context, serviceIds .. if len(serviceIds) > 0 { w["service"] = serviceIds } + now := time.Now() list, err := i.store.List(ctx, w) + log.Infof("search api doc count by services, serviceIds: %v, cost: %v", serviceIds, time.Since(now)) if err != nil { return nil, err } @@ -68,35 +72,35 @@ func (i *imlAPIDocService) APICountByServices(ctx context.Context, serviceIds .. }), nil } -func (i *imlAPIDocService) UpdateDoc(ctx context.Context, serviceId string, input *UpdateDoc) error { +func (i *imlAPIDocService) UpdateDoc(ctx context.Context, serviceId string, input *UpdateDoc) (int64, error) { doc, err := NewDocLoader(input.Content) if err != nil { - return err + return 0, err } if err := doc.Valid(); err != nil { - return err + return 0, err } if input.Prefix != "" { err = doc.AddPrefixInAll(input.Prefix) if err != nil { - return err + return 0, err } } data, err := doc.Marshal() if err != nil { - return err + return 0, err } input.Content = string(data) - + operator := utils.UserId(ctx) info, err := i.store.First(ctx, map[string]interface{}{ "service": serviceId, }) - operator := utils.UserId(ctx) + if err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { - return err + return 0, err } - return i.store.Insert(ctx, &api.Doc{ + return doc.APICount(), i.store.Insert(ctx, &api.Doc{ UUID: input.ID, Service: serviceId, Content: input.Content, @@ -109,7 +113,7 @@ func (i *imlAPIDocService) UpdateDoc(ctx context.Context, serviceId string, inpu info.Updater = operator info.UpdateAt = time.Now() info.APICount = doc.APICount() - return i.store.Save(ctx, info) + return doc.APICount(), i.store.Save(ctx, info) } func (i *imlAPIDocService) GetDoc(ctx context.Context, serviceId string) (*Doc, error) { diff --git a/service/api-doc/service.go b/service/api-doc/service.go index abb8d4fb..5c2c25e3 100644 --- a/service/api-doc/service.go +++ b/service/api-doc/service.go @@ -15,7 +15,7 @@ import ( type IAPIDocService interface { // UpdateDoc 更新文档 - UpdateDoc(ctx context.Context, serviceId string, input *UpdateDoc) error + UpdateDoc(ctx context.Context, serviceId string, input *UpdateDoc) (int64, error) // GetDoc 获取文档 GetDoc(ctx context.Context, serviceId string) (*Doc, error) diff --git a/service/release/iml.go b/service/release/iml.go index da0a32ee..c1b64bf0 100644 --- a/service/release/iml.go +++ b/service/release/iml.go @@ -28,6 +28,43 @@ type imlReleaseService struct { releaseRuntime release.IReleaseRuntime `autowired:""` } +func (s *imlReleaseService) UpdateRelease(ctx context.Context, id string, update *Update) error { + info, err := s.releaseStore.GetByUUID(ctx, id) + if err != nil { + return err + } + if update.Version != nil { + info.Name = *update.Version + } + if update.Remark != nil { + info.Remark = *update.Remark + } + + _, err = s.releaseStore.Update(ctx, info) + return err +} + +func (s *imlReleaseService) GetRunningList(ctx context.Context, serviceId ...string) ([]*Release, error) { + w := make(map[string]interface{}) + if len(serviceId) > 0 { + w["service"] = serviceId + } + list, err := s.releaseRuntime.List(ctx, w) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, nil + } + commitIds := utils.SliceToSlice(list, func(o *release.Runtime) string { + return o.Release + }) + commits, err := s.releaseStore.List(ctx, map[string]interface{}{ + "uuid": commitIds, + }) + return utils.SliceToSlice(commits, FromEntity), err +} + func (s *imlReleaseService) GetRunningApiDocCommits(ctx context.Context, serviceIds ...string) ([]string, error) { w := make(map[string]interface{}) if len(serviceIds) > 0 { diff --git a/service/release/model.go b/service/release/model.go index 2d93af74..226b8b86 100644 --- a/service/release/model.go +++ b/service/release/model.go @@ -26,6 +26,12 @@ func FromEntity(e *release.Release) *Release { } } +type Update struct { + Version *string + Remark *string + APICount *int64 // API数量 +} + type APICommit struct { Release string API string diff --git a/service/release/service.go b/service/release/service.go index 79aea897..7f224b6f 100644 --- a/service/release/service.go +++ b/service/release/service.go @@ -15,12 +15,15 @@ type IReleaseService interface { GetRelease(ctx context.Context, id string) (*Release, error) // CreateRelease 创建发布 CreateRelease(ctx context.Context, service, version, remark string, apiRequestCommit, apisProxyCommits map[string]string, apiDocCommits, serviceDocCommits string, upstreams map[string]map[string]string, strategies map[string]string) (*Release, error) + UpdateRelease(ctx context.Context, id string, update *Update) error // DeleteRelease 删除发布 DeleteRelease(ctx context.Context, id string) error + + GetRunningApiDocCommits(ctx context.Context, serviceIds ...string) ([]string, error) List(ctx context.Context, service string) ([]*Release, error) GetReleaseInfos(ctx context.Context, id string) ([]*APICommit, []*APICommit, *APICommit, []*UpstreamCommit, *ServiceCommit, error) GetCommits(ctx context.Context, id string) ([]*ProjectCommits, error) - GetRunningApiDocCommits(ctx context.Context, serviceIds ...string) ([]string, error) + //GetRunningApiDocCommits(ctx context.Context, serviceIds ...string) ([]string, error) GetRunningApiProxyCommit(ctx context.Context, service string, apiUUID string) (string, error) Completeness(partitions []string, apis []string, requestCommits []*commit.Commit[api.Request], proxyCommits []*commit.Commit[api.Proxy], upstreamCommits []*commit.Commit[upstream.Config]) bool @@ -30,6 +33,7 @@ type IReleaseService interface { // service: the service name // Return type(s): *Release, error GetRunning(ctx context.Context, service string) (*Release, error) + GetRunningList(ctx context.Context, serviceId ...string) ([]*Release, error) SetRunning(ctx context.Context, service string, id string) error CheckNewVersion(ctx context.Context, service string, version string) (bool, error) diff --git a/service/service-overview/iml.go b/service/service-overview/iml.go new file mode 100644 index 00000000..4283f41b --- /dev/null +++ b/service/service-overview/iml.go @@ -0,0 +1,81 @@ +package service_overview + +import ( + "context" + "errors" + + "gorm.io/gorm" + + "github.com/eolinker/go-common/utils" + + "github.com/APIParkLab/APIPark/stores/service" +) + +var _ IOverviewService = (*imlOverviewService)(nil) + +type imlOverviewService struct { + store service.IOverviewStore `autowired:""` +} + +func genUpdateFields(info *service.Overview, update *Update) { + if update.ApiCount != nil { + info.ApiCount = *update.ApiCount + } + if update.ReleaseApiCount != nil { + info.ReleaseApiCount = *update.ReleaseApiCount + } + if update.IsReleased != nil { + info.IsReleased = *update.IsReleased + } + return +} + +func (i imlOverviewService) Update(ctx context.Context, serviceId string, update *Update) error { + if update == nil { + return nil + } + + info, err := i.store.First(ctx, map[string]interface{}{ + "service": serviceId, + }) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + info = &service.Overview{ + Service: serviceId, + } + genUpdateFields(info, update) + return i.store.Insert(ctx) + } + genUpdateFields(info, update) + _, err = i.store.Update(ctx, info) + if err != nil { + return err + } + return nil +} + +func (i imlOverviewService) List(ctx context.Context, serviceIds ...string) ([]*Overview, error) { + w := make(map[string]interface{}) + if len(serviceIds) > 0 { + w = map[string]interface{}{ + "service": serviceIds, + } + } + list, err := i.store.List(ctx, w) + if err != nil { + return nil, err + } + return utils.SliceToSlice(list, FromEntity), nil +} + +func (i imlOverviewService) Map(ctx context.Context, serviceIds ...string) (map[string]*Overview, error) { + list, err := i.List(ctx, serviceIds...) + if err != nil { + return nil, err + } + return utils.SliceToMap(list, func(i *Overview) string { + return i.Service + }), nil +} diff --git a/service/service-overview/model.go b/service/service-overview/model.go new file mode 100644 index 00000000..8f11d043 --- /dev/null +++ b/service/service-overview/model.go @@ -0,0 +1,27 @@ +package service_overview + +import ( + "github.com/APIParkLab/APIPark/stores/service" +) + +type Overview struct { + Service string + ApiCount int64 + ReleaseApiCount int64 + IsReleased bool +} + +func FromEntity(e *service.Overview) *Overview { + return &Overview{ + Service: e.Service, + ApiCount: e.ApiCount, + ReleaseApiCount: e.ReleaseApiCount, + IsReleased: e.IsReleased, + } +} + +type Update struct { + ApiCount *int64 + ReleaseApiCount *int64 + IsReleased *bool +} diff --git a/service/service-overview/service.go b/service/service-overview/service.go new file mode 100644 index 00000000..eaaf898c --- /dev/null +++ b/service/service-overview/service.go @@ -0,0 +1,20 @@ +package service_overview + +import ( + "context" + "reflect" + + "github.com/eolinker/go-common/autowire" +) + +type IOverviewService interface { + Update(ctx context.Context, serviceId string, update *Update) error + List(ctx context.Context, serviceIds ...string) ([]*Overview, error) + Map(ctx context.Context, serviceIds ...string) (map[string]*Overview, error) +} + +func init() { + autowire.Auto[IOverviewService](func() reflect.Value { + return reflect.ValueOf(new(imlOverviewService)) + }) +} diff --git a/stores/service/model.go b/stores/service/model.go index 45297d91..fdf2c4d3 100644 --- a/stores/service/model.go +++ b/stores/service/model.go @@ -35,6 +35,22 @@ func (p *Service) TableName() string { return "service" } +type Overview struct { + Id int64 `gorm:"type:BIGINT(20);size:20;not null;auto_increment;primary_key;column:id;comment:主键ID;"` + Service string `gorm:"size:255;not null;column:service;comment:服务ID"` + ApiCount int64 `gorm:"type:BIGINT(20);not null;column:api_count;comment:接口数量"` + ReleaseApiCount int64 `gorm:"type:BIGINT(20);not null;column:release_api_count;comment:已发布接口数量"` + IsReleased bool `gorm:"type:tinyint(1);not null;column:is_released;comment:是否已发布"` +} + +func (o *Overview) IdValue() int64 { + return o.Id +} + +func (o *Overview) TableName() string { + return "service_overview" +} + type Authorization struct { Id int64 `gorm:"type:BIGINT(20);size:20;not null;auto_increment;primary_key;column:id;comment:主键ID;"` UUID string `gorm:"size:36;not null;column:uuid;uniqueIndex:uuid;comment:UUID;"` diff --git a/stores/service/store.go b/stores/service/store.go index 702a358c..c806fe55 100644 --- a/stores/service/store.go +++ b/stores/service/store.go @@ -13,6 +13,12 @@ type IServiceStore interface { type imlServiceStore struct { store.SearchStore[Service] } +type IOverviewStore interface { + store.IBaseStore[Overview] +} +type imlOverviewStore struct { + store.Store[Overview] +} type IServiceTagStore interface { store.IBaseStore[Tag] @@ -61,6 +67,9 @@ func init() { return reflect.ValueOf(new(imlServiceDocStore)) }) + autowire.Auto[IOverviewStore](func() reflect.Value { + return reflect.ValueOf(new(imlOverviewStore)) + }) autowire.Auto[IServiceModelMappingStore](func() reflect.Value { return reflect.ValueOf(new(imlServiceModelMappingStore)) })