代码推送

This commit is contained in:
2026-09-09 02:39:57 +08:00
parent a112893947
commit 5e47757c73
24 changed files with 1156 additions and 226 deletions

107
internal/geoip/geoip.go Normal file
View File

@@ -0,0 +1,107 @@
package geoip
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"sync"
"time"
)
// ipLocation 缓存的 IP 归属地信息
type ipLocation struct {
Location string
FetchedAt time.Time
}
// Service IP 归属地查询服务(基于 ip-api.com 免费接口 + 内存缓存)
type Service struct {
cache sync.Map
}
// NewService 创建 IP 归属地查询服务
func NewService() *Service {
return &Service{}
}
// ipApiResponse ip-api.com 返回结构
type ipApiResponse struct {
Status string `json:"status"`
Country string `json:"country"`
RegionName string `json:"regionName"`
City string `json:"city"`
ISP string `json:"isp"`
Query string `json:"query"`
}
// Lookup 查询 IP 归属地,带内存缓存(24小时有效)
func (s *Service) Lookup(ip string) string {
// 本地/内网 IP 直接返回
if ip == "127.0.0.1" || ip == "::1" || ip == "" ||
strings.HasPrefix(ip, "192.168.") ||
strings.HasPrefix(ip, "10.") ||
strings.HasPrefix(ip, "172.") {
return "本地网络"
}
// 检查缓存(24小时有效)
if v, ok := s.cache.Load(ip); ok {
loc := v.(*ipLocation)
if time.Since(loc.FetchedAt) < 24*time.Hour {
return loc.Location
}
s.cache.Delete(ip)
}
// 查询 ip-api.com(免费接口,限制 45 次/分钟)
location := s.queryIPAPI(ip)
if location == "" {
return "未知"
}
// 写入缓存
s.cache.Store(ip, &ipLocation{
Location: location,
FetchedAt: time.Now(),
})
return location
}
// queryIPAPI 调用 ip-api.com 查询
func (s *Service) queryIPAPI(ip string) string {
client := &http.Client{Timeout: 3 * time.Second}
url := fmt.Sprintf("http://ip-api.com/json/%s?lang=zh-CN", ip)
resp, err := client.Get(url)
if err != nil {
return ""
}
defer resp.Body.Close()
var result ipApiResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return ""
}
if result.Status != "success" {
return ""
}
parts := []string{}
if result.Country != "" {
parts = append(parts, result.Country)
}
if result.RegionName != "" {
parts = append(parts, result.RegionName)
}
if result.City != "" {
parts = append(parts, result.City)
}
if result.ISP != "" {
parts = append(parts, result.ISP)
}
return strings.Join(parts, " ")
}