Files

125 lines
3.1 KiB
Go
Raw Permalink 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 geo
import (
"log"
"os"
"strings"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
)
// Geo 基于 ip2region v4 离线库的 IP 地区解析器(纯本地,无外部依赖)
type Geo struct {
searcher *xdb.Searcher
}
// New 按顺序尝试数据文件路径加载;全部失败时返回可用但禁用的实例(地区解析优雅降级)
func New(paths ...string) *Geo {
var dbPath string
for _, p := range paths {
if _, err := os.Stat(p); err == nil {
dbPath = p
break
}
}
if dbPath == "" {
log.Printf("[geo] 未找到 ip2region 数据文件(尝试: %v),地区解析已禁用", paths)
return &Geo{}
}
handle, err := os.Open(dbPath)
if err != nil {
log.Printf("[geo] 打开 %s 失败: %v", dbPath, err)
return &Geo{}
}
defer handle.Close()
header, err := xdb.LoadHeader(handle)
if err != nil {
log.Printf("[geo] 读取 %s 头部失败: %v", dbPath, err)
return &Geo{}
}
version, err := xdb.VersionFromHeader(header)
if err != nil {
log.Printf("[geo] 识别 %s 版本失败: %v", dbPath, err)
return &Geo{}
}
// 整库载入内存,查询性能最好(约 11MB)
buff, err := xdb.LoadContentFromFile(dbPath)
if err != nil {
log.Printf("[geo] 加载 %s 数据失败: %v", dbPath, err)
return &Geo{}
}
searcher, err := xdb.NewWithBuffer(version, buff)
if err != nil {
log.Printf("[geo] 初始化搜索器失败: %v", err)
return &Geo{}
}
log.Printf("[geo] ip2region 已加载(%.0f MB%s", float64(len(buff))/1024/1024, dbPath)
return &Geo{searcher: searcher}
}
// Search 返回友好地区名(如 "广东省深圳市 电信"、"新加坡");解析失败返回 ""
func (g *Geo) Search(ip string) string {
if g == nil || g.searcher == nil || ip == "" {
return ""
}
region, err := g.searcher.Search(ip)
if err != nil {
return ""
}
return Format(region)
}
// Format 把 ip2region v4 原始格式 "国家|省|市|ISP|国家码" 转为友好显示
// 例:中国|江苏省|南京市|0|CN → "江苏省南京市";中国|上海|上海市|电信|CN → "上海市 电信"
// United States|California|0|Google LLC|US → "United States California · Google LLC"
func Format(region string) string {
parts := strings.Split(region, "|")
if len(parts) < 5 {
return region
}
country, province, city, isp := parts[0], parts[1], parts[2], parts[3]
if country == "" || country == "0" || country == "Reserved" {
return "" // 保留地址/内网/IPv6 不在 v4 库中
}
if isp == "0" {
isp = ""
}
if country == "中国" {
loc := ""
switch {
case province != "" && province != "0" && city != "" && city != "0":
if city == province || strings.Contains(city, province) {
loc = city // 直辖市:"上海市"
} else {
loc = province + city // "江苏省南京市"
}
case province != "" && province != "0":
loc = province
default:
loc = "中国"
}
if isp != "" {
loc += " " + isp
}
return loc
}
// 国外:国家 + 州/市(英文)
loc := country
switch {
case province != "" && province != "0":
loc += " " + province
case city != "" && city != "0":
loc += " " + city
}
if isp != "" {
loc += " · " + isp
}
return loc
}