pkg/admin/services/provider_service_impl.go (310 lines of code) (raw):

// 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. package services import ( "fmt" "regexp" "strings" "sync" set "github.com/dubbogo/gost/container/set" "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" "github.com/apache/dubbo-admin/pkg/admin/model/util" ) type ProviderServiceImpl struct{} // FindServices finds all services func (p *ProviderServiceImpl) FindServices() (*set.HashSet, error) { services := set.NewSet() servicesAny, ok := cache.InterfaceRegistryCache.Load(constant.ProvidersCategory) if !ok { return services, nil } servicesMap, ok := servicesAny.(*sync.Map) if !ok { return services, fmt.Errorf("servicesMap type not *sync.Map") } servicesMap.Range(func(key, value any) bool { services.Add(key.(string)) return true }) return services, nil } // FindApplications finds all applications func (p *ProviderServiceImpl) FindApplications() (*set.HashSet, error) { var ( applications = set.NewSet() err error ) providersAny, ok := cache.InterfaceRegistryCache.Load(constant.ProvidersCategory) if !ok { return applications, nil } err = extractApplications(providersAny, applications) if err != nil { return applications, err } consumersAny, ok := cache.InterfaceRegistryCache.Load(constant.ConsumersCategory) if !ok { return applications, nil } err = extractApplications(consumersAny, applications) if err != nil { return applications, err } return applications, err } func extractApplications(servicesAny any, applications *set.HashSet) error { servicesMap, ok := servicesAny.(*sync.Map) if !ok { return fmt.Errorf("servicesMap type not *sync.Map") } var err error 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.Add(app) } } return true }) return err } // findAddresses finds all addresses func (p *ProviderServiceImpl) findAddresses() (*set.HashSet, error) { var ( addresses = set.NewSet() err error ) servicesAny, ok := cache.InterfaceRegistryCache.Load(constant.ProvidersCategory) if !ok { return addresses, nil } err = extractAddresses(servicesAny, addresses) if err != nil { return addresses, err } consumersAny, ok := cache.InterfaceRegistryCache.Load(constant.ConsumersCategory) if !ok { return addresses, nil } err = extractAddresses(consumersAny, addresses) if err != nil { return addresses, err } return addresses, err } func extractAddresses(servicesAny any, addresses *set.HashSet) error { servicesMap, ok := servicesAny.(*sync.Map) if !ok { return fmt.Errorf("servicesMap type not *sync.Map") } var err error 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.Add(loc) } } return true }) return err } // FindVersions finds all versions func (p *ProviderServiceImpl) FindVersions() (*set.HashSet, error) { var ( versions = set.NewSet() err error ) servicesAny, ok := cache.InterfaceRegistryCache.Load(constant.ProvidersCategory) if !ok { return versions, nil } err = extractVersions(servicesAny, versions) if err != nil { return versions, err } return versions, err } func extractVersions(servicesAny any, versions *set.HashSet) error { servicesMap, ok := servicesAny.(*sync.Map) if !ok { return fmt.Errorf("servicesMap type not *sync.Map") } var err error 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 { release := url.GetParam("release", "") if release == "" { release = url.GetParam("revision", "") } if release != "" { versions.Add(release) } } return true }) return err } // FindProtocols finds all protocols func (p *ProviderServiceImpl) FindProtocols() (*set.HashSet, error) { var ( protocols = set.NewSet() err error ) servicesAny, ok := cache.InterfaceRegistryCache.Load(constant.ProvidersCategory) if !ok { return protocols, nil } err = extractProtocols(servicesAny, protocols) if err != nil { return protocols, err } return protocols, err } func extractProtocols(servicesAny any, protocols *set.HashSet) error { servicesMap, ok := servicesAny.(*sync.Map) if !ok { return fmt.Errorf("servicesMap type not *sync.Map") } var err error 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 { proto := url.Protocol if proto != "" && proto != "consumer" { protocols.Add(proto) } } return true }) return err } // FindByService finds providers by service name and returns a list of providers 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 } return util.URL2ProviderList(servicesMap), nil } // findByAddress finds providers by address and returns a list of providers 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 } return util.URL2ProviderList(servicesMap), nil } // findByApplication finds providers by application and returns a list of providers 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 } return util.URL2ProviderList(servicesMap), nil } // FindService by patterns and filters, patterns support IP, service and application. func (p *ProviderServiceImpl) FindService(pattern string, filter string) ([]*model.ServiceDTO, 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 *set.HashSet 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.ReplaceAll(filter, constant.PunctuationPoint, "\\.") if hasPrefixOrSuffix(filter) { filter = strings.ReplaceAll(filter, constant.AnyValue, constant.PunctuationPoint+constant.AnyValue) } reg, err = regexp.Compile(filter) if err != nil { return nil, err } items := candidates.Values() for _, candidateAny := range items { candidate := candidateAny.(string) 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 util.Providers2DTO(providers), nil } func hasPrefixOrSuffix(filter string) bool { return strings.HasPrefix(filter, constant.AnyValue) || strings.HasPrefix(filter, constant.InterrogationPoint) || strings.HasPrefix(filter, constant.PlusSigns) || strings.HasSuffix(filter, constant.AnyValue) || strings.HasSuffix(filter, constant.InterrogationPoint) || strings.HasSuffix(filter, constant.PlusSigns) }