Files
utility_go/internal/logic/ip2region/ip2region.go
2025-09-18 17:54:11 +08:00

165 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package ip2region
import (
"net"
"path"
"strings"
"github.com/ayflying/utility_go/service"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
)
var (
ctx = gctx.New()
wait = false
)
const IpDbPath = "runtime/library"
type sIp2region struct {
//searcher *xdb.Searcher
searchers map[string]*xdb.Searcher
}
func New() *sIp2region {
return &sIp2region{}
}
func init() {
service.RegisterIp2Region(New())
//boot.AddFunc(func() {
// service.Ip2Region().Load()
//})
}
//func (s *sIp2region) New() *xdb.Searcher {
//
// return nil
//}
// Load 加载到内存中
//
// @Description: 加载ip2region数据库到内存中。
// @receiver s *sIp2region: sIp2region的实例。
func (s *sIp2region) Load(t *xdb.Version) {
var err error
var url string
//var dbPath = "runtime/library/ip2region.xdb"
switch t {
case xdb.IPv4:
//url = "https://github.com/ayflying/resource/raw/refs/heads/master/attachment/ip2region_v4.xdb"
url = "https://github.com/lionsoul2014/ip2region/raw/refs/heads/master/data/ip2region_v4.xdb"
case xdb.IPv6:
url = "https://github.com/lionsoul2014/ip2region/raw/refs/heads/master/data/ip2region_v6.xdb"
}
if wait {
return
}
filename := gfile.Basename(url)
var IpDbFile = path.Join(IpDbPath, filename)
g.Log().Debugf(ctx, "加载ip库文件:%v", filename)
if gfile.IsEmpty(IpDbFile) {
wait = true
defer func() {
wait = false
}()
g.Log().Debug(ctx, "等待下载ip库文件")
//下载文件
putData, err2 := g.Client().Discovery(nil).Get(ctx, url)
if err2 != nil {
return
}
err = gfile.PutBytes(IpDbFile, putData.ReadAll())
}
err = xdb.VerifyFromFile(IpDbFile)
if err != nil {
// err 包含的验证的错误
gfile.RemoveFile(IpDbFile)
g.Log().Errorf(ctx, "ip库xdb file verify: %v", err)
return
}
// 1、从 dbPath 加载 VectorIndex 缓存,把下述 vIndex 变量全局到内存里面。
vIndex, err := xdb.LoadVectorIndexFromFile(IpDbFile)
if err != nil {
g.Log().Errorf(ctx, "failed to load vector index from `%s`: %s\n", IpDbFile, err)
return
}
// 2、用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
if s.searchers == nil {
s.searchers = make(map[string]*xdb.Searcher)
}
s.searchers[t.Name], err = xdb.NewWithVectorIndex(t, IpDbFile, vIndex)
if err != nil {
g.Log().Errorf(ctx, "failed to create searcher with vector index: %s\n", err)
return
}
//cBuff := gfile.GetBytes(IpDbFile)
//// 基于读取的内容,创建查询对象
//s.searchers[t.Name], err = xdb.NewWithBuffer(t, cBuff)
//if err != nil {
// g.Log().Errorf(ctx, "无法创建内容为的搜索器: %s", err)
// return
//}
}
func (s *sIp2region) GetIp(ip string) (res []string) {
//初始化加载
//if s.searcher == nil {
// s.Load(xdb.IPv6)
//}
var searchers *xdb.Searcher
//区分ipv6与ipv4
if s.isIPv6(ip) {
if s.searchers[xdb.IPv6.Name] == nil {
s.Load(xdb.IPv6)
}
searchers = s.searchers[xdb.IPv6.Name]
} else {
if s.searchers[xdb.IPv4.Name] == nil {
s.Load(xdb.IPv4)
}
searchers = s.searchers[xdb.IPv4.Name]
}
res = make([]string, 5)
if searchers == nil {
return
}
region, err := searchers.SearchByStr(ip)
if err != nil {
return
}
res = strings.Split(region, "|")
return
}
// isIPv6 判断输入字符串是否为IPv6地址
//
// @Description: 通过解析输入的IP字符串判断其是否为IPv6地址。
// @receiver s *sIp2region: 代表`sIp2region`类型的实例,本函数中未使用,可忽略。
// @param ipStr string: 待判断的IP地址字符串。
// @return bool: 返回true表示是IPv6地址返回false表示不是IPv6地址。
func (s *sIp2region) isIPv6(ipStr string) bool {
// 尝试将输入字符串解析为IP地址
ip := net.ParseIP(ipStr)
// 尝试将IP地址转换为IPv4格式
ipv4 := ip.To4()
// 如果转换为IPv4格式不为nil则说明是IPv4地址返回false
if ipv4 != nil {
return false
}
// 如果无法转换为IPv4格式则说明是IPv6地址返回true
return true
}