feat: geo ip.
This commit is contained in:
15
geoip/geoip.go
Normal file
15
geoip/geoip.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package geoip
|
||||||
|
|
||||||
|
// Result 归属地信息
|
||||||
|
type Result struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Country string `json:"country"` // 国家
|
||||||
|
Province string `json:"province"` // 省
|
||||||
|
City string `json:"city"` // 城市
|
||||||
|
ISP string `json:"isp"` // 服务提供商
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeoIP 客户端
|
||||||
|
type GeoIP interface {
|
||||||
|
Query(queryIp string) (res Result, err error)
|
||||||
|
}
|
||||||
1
geoip/geoip_test.go
Normal file
1
geoip/geoip_test.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package geoip
|
||||||
@@ -6,15 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/go-kratos/kratos/v2/log"
|
"github.com/go-kratos/kratos/v2/log"
|
||||||
"github.com/oschwald/geoip2-golang"
|
"github.com/oschwald/geoip2-golang"
|
||||||
|
|
||||||
|
"github.com/tx7do/kratos-utils/geoip"
|
||||||
"github.com/tx7do/kratos-utils/geoip/geolite/assets"
|
"github.com/tx7do/kratos-utils/geoip/geolite/assets"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Result struct {
|
|
||||||
Country string // 国家
|
|
||||||
Province string // 省
|
|
||||||
City string // 城市
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultOutputLanguage = "zh-CN"
|
const defaultOutputLanguage = "zh-CN"
|
||||||
|
|
||||||
// Client 地理位置解析结构体
|
// Client 地理位置解析结构体
|
||||||
@@ -56,7 +52,7 @@ func (g *Client) query(rawIP string) (city *geoip2.City, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Query 通过IP获取地区
|
// Query 通过IP获取地区
|
||||||
func (g *Client) Query(rawIP string) (ret Result, err error) {
|
func (g *Client) Query(rawIP string) (ret geoip.Result, err error) {
|
||||||
record, err := g.query(rawIP)
|
record, err := g.query(rawIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
@@ -7,14 +7,3 @@ const (
|
|||||||
|
|
||||||
redirectMode2 = 0x02 // RedirectMode2 国家的类型, 指向一个指向
|
redirectMode2 = 0x02 // RedirectMode2 国家的类型, 指向一个指向
|
||||||
)
|
)
|
||||||
|
|
||||||
//var unCountry = []byte{"未知国家"}
|
|
||||||
//var unArea = []byte{"未知地区"}
|
|
||||||
|
|
||||||
// Result 归属地信息
|
|
||||||
type Result struct {
|
|
||||||
IP string `json:"ip"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
Area string `json:"area"`
|
|
||||||
ISP string `json:"isp"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package qqwry
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/tx7do/kratos-utils/geoip"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -136,7 +137,10 @@ func (c *Client) readUInt24(offset int32) uint32 {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Query(queryIp string) (country, city, isp string, err error) {
|
func (c *Client) Query(queryIp string) (res geoip.Result, err error) {
|
||||||
|
res.IP = queryIp
|
||||||
|
res.Country = "中国"
|
||||||
|
|
||||||
ip32, err := c.parseIp(queryIp)
|
ip32, err := c.parseIp(queryIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -152,7 +156,8 @@ func (c *Client) Query(queryIp string) (country, city, isp string, err error) {
|
|||||||
offset += 4
|
offset += 4
|
||||||
mode := c.readMode(uint32(offset))
|
mode := c.readMode(uint32(offset))
|
||||||
|
|
||||||
var _city []byte
|
var _area []byte
|
||||||
|
var area string
|
||||||
|
|
||||||
var ispPos uint32
|
var ispPos uint32
|
||||||
switch mode {
|
switch mode {
|
||||||
@@ -164,25 +169,35 @@ func (c *Client) Query(queryIp string) (country, city, isp string, err error) {
|
|||||||
posCA = c.readUInt24(int32(posC) + 1)
|
posCA = c.readUInt24(int32(posC) + 1)
|
||||||
posC += 4
|
posC += 4
|
||||||
}
|
}
|
||||||
_city = c.readString(posCA)
|
_area = c.readString(posCA)
|
||||||
if mode != redirectMode2 {
|
if mode != redirectMode2 {
|
||||||
posC += uint32(len(city) + 1)
|
posC += uint32(len(area) + 1)
|
||||||
}
|
}
|
||||||
ispPos = posC
|
ispPos = posC
|
||||||
|
|
||||||
case redirectMode2:
|
case redirectMode2:
|
||||||
posCA := c.readUInt24(offset + 1)
|
posCA := c.readUInt24(offset + 1)
|
||||||
_city = c.readString(posCA)
|
_area = c.readString(posCA)
|
||||||
ispPos = uint32(offset) + 4
|
ispPos = uint32(offset) + 4
|
||||||
|
|
||||||
default:
|
default:
|
||||||
posCA := offset + 0
|
posCA := offset + 0
|
||||||
_city = c.readString(uint32(posCA))
|
_area = c.readString(uint32(posCA))
|
||||||
ispPos = uint32(offset) + uint32(len(city)) + 1
|
ispPos = uint32(offset) + uint32(len(area)) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(_city) != 0 {
|
if len(_area) != 0 {
|
||||||
city = strings.TrimSpace(gb18030Decode(_city))
|
area = strings.TrimSpace(gb18030Decode(_area))
|
||||||
|
|
||||||
|
areas := SpiltAddress(area)
|
||||||
|
if len(areas) == 2 {
|
||||||
|
res.Province = areas[0]
|
||||||
|
res.City = areas[1]
|
||||||
|
} else if len(areas) == 1 {
|
||||||
|
res.City = areas[0]
|
||||||
|
} else {
|
||||||
|
res.City = area
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ispMode := assets.QQWryDat[ispPos]
|
ispMode := assets.QQWryDat[ispPos]
|
||||||
@@ -192,10 +207,10 @@ func (c *Client) Query(queryIp string) (country, city, isp string, err error) {
|
|||||||
if ispPos > 0 {
|
if ispPos > 0 {
|
||||||
var _isp []byte
|
var _isp []byte
|
||||||
_isp = c.readString(ispPos)
|
_isp = c.readString(ispPos)
|
||||||
isp = strings.TrimSpace(gb18030Decode(_isp))
|
res.ISP = strings.TrimSpace(gb18030Decode(_isp))
|
||||||
if isp != "" {
|
if res.ISP != "" {
|
||||||
if strings.Contains(isp, "CZ88.NET") {
|
if strings.Contains(res.ISP, "CZ88.NET") {
|
||||||
isp = ""
|
res.ISP = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,20 @@ package qqwry
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClient(t *testing.T) {
|
func TestClient(t *testing.T) {
|
||||||
g := NewClient()
|
g := NewClient()
|
||||||
assert.NotNil(t, g)
|
assert.NotNil(t, g)
|
||||||
|
|
||||||
country, city, isp, err := g.Query("47.108.149.89")
|
res, err := g.Query("47.108.149.89")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
fmt.Println("国家:", country, "城市:", city, "服务商:", isp)
|
fmt.Println("国家:", res.Country, "省:", res.Province, "城市:", res.City, "服务商:", res.ISP)
|
||||||
|
assert.Equal(t, res.Country, "中国")
|
||||||
|
assert.Equal(t, res.Province, "四川省")
|
||||||
|
assert.Equal(t, res.City, "成都市")
|
||||||
|
assert.Equal(t, res.ISP, "阿里云")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ package qqwry
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var regSpiltAddress = regexp.MustCompile(`.+?(省|市|自治区|自治州|盟|县|区|管委会|街道|镇|乡)`)
|
||||||
|
|
||||||
func gb18030Decode(src []byte) string {
|
func gb18030Decode(src []byte) string {
|
||||||
in := bytes.NewReader(src)
|
in := bytes.NewReader(src)
|
||||||
out := transform.NewReader(in, simplifiedchinese.GB18030.NewDecoder())
|
out := transform.NewReader(in, simplifiedchinese.GB18030.NewDecoder())
|
||||||
@@ -26,3 +29,7 @@ func byte3ToUInt32(data []byte) uint32 {
|
|||||||
i |= (uint32(data[2]) << 16) & 0xff0000
|
i |= (uint32(data[2]) << 16) & 0xff0000
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SpiltAddress(addr string) []string {
|
||||||
|
return regSpiltAddress.FindAllString(addr, -1)
|
||||||
|
}
|
||||||
|
|||||||
11
geoip/qqwry/utils_test.go
Normal file
11
geoip/qqwry/utils_test.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package qqwry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSpiltAddress(t *testing.T) {
|
||||||
|
names := SpiltAddress("浙江省杭州市西湖区")
|
||||||
|
fmt.Println(names)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user