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
+ }
+ }
+}