github.com/kelleygo/clashcore@v1.0.2/component/geodata/memconservative/cache.go (about)

     1  package memconservative
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/kelleygo/clashcore/component/geodata/router"
     9  	C "github.com/kelleygo/clashcore/constant"
    10  	"github.com/kelleygo/clashcore/log"
    11  	"google.golang.org/protobuf/proto"
    12  )
    13  
    14  type GeoIPCache map[string]*router.GeoIP
    15  
    16  func (g GeoIPCache) Has(key string) bool {
    17  	return !(g.Get(key) == nil)
    18  }
    19  
    20  func (g GeoIPCache) Get(key string) *router.GeoIP {
    21  	if g == nil {
    22  		return nil
    23  	}
    24  	return g[key]
    25  }
    26  
    27  func (g GeoIPCache) Set(key string, value *router.GeoIP) {
    28  	if g == nil {
    29  		g = make(map[string]*router.GeoIP)
    30  	}
    31  	g[key] = value
    32  }
    33  
    34  func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
    35  	asset := C.Path.GetAssetLocation(filename)
    36  	idx := strings.ToLower(asset + ":" + code)
    37  	if g.Has(idx) {
    38  		return g.Get(idx), nil
    39  	}
    40  
    41  	geoipBytes, err := Decode(asset, code)
    42  	switch err {
    43  	case nil:
    44  		var geoip router.GeoIP
    45  		if err := proto.Unmarshal(geoipBytes, &geoip); err != nil {
    46  			return nil, err
    47  		}
    48  		g.Set(idx, &geoip)
    49  		return &geoip, nil
    50  
    51  	case errCodeNotFound:
    52  		return nil, fmt.Errorf("country code %s%s%s", code, " not found in ", filename)
    53  
    54  	case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
    55  		errInvalidGeodataFile, errInvalidGeodataVarintLength:
    56  		log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method")
    57  		geoipBytes, err = os.ReadFile(asset)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		var geoipList router.GeoIPList
    62  		if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
    63  			return nil, err
    64  		}
    65  		for _, geoip := range geoipList.GetEntry() {
    66  			if strings.EqualFold(code, geoip.GetCountryCode()) {
    67  				g.Set(idx, geoip)
    68  				return geoip, nil
    69  			}
    70  		}
    71  
    72  	default:
    73  		return nil, err
    74  	}
    75  
    76  	return nil, fmt.Errorf("country code %s%s%s", code, " not found in ", filename)
    77  }
    78  
    79  type GeoSiteCache map[string]*router.GeoSite
    80  
    81  func (g GeoSiteCache) Has(key string) bool {
    82  	return !(g.Get(key) == nil)
    83  }
    84  
    85  func (g GeoSiteCache) Get(key string) *router.GeoSite {
    86  	if g == nil {
    87  		return nil
    88  	}
    89  	return g[key]
    90  }
    91  
    92  func (g GeoSiteCache) Set(key string, value *router.GeoSite) {
    93  	if g == nil {
    94  		g = make(map[string]*router.GeoSite)
    95  	}
    96  	g[key] = value
    97  }
    98  
    99  func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) {
   100  	asset := C.Path.GetAssetLocation(filename)
   101  	idx := strings.ToLower(asset + ":" + code)
   102  	if g.Has(idx) {
   103  		return g.Get(idx), nil
   104  	}
   105  
   106  	geositeBytes, err := Decode(asset, code)
   107  	switch err {
   108  	case nil:
   109  		var geosite router.GeoSite
   110  		if err := proto.Unmarshal(geositeBytes, &geosite); err != nil {
   111  			return nil, err
   112  		}
   113  		g.Set(idx, &geosite)
   114  		return &geosite, nil
   115  
   116  	case errCodeNotFound:
   117  		return nil, fmt.Errorf("list %s%s%s", code, " not found in ", filename)
   118  
   119  	case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
   120  		errInvalidGeodataFile, errInvalidGeodataVarintLength:
   121  		log.Warnln("failed to decode geosite file: %s%s", filename, ", fallback to the original ReadFile method")
   122  		geositeBytes, err = os.ReadFile(asset)
   123  		if err != nil {
   124  			return nil, err
   125  		}
   126  		var geositeList router.GeoSiteList
   127  		if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
   128  			return nil, err
   129  		}
   130  		for _, geosite := range geositeList.GetEntry() {
   131  			if strings.EqualFold(code, geosite.GetCountryCode()) {
   132  				g.Set(idx, geosite)
   133  				return geosite, nil
   134  			}
   135  		}
   136  
   137  	default:
   138  		return nil, err
   139  	}
   140  
   141  	return nil, fmt.Errorf("list %s%s%s", code, " not found in ", filename)
   142  }