cache.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package geodata
  2. import (
  3. "io/ioutil"
  4. "runtime"
  5. "strings"
  6. "google.golang.org/protobuf/proto"
  7. "github.com/v2fly/v2ray-core/v4/app/router"
  8. "github.com/v2fly/v2ray-core/v4/common/platform"
  9. )
  10. type GeoIPCache map[string]*router.GeoIP
  11. func (g GeoIPCache) Has(key string) bool {
  12. return !(g.Get(key) == nil)
  13. }
  14. func (g GeoIPCache) Get(key string) *router.GeoIP {
  15. if g == nil {
  16. return nil
  17. }
  18. return g[key]
  19. }
  20. func (g GeoIPCache) Set(key string, value *router.GeoIP) {
  21. if g == nil {
  22. g = make(map[string]*router.GeoIP)
  23. }
  24. g[key] = value
  25. }
  26. func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
  27. asset := platform.GetAssetLocation(filename)
  28. idx := strings.ToUpper(asset + "|" + code)
  29. if g.Has(idx) {
  30. return g.Get(idx), nil
  31. }
  32. geoipBytes, err := Decode(asset, code)
  33. switch err {
  34. case nil:
  35. var geoip router.GeoIP
  36. if err := proto.Unmarshal(geoipBytes, &geoip); err != nil {
  37. return nil, err
  38. }
  39. g.Set(idx, &geoip)
  40. return &geoip, nil
  41. case errCodeNotFound:
  42. return nil, newError(code, " not found in ", filename)
  43. case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
  44. errInvalidGeodataFile, errInvalidGeodataVarintLength:
  45. newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog()
  46. geoipBytes, err = ioutil.ReadFile(asset)
  47. if err != nil {
  48. return nil, err
  49. }
  50. var geoipList router.GeoIPList
  51. if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
  52. return nil, err
  53. }
  54. runtime.GC()
  55. for _, geoip := range geoipList.GetEntry() {
  56. if strings.EqualFold(code, geoip.GetCountryCode()) {
  57. g.Set(idx, geoip)
  58. return geoip, nil
  59. }
  60. runtime.GC()
  61. }
  62. default:
  63. return nil, err
  64. }
  65. return nil, newError(code, " not found in ", filename)
  66. }
  67. type GeoSiteCache map[string]*router.GeoSite
  68. func (g GeoSiteCache) Has(key string) bool {
  69. return !(g.Get(key) == nil)
  70. }
  71. func (g GeoSiteCache) Get(key string) *router.GeoSite {
  72. if g == nil {
  73. return nil
  74. }
  75. return g[key]
  76. }
  77. func (g GeoSiteCache) Set(key string, value *router.GeoSite) {
  78. if g == nil {
  79. g = make(map[string]*router.GeoSite)
  80. }
  81. g[key] = value
  82. }
  83. func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) {
  84. asset := platform.GetAssetLocation(filename)
  85. idx := strings.ToUpper(asset + "|" + code)
  86. if g.Has(idx) {
  87. return g.Get(idx), nil
  88. }
  89. geositeBytes, err := Decode(asset, code)
  90. switch err {
  91. case nil:
  92. var geosite router.GeoSite
  93. if err := proto.Unmarshal(geositeBytes, &geosite); err != nil {
  94. return nil, err
  95. }
  96. g.Set(idx, &geosite)
  97. return &geosite, nil
  98. case errCodeNotFound:
  99. return nil, newError(code, " not found in ", filename)
  100. case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
  101. errInvalidGeodataFile, errInvalidGeodataVarintLength:
  102. newError("failed to decode geodata file: ", filename, ". Fallback to the original ReadFile method.").AtWarning().WriteToLog()
  103. geositeBytes, err = ioutil.ReadFile(asset)
  104. if err != nil {
  105. return nil, err
  106. }
  107. var geositeList router.GeoSiteList
  108. if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
  109. return nil, err
  110. }
  111. runtime.GC()
  112. for _, geosite := range geositeList.GetEntry() {
  113. if strings.EqualFold(code, geosite.GetCountryCode()) {
  114. g.Set(idx, geosite)
  115. return geosite, nil
  116. }
  117. runtime.GC()
  118. }
  119. default:
  120. return nil, err
  121. }
  122. return nil, newError(code, " not found in ", filename)
  123. }