147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
package ip_tool
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"net/url"
|
||
"time"
|
||
|
||
"github.com/pkg/errors"
|
||
)
|
||
|
||
type HuaChenIpClient struct {
|
||
AppCode string
|
||
Host string
|
||
cache ICacheAdapter
|
||
}
|
||
|
||
func NewHuaChenIpClient(appCode string, cache ICacheAdapter) *HuaChenIpClient {
|
||
return &HuaChenIpClient{
|
||
AppCode: appCode,
|
||
Host: "https://c2ba.api.huachen.cn",
|
||
cache: cache,
|
||
}
|
||
}
|
||
|
||
func (h *HuaChenIpClient) GetIpInfo(ip string) (res *ApiResult, err error) {
|
||
if ip == "" {
|
||
return nil, errors.New("请输入ip地址")
|
||
}
|
||
// 设置参数
|
||
params := url.Values{}
|
||
params.Add("ip", ip)
|
||
// 拼接URL
|
||
var fullURL string
|
||
fullURL, err = url.JoinPath(h.Host, "ip")
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,拼接路径错误", ip)
|
||
}
|
||
// 拼接参数
|
||
fullURL = fmt.Sprintf("%s?%s", fullURL, params.Encode())
|
||
// 创建HTTP客户端
|
||
client := &http.Client{}
|
||
// 创建请求
|
||
var req *http.Request
|
||
req, err = http.NewRequest(http.MethodGet, fullURL, nil)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,创建请求失败", ip)
|
||
}
|
||
|
||
// 设置请求头
|
||
req.Header.Add("Authorization", "APPCODE "+h.AppCode)
|
||
req.Header.Add("Content-Type", "application/json")
|
||
|
||
// 发送请求
|
||
client.Timeout = 5 * time.Second
|
||
var resp *http.Response
|
||
resp, err = client.Do(req)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,发送请求失败", ip)
|
||
}
|
||
defer func(Body io.ReadCloser) {
|
||
err = Body.Close()
|
||
if err != nil {
|
||
log.Printf("获取ip:%s信息,关闭响应体失败: %+v\n", ip, err)
|
||
}
|
||
}(resp.Body)
|
||
|
||
// 读取响应体
|
||
var body []byte
|
||
body, err = io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,读取响应体失败", ip)
|
||
}
|
||
|
||
// 解析JSON响应
|
||
var apiResult ApiResult
|
||
err = json.Unmarshal(body, &apiResult)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,解析JSON响应失败,%s", ip, string(body))
|
||
}
|
||
|
||
// 检查API返回状态
|
||
if apiResult.Ret != 200 {
|
||
return &apiResult, errors.New(fmt.Sprintf("获取ip:%s信息失败,%+v", ip, apiResult))
|
||
}
|
||
return &apiResult, nil
|
||
}
|
||
|
||
func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string, ttl time.Duration) (res *ApiResult, err error) {
|
||
getCache, err := h.cache.Get(ctx, h.ipKey(ip))
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取缓存失败,ip:%s", ip)
|
||
}
|
||
if getCache != nil {
|
||
return getCache, nil
|
||
}
|
||
info, err := h.GetIpInfo(ip)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取ip:%s信息失败,", ip)
|
||
}
|
||
|
||
infoJson, err := json.Marshal(info)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "无法将IP信息转换为JSON,ip:%s", ip)
|
||
}
|
||
|
||
err = h.cache.Set(ctx, h.ipKey(ip), string(infoJson), ttl)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "缓存ip:%s信息失败,", ip)
|
||
}
|
||
res = info
|
||
return
|
||
}
|
||
|
||
// ipKey 生成Redis key
|
||
func (h *HuaChenIpClient) ipKey(ip string) string {
|
||
return fmt.Sprintf("ip:%s", ip)
|
||
}
|
||
|
||
type ApiResult struct {
|
||
Ret int `json:"ret"`
|
||
Msg string `json:"msg"`
|
||
Data IpInfo `json:"data"`
|
||
LogId string `json:"log_id"`
|
||
}
|
||
|
||
type IpInfo struct {
|
||
Ip string `json:"ip"`
|
||
LongIp string `json:"long_ip"`
|
||
Isp string `json:"isp"`
|
||
Area string `json:"area"`
|
||
RegionId string `json:"region_id"`
|
||
Region string `json:"region"`
|
||
CityId string `json:"city_id"`
|
||
City string `json:"city"`
|
||
District string `json:"district"`
|
||
DistrictId string `json:"district_id"`
|
||
CountryId string `json:"country_id"`
|
||
Country string `json:"country"`
|
||
Lat string `json:"lat"`
|
||
Lng string `json:"lng"`
|
||
}
|