robocanic commented on code in PR #1426:
URL: https://github.com/apache/dubbo-admin/pull/1426#discussion_r3070456703


##########
pkg/console/service/application.go:
##########
@@ -196,6 +196,143 @@ func getAppConsumeServiceInfo(ctx consolectx.Context, req 
*model.ApplicationServ
        return pageResult, nil
 }
 
+// GraphApplications returns the application-level graph for a given 
application.
+// It collects provider and consumer service relations and transforms them 
into nodes and edges.
+// The current implementation is a simplified version (provider/consumer link 
traversal).
+func GraphApplications(ctx consolectx.Context, req *model.ApplicationGraphReq) 
(*model.GraphData, error) {
+
+       // Step 1: query all services provided by this application in the 
namespace.
+       providerServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceProviderMetadataResource](
+               ctx.ResourceManager(),
+               meshresource.ServiceProviderMetadataKind,
+               map[string]string{
+                       index.ByMeshIndex:              req.Mesh,
+                       index.ByServiceProviderAppName: req.AppName,
+               },
+       )
+       if err != nil {
+               return nil, bizerror.MeshNotFoundError("")
+       }
+
+       // Step 2: query all services consumed by this application in the 
namespace.
+       consumerServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceConsumerMetadataResource](
+               ctx.ResourceManager(),
+               meshresource.ServiceConsumerMetadataKind,
+               map[string]string{
+                       index.ByMeshIndex:              req.Mesh,
+                       index.ByServiceConsumerAppName: req.AppName,
+               },
+       )
+       if err != nil {
+               return nil, bizerror.MeshNotFoundError("")
+       }
+
+       // Step 3: build the graph nodes and edges from provider and consumer 
relations.
+       // providerAppSet and consumerAppSet track already-added application 
nodes.
+       providerAppSet := make(map[string]struct{})
+       consumerAppSet := make(map[string]struct{})
+
+       nodes := make([]model.GraphNode, 0)
+       edges := make([]model.GraphEdge, 0)
+       // init self node
+       nodes = append(nodes, model.GraphNode{
+               ID:    req.AppName,
+               Label: req.AppName,
+               Type:  "application",
+               Rule:  "", // self node doesn't have a rule
+               Data:  nil,
+       })
+       // 3.a: iterate over provided services, collect service nodes and 
consumer app nodes.
+       for _, provider := range providerServiceList {
+               if provider.Spec == nil {
+                       continue
+               }
+
+               // For each provided service, find consuming applications and 
add them as nodes.
+               consumerAppServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceConsumerMetadataResource](
+                       ctx.ResourceManager(),
+                       meshresource.ServiceConsumerMetadataKind,
+                       map[string]string{
+                               index.ByMeshIndex:                 req.Mesh,
+                               index.ByServiceConsumerServiceKey: 
provider.Spec.ServiceName + ":" + provider.Spec.Version + ":" + 
provider.Spec.Group,
+                       },
+               )
+               if err != nil {
+                       logger.Errorf("failed to list consumer apps by provider 
service key, mesh: %s, serviceKey: %s, err: %s", req.Mesh, 
provider.Spec.ProviderAppName+":"+provider.Spec.Version+":"+provider.Spec.Group,
 err)
+                       continue
+               }
+
+               for _, item := range consumerAppServiceList {
+                       if item.Spec == nil {
+                               continue
+                       }
+                       if _, ok := consumerAppSet[item.Spec.ConsumerAppName]; 
!ok {
+                               consumerAppSet[item.Spec.ConsumerAppName] = 
struct{}{}
+                               nodes = append(nodes, model.GraphNode{
+                                       ID:    item.Spec.ConsumerAppName,
+                                       Label: item.Spec.ConsumerAppName,
+                                       Type:  "application",
+                                       Rule:  constants.ConsumerSide,
+                                       Data:  nil,
+                               })
+                               edges = append(edges, model.GraphEdge{
+                                       Source: item.Spec.ConsumerAppName,
+                                       Target: provider.Spec.ProviderAppName,
+                                       Data:   nil,
+                               })
+                       }
+               }
+       }
+
+       // 3.b: iterate over consumed services, collect service nodes and 
provider app nodes.
+       for _, consumer := range consumerServiceList {
+               if consumer.Spec == nil {
+                       continue
+               }
+
+               // For each consumed service, find providing applications and 
add them as nodes.
+               providerAppList, err := 
manager.ListByIndexes[*meshresource.ServiceProviderMetadataResource](
+                       ctx.ResourceManager(),
+                       meshresource.ServiceProviderMetadataKind,
+                       map[string]string{
+                               index.ByMeshIndex:                 req.Mesh,
+                               index.ByServiceProviderServiceKey: 
consumer.Spec.ServiceName + ":" + consumer.Spec.Version + ":" + 
consumer.Spec.Group,
+                       },
+               )
+               if err != nil {
+                       logger.Errorf("failed to list consumer apps by provider 
service key, mesh: %s, serviceKey: %s, err: %s", req.Mesh, 
consumer.Spec.ConsumerAppName+":"+consumer.Spec.Version+":"+consumer.Spec.Group,
 err)
+                       continue
+               }
+
+               for _, item := range providerAppList {
+                       if item.Spec == nil {
+                               continue
+                       }
+                       if _, ok := providerAppSet[item.Spec.ProviderAppName]; 
!ok {
+                               providerAppSet[item.Spec.ProviderAppName] = 
struct{}{}
+                               nodes = append(nodes, model.GraphNode{
+                                       ID:    item.Spec.ProviderAppName,
+                                       Label: item.Spec.ProviderAppName,
+                                       Type:  "application",
+                                       Rule:  constants.ProviderSide,
+                                       Data:  nil,
+                               })
+                               edges = append(edges, model.GraphEdge{
+                                       Source: consumer.Spec.ConsumerAppName,
+                                       Target: item.Spec.ProviderAppName,
+                                       Data:   nil,
+                               })
+                       }

Review Comment:
   预期内的,理由同上



##########
pkg/console/service/application.go:
##########
@@ -196,6 +196,143 @@ func getAppConsumeServiceInfo(ctx consolectx.Context, req 
*model.ApplicationServ
        return pageResult, nil
 }
 
+// GraphApplications returns the application-level graph for a given 
application.
+// It collects provider and consumer service relations and transforms them 
into nodes and edges.
+// The current implementation is a simplified version (provider/consumer link 
traversal).
+func GraphApplications(ctx consolectx.Context, req *model.ApplicationGraphReq) 
(*model.GraphData, error) {
+
+       // Step 1: query all services provided by this application in the 
namespace.
+       providerServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceProviderMetadataResource](
+               ctx.ResourceManager(),
+               meshresource.ServiceProviderMetadataKind,
+               map[string]string{
+                       index.ByMeshIndex:              req.Mesh,
+                       index.ByServiceProviderAppName: req.AppName,
+               },
+       )
+       if err != nil {
+               return nil, bizerror.MeshNotFoundError("")

Review Comment:
   Suggestion: 这里抛的error不应该是MeshNotFound,MeshNotFound应该只有在Mesh找不到的时候才抛这个error



##########
pkg/core/discovery/subscriber/service_provider_metadata.go:
##########
@@ -106,3 +166,195 @@ func (s *ServiceProviderMetadataEventSubscriber) 
processUpsert(r *meshresource.S
        s.emitter.Send(events.NewResourceChangedEvent(cache.Added, nil, appRes))
        return nil
 }
+
+func (s *ServiceProviderMetadataEventSubscriber) syncService(mesh, 
serviceName, version, group string) error {
+       serviceKey := meshresource.BuildServiceIdentityKey(serviceName, 
version, group)
+       resources, err := s.providerStore.ListByIndexes(map[string]string{
+               index.ByMeshIndex:                  mesh,
+               index.ByServiceProviderServiceName: serviceName,
+       })
+       if err != nil {
+               return err
+       }
+
+       providers := make([]*meshresource.ServiceProviderMetadataResource, 0, 
len(resources))
+       for _, item := range resources {
+               res, ok := item.(*meshresource.ServiceProviderMetadataResource)
+               if !ok {
+                       return 
bizerror.NewAssertionError(meshresource.ServiceProviderMetadataKind, 
reflect.TypeOf(item).Name())
+               }
+               if res.Spec == nil {
+                       continue
+               }
+               if res.Spec.Version == version && res.Spec.Group == group {
+                       providers = append(providers, res)
+               }
+       }

Review Comment:
   Copilot这里说得没错,可以直接用ByServiceProviderServiceKey这个索引



##########
pkg/console/handler/service.go:
##########
@@ -229,3 +229,61 @@ func ServiceConfigArgumentRoutePUT(ctx consolectx.Context) 
gin.HandlerFunc {
                c.JSON(http.StatusOK, model.NewSuccessResp(nil))
        }
 }
+
+// GetServiceGraph returns the service graph as graph data (nodes and edges) 
for visualization
+func GetServiceGraph(ctx consolectx.Context) gin.HandlerFunc {
+       return func(c *gin.Context) {
+               req := &model.ServiceGraphReq{}
+               if err := c.ShouldBindQuery(req); err != nil {
+                       c.JSON(http.StatusBadRequest, 
model.NewErrorResp(err.Error()))
+                       return
+               }
+
+               resp, err := service.GraphServices(ctx, req)
+               if err != nil {
+                       util.HandleServiceError(c, err)
+                       return
+               }
+
+               c.JSON(http.StatusOK, model.NewSuccessResp(resp))
+       }
+}
+
+// GetServiceDetail returns service detail information
+func GetServiceDetail(ctx consolectx.Context) gin.HandlerFunc {
+       return func(c *gin.Context) {
+               req := &model.ServiceDetailReq{}
+               if err := c.ShouldBindQuery(req); err != nil {
+                       c.JSON(http.StatusBadRequest, 
model.NewErrorResp(err.Error()))
+                       return
+               }
+
+               resp, err := service.GetServiceDetail(ctx, req)
+               if err != nil {
+                       util.HandleServiceError(c, err)
+                       return
+               }
+
+               c.JSON(http.StatusOK, model.NewSuccessResp(resp))
+       }
+}
+
+// GetServiceInterfaces returns service interfaces information
+func GetServiceInterfaces(ctx consolectx.Context) gin.HandlerFunc {

Review Comment:
   这个功能我记得zerui已经实现了,合并一下develop看看



##########
pkg/console/service/application.go:
##########
@@ -196,6 +196,143 @@ func getAppConsumeServiceInfo(ctx consolectx.Context, req 
*model.ApplicationServ
        return pageResult, nil
 }
 
+// GraphApplications returns the application-level graph for a given 
application.
+// It collects provider and consumer service relations and transforms them 
into nodes and edges.
+// The current implementation is a simplified version (provider/consumer link 
traversal).
+func GraphApplications(ctx consolectx.Context, req *model.ApplicationGraphReq) 
(*model.GraphData, error) {
+
+       // Step 1: query all services provided by this application in the 
namespace.
+       providerServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceProviderMetadataResource](
+               ctx.ResourceManager(),
+               meshresource.ServiceProviderMetadataKind,
+               map[string]string{
+                       index.ByMeshIndex:              req.Mesh,
+                       index.ByServiceProviderAppName: req.AppName,
+               },
+       )
+       if err != nil {
+               return nil, bizerror.MeshNotFoundError("")
+       }
+
+       // Step 2: query all services consumed by this application in the 
namespace.
+       consumerServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceConsumerMetadataResource](
+               ctx.ResourceManager(),
+               meshresource.ServiceConsumerMetadataKind,
+               map[string]string{
+                       index.ByMeshIndex:              req.Mesh,
+                       index.ByServiceConsumerAppName: req.AppName,
+               },
+       )
+       if err != nil {
+               return nil, bizerror.MeshNotFoundError("")
+       }
+
+       // Step 3: build the graph nodes and edges from provider and consumer 
relations.
+       // providerAppSet and consumerAppSet track already-added application 
nodes.
+       providerAppSet := make(map[string]struct{})
+       consumerAppSet := make(map[string]struct{})
+
+       nodes := make([]model.GraphNode, 0)
+       edges := make([]model.GraphEdge, 0)
+       // init self node
+       nodes = append(nodes, model.GraphNode{
+               ID:    req.AppName,
+               Label: req.AppName,
+               Type:  "application",
+               Rule:  "", // self node doesn't have a rule
+               Data:  nil,
+       })
+       // 3.a: iterate over provided services, collect service nodes and 
consumer app nodes.
+       for _, provider := range providerServiceList {
+               if provider.Spec == nil {
+                       continue
+               }
+
+               // For each provided service, find consuming applications and 
add them as nodes.
+               consumerAppServiceList, err := 
manager.ListByIndexes[*meshresource.ServiceConsumerMetadataResource](
+                       ctx.ResourceManager(),
+                       meshresource.ServiceConsumerMetadataKind,
+                       map[string]string{
+                               index.ByMeshIndex:                 req.Mesh,
+                               index.ByServiceConsumerServiceKey: 
provider.Spec.ServiceName + ":" + provider.Spec.Version + ":" + 
provider.Spec.Group,
+                       },
+               )
+               if err != nil {
+                       logger.Errorf("failed to list consumer apps by provider 
service key, mesh: %s, serviceKey: %s, err: %s", req.Mesh, 
provider.Spec.ProviderAppName+":"+provider.Spec.Version+":"+provider.Spec.Group,
 err)
+                       continue
+               }
+
+               for _, item := range consumerAppServiceList {
+                       if item.Spec == nil {
+                               continue
+                       }
+                       if _, ok := consumerAppSet[item.Spec.ConsumerAppName]; 
!ok {
+                               consumerAppSet[item.Spec.ConsumerAppName] = 
struct{}{}
+                               nodes = append(nodes, model.GraphNode{
+                                       ID:    item.Spec.ConsumerAppName,
+                                       Label: item.Spec.ConsumerAppName,
+                                       Type:  "application",
+                                       Rule:  constants.ConsumerSide,
+                                       Data:  nil,
+                               })
+                               edges = append(edges, model.GraphEdge{
+                                       Source: item.Spec.ConsumerAppName,
+                                       Target: provider.Spec.ProviderAppName,
+                                       Data:   nil,
+                               })
+                       }

Review Comment:
   预期内的。这里只需要记录应用级别的消费关系



##########
pkg/core/discovery/subscriber/service_provider_metadata.go:
##########
@@ -19,29 +19,37 @@ package subscriber
 
 import (
        "reflect"
+       "sort"
+       "strings"
 
-       "github.com/duke-git/lancet/v2/strutil"
-       "k8s.io/client-go/tools/cache"
-
+       meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"

Review Comment:
   这里的引包的排序需要规整一下,参考:
   
https://github.com/apache/dubbo-admin/wiki/%E6%96%B0%E7%89%88Dubbo-Admin%E5%BC%80%E5%8F%91%E8%80%85%E6%8C%87%E5%8D%97#goland-import%E9%85%8D%E7%BD%AE



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to