mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 04:30:08 +00:00
hy2内核增加自定义配置
This commit is contained in:
181
core/hy2/geoloader.go
Normal file
181
core/hy2/geoloader.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/apernet/hysteria/extras/outbounds/acl"
|
||||
"github.com/apernet/hysteria/extras/outbounds/acl/v2geo"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
geoipFilename = "geoip.dat"
|
||||
geoipURL = "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
|
||||
geositeFilename = "geosite.dat"
|
||||
geositeURL = "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
|
||||
geoDlTmpPattern = ".hysteria-geoloader.dlpart.*"
|
||||
|
||||
geoDefaultUpdateInterval = 7 * 24 * time.Hour // 7 days
|
||||
)
|
||||
|
||||
var _ acl.GeoLoader = (*GeoLoader)(nil)
|
||||
|
||||
// GeoLoader provides the on-demand GeoIP/GeoSite database
|
||||
// loading functionality required by the ACL engine.
|
||||
// Empty filenames = automatic download from built-in URLs.
|
||||
type GeoLoader struct {
|
||||
GeoIPFilename string
|
||||
GeoSiteFilename string
|
||||
UpdateInterval time.Duration
|
||||
|
||||
geoipMap map[string]*v2geo.GeoIP
|
||||
geositeMap map[string]*v2geo.GeoSite
|
||||
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
func (l *GeoLoader) shouldDownload(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
if info.Size() == 0 {
|
||||
// empty files are loadable by v2geo, but we consider it broken
|
||||
return true
|
||||
}
|
||||
dt := time.Since(info.ModTime())
|
||||
if l.UpdateInterval == 0 {
|
||||
return dt > geoDefaultUpdateInterval
|
||||
} else {
|
||||
return dt > l.UpdateInterval
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GeoLoader) downloadAndCheck(filename, url string, checkFunc func(filename string) error) error {
|
||||
l.geoDownloadFunc(filename, url)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
l.geoDownloadErrFunc(err)
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
f, err := os.CreateTemp(".", geoDlTmpPattern)
|
||||
if err != nil {
|
||||
l.geoDownloadErrFunc(err)
|
||||
return err
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
l.geoDownloadErrFunc(err)
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
|
||||
err = checkFunc(f.Name())
|
||||
if err != nil {
|
||||
l.geoDownloadErrFunc(fmt.Errorf("integrity check failed: %w", err))
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.Rename(f.Name(), filename)
|
||||
if err != nil {
|
||||
l.geoDownloadErrFunc(fmt.Errorf("rename failed: %w", err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (l *GeoLoader) LoadGeoIP() (map[string]*v2geo.GeoIP, error) {
|
||||
if l.geoipMap != nil {
|
||||
return l.geoipMap, nil
|
||||
}
|
||||
autoDL := false
|
||||
filename := l.GeoIPFilename
|
||||
if filename == "" {
|
||||
autoDL = true
|
||||
filename = geoipFilename
|
||||
}
|
||||
if autoDL {
|
||||
if !l.shouldDownload(filename) {
|
||||
m, err := v2geo.LoadGeoIP(filename)
|
||||
if err == nil {
|
||||
l.geoipMap = m
|
||||
return m, nil
|
||||
}
|
||||
// file is broken, download it again
|
||||
}
|
||||
err := l.downloadAndCheck(filename, geoipURL, func(filename string) error {
|
||||
_, err := v2geo.LoadGeoIP(filename)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
// as long as the previous download exists, fallback to it
|
||||
if _, serr := os.Stat(filename); os.IsNotExist(serr) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
m, err := v2geo.LoadGeoIP(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.geoipMap = m
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (l *GeoLoader) LoadGeoSite() (map[string]*v2geo.GeoSite, error) {
|
||||
if l.geositeMap != nil {
|
||||
return l.geositeMap, nil
|
||||
}
|
||||
autoDL := false
|
||||
filename := l.GeoSiteFilename
|
||||
if filename == "" {
|
||||
autoDL = true
|
||||
filename = geositeFilename
|
||||
}
|
||||
if autoDL {
|
||||
if !l.shouldDownload(filename) {
|
||||
m, err := v2geo.LoadGeoSite(filename)
|
||||
if err == nil {
|
||||
l.geositeMap = m
|
||||
return m, nil
|
||||
}
|
||||
// file is broken, download it again
|
||||
}
|
||||
err := l.downloadAndCheck(filename, geositeURL, func(filename string) error {
|
||||
_, err := v2geo.LoadGeoSite(filename)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
// as long as the previous download exists, fallback to it
|
||||
if _, serr := os.Stat(filename); os.IsNotExist(serr) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
m, err := v2geo.LoadGeoSite(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.geositeMap = m
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (l *GeoLoader) geoDownloadFunc(filename, url string) {
|
||||
l.Logger.Info("downloading database", zap.String("filename", filename), zap.String("url", url))
|
||||
}
|
||||
|
||||
func (l *GeoLoader) geoDownloadErrFunc(err error) {
|
||||
if err != nil {
|
||||
l.Logger.Error("failed to download database", zap.Error(err))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user