This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/refactor-with-go by this push:
     new 812bbff0 ADD: FilterFromCategory (#1013)
812bbff0 is described below

commit 812bbff057680d368bb09ffac249659e350db704
Author: wudong5 <[email protected]>
AuthorDate: Thu Mar 9 17:17:58 2023 +0800

    ADD: FilterFromCategory (#1013)
---
 conf/dubboadmin.yml                         |  21 +++
 pkg/admin/constant/const.go                 |   5 +
 pkg/admin/handlers/service.go               |  16 ++-
 pkg/admin/services/provider_service.go      |   4 +-
 pkg/admin/services/provider_service_impl.go | 209 +++++++++++++++++++++++-----
 pkg/admin/services/registry_service_sync.go |   4 +-
 pkg/admin/util/sync_utils.go                | 103 ++++++++++++++
 7 files changed, 322 insertions(+), 40 deletions(-)

diff --git a/conf/dubboadmin.yml b/conf/dubboadmin.yml
new file mode 100644
index 00000000..b8d0fdd7
--- /dev/null
+++ b/conf/dubboadmin.yml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+admin:
+  registry:
+    address: zookeeper://127.0.0.1:2181
+  config-center: zookeeper://127.0.0.1:2181
+  metadata-report:
+    address: zookeeper://127.0.0.1:2181
\ No newline at end of file
diff --git a/pkg/admin/constant/const.go b/pkg/admin/constant/const.go
index 064045ed..5cd0e446 100644
--- a/pkg/admin/constant/const.go
+++ b/pkg/admin/constant/const.go
@@ -52,4 +52,9 @@ const (
        DefaultWeight         = 100
        OwnerKey              = "owner"
        Service               = "service"
+       Colon                 = ":"
+       InterrogationPoint    = "?"
+       IP                    = "ip"
+       PlusSigns             = "+"
+       PunctuationPoint      = "."
 )
diff --git a/pkg/admin/handlers/service.go b/pkg/admin/handlers/service.go
index d34bb73d..48a9482e 100644
--- a/pkg/admin/handlers/service.go
+++ b/pkg/admin/handlers/service.go
@@ -27,7 +27,13 @@ import (
 var providerService services.ProviderService = &services.ProviderServiceImpl{}
 
 func AllServices(c *gin.Context) {
-       services := providerService.FindServices()
+       services, err := providerService.FindServices()
+       if err != nil {
+               c.JSON(http.StatusInternalServerError, gin.H{
+                       "error": err.Error(),
+               })
+               return
+       }
        c.JSON(http.StatusOK, gin.H{
                "code": 1,
                "data": services,
@@ -37,7 +43,13 @@ func AllServices(c *gin.Context) {
 func SearchService(c *gin.Context) {
        pattern := c.Query("pattern")
        filter := c.Query("filter")
-       providers := providerService.FindService(pattern, filter)
+       providers, err := providerService.FindService(pattern, filter)
+       if err != nil {
+               c.JSON(http.StatusInternalServerError, gin.H{
+                       "error": err.Error(),
+               })
+               return
+       }
        c.JSON(http.StatusOK, gin.H{
                "code": 1,
                "data": providers,
diff --git a/pkg/admin/services/provider_service.go 
b/pkg/admin/services/provider_service.go
index c7a7fea7..f87a75b7 100644
--- a/pkg/admin/services/provider_service.go
+++ b/pkg/admin/services/provider_service.go
@@ -18,6 +18,6 @@ package services
 import "github.com/apache/dubbo-admin/pkg/admin/model"
 
 type ProviderService interface {
-       FindServices() []string
-       FindService(string, string) []*model.Provider
+       FindServices() ([]string, error)
+       FindService(string, string) ([]*model.Provider, error)
 }
diff --git a/pkg/admin/services/provider_service_impl.go 
b/pkg/admin/services/provider_service_impl.go
index ed2bedde..6a16f2e1 100644
--- a/pkg/admin/services/provider_service_impl.go
+++ b/pkg/admin/services/provider_service_impl.go
@@ -16,10 +16,12 @@
 package services
 
 import (
+       "fmt"
+       "regexp"
+       "strings"
        "sync"
 
        "dubbo.apache.org/dubbo-go/v3/common"
-       "dubbo.apache.org/dubbo-go/v3/common/logger"
        "github.com/apache/dubbo-admin/pkg/admin/cache"
        "github.com/apache/dubbo-admin/pkg/admin/constant"
        "github.com/apache/dubbo-admin/pkg/admin/model"
@@ -28,56 +30,195 @@ import (
 
 type ProviderServiceImpl struct{}
 
-func (p *ProviderServiceImpl) FindServices() []string {
-       servicesMap, ok := 
cache.InterfaceRegistryCache.Load(constant.ProvidersCategory)
+func (p *ProviderServiceImpl) FindServices() ([]string, error) {
        var services []string
+       servicesAny, ok := 
cache.InterfaceRegistryCache.Load(constant.ProvidersCategory)
        if !ok {
-               return services
+               return nil, nil
        }
-       servicesMap.(*sync.Map).Range(func(key, v interface{}) bool {
+       servicesMap, ok := servicesAny.(*sync.Map)
+       if !ok {
+               return nil, fmt.Errorf("servicesMap type not *sync.Map")
+       }
+
+       servicesMap.Range(func(key, value any) bool {
                services = append(services, key.(string))
                return true
        })
-       return services
+       return services, nil
 }
 
-func (p *ProviderServiceImpl) findByService(serviceName string) 
[]*model.Provider {
-       var providers []*model.Provider
-       addProvider := func(serviceMap any) {
-               for id, url := range serviceMap.(map[string]*common.URL) {
-                       provider := util.URL2Provider(id, url)
-                       if provider != nil {
-                               providers = append(providers, provider)
+func (p *ProviderServiceImpl) findApplications() ([]string, error) {
+       var (
+               applications []string
+               err          error
+       )
+       servicesAny, ok := 
cache.InterfaceRegistryCache.Load(constant.ProvidersCategory)
+       if !ok {
+               return nil, nil
+       }
+       servicesMap, ok := servicesAny.(*sync.Map)
+       if !ok {
+               return nil, fmt.Errorf("servicesMap type not *sync.Map")
+       }
+
+       servicesMap.Range(func(key, value any) bool {
+               service, ok := value.(map[string]*common.URL)
+               if !ok {
+                       err = fmt.Errorf("service type not 
map[string]*common.URL")
+                       return false
+               }
+               for _, url := range service {
+                       app := url.GetParam(constant.ApplicationKey, "")
+                       if app != "" {
+                               applications = append(applications, app)
                        }
                }
-       }
-       services, ok := 
cache.InterfaceRegistryCache.Load(constant.ProvidersCategory)
+               return true
+       })
+       return applications, err
+}
+
+func (p *ProviderServiceImpl) findAddresses() ([]string, error) {
+       var (
+               addresses []string
+               err       error
+       )
+       servicesAny, ok := 
cache.InterfaceRegistryCache.Load(constant.ProvidersCategory)
        if !ok {
-               return providers
+               return nil, nil
        }
-       servicesMap, ok := services.(*sync.Map)
+       servicesMap, ok := servicesAny.(*sync.Map)
        if !ok {
-               // servicesMap type error
-               logger.Error("servicesMap type not *sync.Map")
-               return providers
+               return nil, fmt.Errorf("servicesMap type not *sync.Map")
+       }
+
+       servicesMap.Range(func(key, value any) bool {
+               service, ok := value.(map[string]*common.URL)
+               if !ok {
+                       err = fmt.Errorf("service type not 
map[string]*common.URL")
+                       return false
+               }
+               for _, url := range service {
+                       loc := url.Location
+                       if loc != "" {
+                               addresses = append(addresses, loc)
+                       }
+               }
+               return true
+       })
+       return addresses, err
+}
+
+func (p *ProviderServiceImpl) findByService(providerService string) 
([]*model.Provider, error) {
+       filter := make(map[string]string)
+       filter[constant.CategoryKey] = constant.ProvidersCategory
+       filter[util.ServiceFilterKey] = providerService
+       servicesMap, err := util.FilterFromCategory(filter)
+       if err != nil {
+               return nil, err
        }
-       if serviceName == constant.AnyValue {
-               servicesMap.Range(func(key, value any) bool {
-                       addProvider(value)
-                       return true
-               })
+       return util.URL2ProviderList(servicesMap), nil
+}
+
+func (p *ProviderServiceImpl) findByAddress(providerAddress string) 
([]*model.Provider, error) {
+       filter := make(map[string]string)
+       filter[constant.CategoryKey] = constant.ProvidersCategory
+       filter[util.AddressFilterKey] = providerAddress
+       servicesMap, err := util.FilterFromCategory(filter)
+       if err != nil {
+               return nil, err
        }
-       serviceMap, ok := servicesMap.Load(serviceName)
-       if !ok {
-               return providers
+       return util.URL2ProviderList(servicesMap), nil
+}
+
+func (p *ProviderServiceImpl) findByApplication(providerApplication string) 
([]*model.Provider, error) {
+       filter := make(map[string]string)
+       filter[constant.CategoryKey] = constant.ProvidersCategory
+       filter[constant.ApplicationKey] = providerApplication
+       servicesMap, err := util.FilterFromCategory(filter)
+       if err != nil {
+               return nil, err
        }
-       addProvider(serviceMap)
-       return providers
+       return util.URL2ProviderList(servicesMap), nil
 }
 
-func (p *ProviderServiceImpl) FindService(pattern string, filter string) 
[]*model.Provider {
-       if pattern == constant.Service {
-               return p.findByService(filter)
+func (p *ProviderServiceImpl) FindService(pattern string, filter string) 
([]*model.Provider, error) {
+       var (
+               providers []*model.Provider
+               reg       *regexp.Regexp
+               err       error
+       )
+       if !strings.Contains(filter, constant.AnyValue) && 
!strings.Contains(filter, constant.InterrogationPoint) {
+               if pattern == constant.IP {
+                       providers, err = p.findByAddress(filter)
+                       if err != nil {
+                               return nil, err
+                       }
+               } else if pattern == constant.Service {
+                       providers, err = p.findByService(filter)
+                       if err != nil {
+                               return nil, err
+                       }
+               } else if pattern == constant.ApplicationKey {
+                       providers, err = p.findByApplication(filter)
+                       if err != nil {
+                               return nil, err
+                       }
+               } else {
+                       return nil, fmt.Errorf("unsupport the pattern: %s", 
pattern)
+               }
+       } else {
+               var candidates []string
+               if pattern == constant.IP {
+                       candidates, err = p.findAddresses()
+                       if err != nil {
+                               return nil, err
+                       }
+               } else if pattern == constant.Service {
+                       candidates, err = p.FindServices()
+                       if err != nil {
+                               return nil, err
+                       }
+               } else if pattern == constant.ApplicationKey {
+                       candidates, err = p.findApplications()
+                       if err != nil {
+                               return nil, err
+                       }
+               } else {
+                       return nil, fmt.Errorf("unsupport the pattern: %s", 
pattern)
+               }
+
+               filter = strings.ToLower(filter)
+               if strings.HasPrefix(filter, constant.AnyValue) || 
strings.HasPrefix(filter, constant.InterrogationPoint) ||
+                       strings.HasPrefix(filter, constant.PlusSigns) {
+                       filter = constant.PunctuationPoint + filter
+               }
+               reg, err = regexp.Compile(filter)
+               if err != nil {
+                       return nil, err
+               }
+               for _, candidate := range candidates {
+                       if reg.MatchString(candidate) {
+                               if pattern == constant.IP {
+                                       providers, err = 
p.findByAddress(candidate)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                               } else if pattern == constant.Service {
+                                       providers, err = 
p.findByService(candidate)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                               } else if pattern == constant.ApplicationKey {
+                                       providers, err = 
p.findByApplication(candidate)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                               }
+                       }
+               }
        }
-       return nil
+
+       return providers, nil
 }
diff --git a/pkg/admin/services/registry_service_sync.go 
b/pkg/admin/services/registry_service_sync.go
index fb481160..2c1148b7 100644
--- a/pkg/admin/services/registry_service_sync.go
+++ b/pkg/admin/services/registry_service_sync.go
@@ -108,8 +108,8 @@ func (adminNotifyListener) Notify(event 
*registry.ServiceEvent) {
        } else {
                interfaceName = serviceURL.Service()
                var services map[string]map[string]*common.URL
-               if _, ok := categories[category]; ok {
-                       // services = s
+               if s, ok := categories[category]; ok {
+                       services = s
                } else {
                        services = make(map[string]map[string]*common.URL)
                        categories[category] = services
diff --git a/pkg/admin/util/sync_utils.go b/pkg/admin/util/sync_utils.go
index 95de8e2b..0ebbd41f 100644
--- a/pkg/admin/util/sync_utils.go
+++ b/pkg/admin/util/sync_utils.go
@@ -16,11 +16,22 @@
 package util
 
 import (
+       "fmt"
+       "strings"
+       "sync"
+
        "dubbo.apache.org/dubbo-go/v3/common"
+       "github.com/apache/dubbo-admin/pkg/admin/cache"
        "github.com/apache/dubbo-admin/pkg/admin/constant"
        "github.com/apache/dubbo-admin/pkg/admin/model"
 )
 
+const (
+       ServiceFilterKey = ".service"
+       AddressFilterKey = ".address"
+       IDFilterKey      = ".id"
+)
+
 func URL2Provider(id string, url *common.URL) *model.Provider {
        if url == nil {
                return nil
@@ -42,3 +53,95 @@ func URL2Provider(id string, url *common.URL) 
*model.Provider {
                RegistrySource: model.Interface,
        }
 }
+
+func URL2ProviderList(servicesMap map[string]*common.URL) []*model.Provider {
+       var providers []*model.Provider
+       if servicesMap == nil {
+               return providers
+       }
+       for id, url := range servicesMap {
+               provider := URL2Provider(id, url)
+               if provider != nil {
+                       providers = append(providers, provider)
+               }
+       }
+       return providers
+}
+
+func FilterFromCategory(filter map[string]string) (map[string]*common.URL, 
error) {
+       c, ok := filter[constant.CategoryKey]
+       if !ok {
+               return nil, fmt.Errorf("no category")
+       }
+       delete(filter, constant.CategoryKey)
+       services, ok := cache.InterfaceRegistryCache.Load(c)
+       if !ok {
+               return nil, nil
+       }
+       servicesMap, ok := services.(*sync.Map)
+       if !ok {
+               return nil, fmt.Errorf("servicesMap type not *sync.Map")
+       }
+       return filterFromService(servicesMap, filter)
+}
+
+func filterFromService(servicesMap *sync.Map, filter map[string]string) 
(map[string]*common.URL, error) {
+       ret := make(map[string]*common.URL)
+       var err error
+
+       s, ok := filter[ServiceFilterKey]
+       if !ok {
+               servicesMap.Range(func(key, value any) bool {
+                       service, ok := value.(map[string]*common.URL)
+                       if !ok {
+                               err = fmt.Errorf("service type not 
map[string]*common.URL")
+                               return false
+                       }
+                       filterFromURLs(service, ret, filter)
+                       return true
+               })
+       } else {
+               delete(filter, ServiceFilterKey)
+               value, ok := servicesMap.Load(s)
+               if ok {
+                       service, ok := value.(map[string]*common.URL)
+                       if !ok {
+                               return nil, fmt.Errorf("service type not 
map[string]*common.URL")
+                       }
+                       filterFromURLs(service, ret, filter)
+               }
+       }
+       return ret, err
+}
+
+func filterFromURLs(from, to map[string]*common.URL, filter map[string]string) 
{
+       if from == nil || to == nil {
+               return
+       }
+       for id, url := range from {
+               match := true
+               for key, value := range filter {
+                       if key == AddressFilterKey {
+                               if strings.Contains(value, constant.Colon) {
+                                       if value != url.Location {
+                                               match = false
+                                               break
+                                       }
+                               } else {
+                                       if value != url.Ip {
+                                               match = false
+                                               break
+                                       }
+                               }
+                       } else {
+                               if value != url.GetParam(key, "") {
+                                       match = false
+                                       break
+                               }
+                       }
+               }
+               if match {
+                       to[id] = url
+               }
+       }
+}

Reply via email to