chore: better geodata shared

This commit is contained in:
wwqgtxx 2023-03-23 18:58:24 +08:00
parent 7e10d78d53
commit a7944f1369
3 changed files with 44 additions and 49 deletions

View File

@ -1,13 +1,10 @@
package geodata package geodata
import ( import (
"errors"
"fmt" "fmt"
C "github.com/Dreamacro/clash/constant"
"strings"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
"github.com/Dreamacro/clash/log" C "github.com/Dreamacro/clash/constant"
) )
type loader struct { type loader struct {
@ -15,47 +12,7 @@ type loader struct {
} }
func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) { func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) {
return l.LoadGeoSiteWithAttr(C.GeositeName, list) return l.LoadSiteByPath(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
} }
func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) { func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) {

View File

@ -14,6 +14,5 @@ type LoaderImplementation interface {
type Loader interface { type Loader interface {
LoaderImplementation LoaderImplementation
LoadGeoSite(list string) ([]*router.Domain, error) LoadGeoSite(list string) ([]*router.Domain, error)
LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error)
LoadGeoIP(country string) ([]*router.CIDR, error) LoadGeoIP(country string) ([]*router.CIDR, error)
} }

View File

@ -1,12 +1,14 @@
package geodata package geodata
import ( import (
"errors"
"fmt" "fmt"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
"strings" "strings"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
) )
var geoLoaderName = "memconservative" var geoLoaderName = "memconservative"
@ -51,18 +53,52 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
} }
countryCode = strings.ToLower(countryCode) 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) geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return geoLoader.LoadGeoSite(countryCode) return geoLoader.LoadGeoSite(listName)
}) })
if err != nil { if err != nil {
if !shared {
loadGeoSiteMatcherSF.Forget(listName) // don't store the error result
}
return nil, 0, err return nil, 0, err
} }
domains := v.([]*router.Domain) 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 linear: linear algorithm
matcher, err := router.NewDomainMatcher(domains) matcher, err := router.NewDomainMatcher(domains)
@ -90,7 +126,7 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) {
} }
country = strings.ToLower(country) 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) geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -98,6 +134,9 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) {
return geoLoader.LoadGeoIP(country) return geoLoader.LoadGeoIP(country)
}) })
if err != nil { if err != nil {
if !shared {
loadGeoIPMatcherSF.Forget(country) // don't store the error result
}
return nil, 0, err return nil, 0, err
} }
records := v.([]*router.CIDR) records := v.([]*router.CIDR)