diff --git a/component/geodata/geodata.go b/component/geodata/geodata.go index ac0f820e..9d0b0df0 100644 --- a/component/geodata/geodata.go +++ b/component/geodata/geodata.go @@ -1,13 +1,10 @@ package geodata import ( - "errors" "fmt" - C "github.com/Dreamacro/clash/constant" - "strings" "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/log" + C "github.com/Dreamacro/clash/constant" ) type loader struct { @@ -15,47 +12,7 @@ type loader struct { } func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) { - return l.LoadGeoSiteWithAttr(C.GeositeName, list) -} - -func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) { - parts := strings.Split(siteWithAttr, "@") - if len(parts) == 0 { - return nil, errors.New("empty rule") - } - list := strings.TrimSpace(parts[0]) - attrVal := parts[1:] - - if len(list) == 0 { - return nil, fmt.Errorf("empty listname in rule: %s", siteWithAttr) - } - - domains, err := l.LoadSiteByPath(file, list) - if err != nil { - return nil, err - } - - attrs := parseAttrs(attrVal) - if attrs.IsEmpty() { - if strings.Contains(siteWithAttr, "@") { - log.Warnln("empty attribute list: %s", siteWithAttr) - } - return domains, nil - } - - filteredDomains := make([]*router.Domain, 0, len(domains)) - hasAttrMatched := false - for _, domain := range domains { - if attrs.Match(domain) { - hasAttrMatched = true - filteredDomains = append(filteredDomains, domain) - } - } - if !hasAttrMatched { - log.Warnln("attribute match no rule: geosite: %s", siteWithAttr) - } - - return filteredDomains, nil + return l.LoadSiteByPath(C.GeositeName, list) } func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) { diff --git a/component/geodata/geodataproto.go b/component/geodata/geodataproto.go index ffefc484..34bdad70 100644 --- a/component/geodata/geodataproto.go +++ b/component/geodata/geodataproto.go @@ -14,6 +14,5 @@ type LoaderImplementation interface { type Loader interface { LoaderImplementation LoadGeoSite(list string) ([]*router.Domain, error) - LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) LoadGeoIP(country string) ([]*router.CIDR, error) } diff --git a/component/geodata/utils.go b/component/geodata/utils.go index f1ea7151..04ccfa51 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -1,12 +1,14 @@ package geodata import ( + "errors" "fmt" "golang.org/x/sync/singleflight" "strings" "github.com/Dreamacro/clash/component/geodata/router" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) var geoLoaderName = "memconservative" @@ -51,18 +53,52 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) } countryCode = strings.ToLower(countryCode) - v, err, _ := loadGeoSiteMatcherSF.Do(countryCode, func() (interface{}, error) { + parts := strings.Split(countryCode, "@") + if len(parts) == 0 { + return nil, 0, errors.New("empty rule") + } + listName := strings.TrimSpace(parts[0]) + attrVal := parts[1:] + + if len(listName) == 0 { + return nil, 0, fmt.Errorf("empty listname in rule: %s", countryCode) + } + + v, err, shared := loadGeoSiteMatcherSF.Do(listName, func() (interface{}, error) { geoLoader, err := GetGeoDataLoader(geoLoaderName) if err != nil { return nil, err } - return geoLoader.LoadGeoSite(countryCode) + return geoLoader.LoadGeoSite(listName) }) if err != nil { + if !shared { + loadGeoSiteMatcherSF.Forget(listName) // don't store the error result + } return nil, 0, err } domains := v.([]*router.Domain) + attrs := parseAttrs(attrVal) + if attrs.IsEmpty() { + if strings.Contains(countryCode, "@") { + log.Warnln("empty attribute list: %s", countryCode) + } + } else { + filteredDomains := make([]*router.Domain, 0, len(domains)) + hasAttrMatched := false + for _, domain := range domains { + if attrs.Match(domain) { + hasAttrMatched = true + filteredDomains = append(filteredDomains, domain) + } + } + if !hasAttrMatched { + log.Warnln("attribute match no rule: geosite: %s", countryCode) + } + domains = filteredDomains + } + /** linear: linear algorithm matcher, err := router.NewDomainMatcher(domains) @@ -90,7 +126,7 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { } country = strings.ToLower(country) - v, err, _ := loadGeoIPMatcherSF.Do(country, func() (interface{}, error) { + v, err, shared := loadGeoIPMatcherSF.Do(country, func() (interface{}, error) { geoLoader, err := GetGeoDataLoader(geoLoaderName) if err != nil { return nil, err @@ -98,6 +134,9 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { return geoLoader.LoadGeoIP(country) }) if err != nil { + if !shared { + loadGeoIPMatcherSF.Forget(country) // don't store the error result + } return nil, 0, err } records := v.([]*router.CIDR)