|
|
|
|
package ip2region
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"net"
|
|
|
|
|
"strconv"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type QueryResult struct {
|
|
|
|
|
Ip string `json:"ip,omitempty"` // ip
|
|
|
|
|
CityId int64 `json:"city_id,omitempty"` // 城市代码
|
|
|
|
|
Country string `json:"country,omitempty"` // 国家
|
|
|
|
|
Region string `json:"region,omitempty"` // 区域
|
|
|
|
|
Province string `json:"province,omitempty"` // 省份
|
|
|
|
|
City string `json:"city,omitempty"` // 城市
|
|
|
|
|
Isp string `json:"isp,omitempty"` // 运营商
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ip QueryResult) String() string {
|
|
|
|
|
return ip.Ip + "|" + strconv.FormatInt(ip.CityId, 10) + "|" + ip.Country + "|" + ip.Region + "|" + ip.Province + "|" + ip.City + "|" + ip.Isp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query memory算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内
|
|
|
|
|
func (c *Client) Query(ipAddress net.IP) (result QueryResult, err error) {
|
|
|
|
|
|
|
|
|
|
result.Ip = ipAddress.String()
|
|
|
|
|
|
|
|
|
|
if c.totalBlocks == 0 {
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
|
|
return QueryResult{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.firstIndexPtr = getLong(dbBuff, 0)
|
|
|
|
|
c.lastIndexPtr = getLong(dbBuff, 4)
|
|
|
|
|
c.totalBlocks = (c.lastIndexPtr-c.firstIndexPtr)/IndexBlockLength + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ip, err := ip2long(result.Ip)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return QueryResult{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h := c.totalBlocks
|
|
|
|
|
var dataPtr, l int64
|
|
|
|
|
for l <= h {
|
|
|
|
|
|
|
|
|
|
m := (l + h) >> 1
|
|
|
|
|
p := c.firstIndexPtr + m*IndexBlockLength
|
|
|
|
|
sip := getLong(dbBuff, p)
|
|
|
|
|
if ip < sip {
|
|
|
|
|
h = m - 1
|
|
|
|
|
} else {
|
|
|
|
|
eip := getLong(dbBuff, p+4)
|
|
|
|
|
if ip > eip {
|
|
|
|
|
l = m + 1
|
|
|
|
|
} else {
|
|
|
|
|
dataPtr = getLong(dbBuff, p+8)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if dataPtr == 0 {
|
|
|
|
|
return QueryResult{}, errors.New("not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataLen := (dataPtr >> 24) & 0xFF
|
|
|
|
|
dataPtr = dataPtr & 0x00FFFFFF
|
|
|
|
|
result = getIpInfo(result.Ip, getLong(dbBuff, dataPtr), dbBuff[(dataPtr)+4:dataPtr+dataLen])
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|