diff --git a/api/callback/callback.go b/api/callback/callback.go new file mode 100644 index 0000000..a81cce6 --- /dev/null +++ b/api/callback/callback.go @@ -0,0 +1,15 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package callback + +import ( + "context" + + "github.com/ayflying/utility_go/api/callback/v1" +) + +type ICallbackV1 interface { + Ip(ctx context.Context, req *v1.IpReq) (res *v1.IpRes, err error) +} diff --git a/api/callback/v1/ip.go b/api/callback/v1/ip.go new file mode 100644 index 0000000..254a8db --- /dev/null +++ b/api/callback/v1/ip.go @@ -0,0 +1,20 @@ +package v1 + +import "github.com/gogf/gf/v2/frame/g" + +type IpReq struct { + g.Meta `path:"/callback/ip/{ip}" tags:"回调响应" method:"get" summary:"获取ip"` + Ip string `json:"ip" dc:"ip"` +} +type IpRes struct { + g.Meta `mime:"application/json" example:"string"` + Address []string `json:"address" dc:"地区名"` +} + +type Ip struct { + Country string `json:"country" dc:"国家"` //国家 + Region string `json:"region" dc:"地区"` //地区 + Province string `json:"province" dc:"省份"` //省份 + City string `json:"city" dc:"城市"` //城市 + District string `json:"district" dc:"区县"` //区县 +} diff --git a/controller/callback/callback.go b/controller/callback/callback.go new file mode 100644 index 0000000..6e1244a --- /dev/null +++ b/controller/callback/callback.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package callback diff --git a/controller/callback/callback_new.go b/controller/callback/callback_new.go new file mode 100644 index 0000000..d66a294 --- /dev/null +++ b/controller/callback/callback_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package callback + +import ( + "github.com/ayflying/utility_go/api/callback" +) + +type ControllerV1 struct{} + +func NewV1() callback.ICallbackV1 { + return &ControllerV1{} +} diff --git a/controller/callback/callback_v1_ip.go b/controller/callback/callback_v1_ip.go new file mode 100644 index 0000000..1655207 --- /dev/null +++ b/controller/callback/callback_v1_ip.go @@ -0,0 +1,14 @@ +package callback + +import ( + "context" + "github.com/ayflying/utility_go/service" + + "github.com/ayflying/utility_go/api/callback/v1" +) + +func (c *ControllerV1) Ip(ctx context.Context, req *v1.IpReq) (res *v1.IpRes, err error) { + res = &v1.IpRes{} + res.Address = service.Ip2Region().GetIp(req.Ip) + return +} diff --git a/go.mod b/go.mod index 6503009..b512184 100644 --- a/go.mod +++ b/go.mod @@ -11,10 +11,12 @@ require ( github.com/go-pay/util v0.0.4 github.com/gogf/gf/contrib/config/apollo/v2 v2.8.3 github.com/gogf/gf/v2 v2.8.3 + github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20241220152942-06eb5c6e8230 github.com/minio/minio-go/v7 v7.0.85 github.com/xuri/excelize/v2 v2.9.0 golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 google.golang.org/api v0.44.0 + google.golang.org/protobuf v1.26.0 ) require ( @@ -77,7 +79,6 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect google.golang.org/grpc v1.38.0 // indirect - google.golang.org/protobuf v1.26.0 // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index b4ad219..9e852e0 100644 --- a/go.sum +++ b/go.sum @@ -241,6 +241,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20241220152942-06eb5c6e8230 h1:B0oaMTAQKDZd8cwYT0qsAI7+c3KbFeBNA8GhgoBMXWw= +github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20241220152942-06eb5c6e8230/go.mod h1:C5LA5UO2ZXJrLaPLYtE1wUJMiyd/nwWaCO5cw/2pSHs= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= diff --git a/hack/config.yaml b/hack/config.yaml index 58f0da2..b5a8f99 100644 --- a/hack/config.yaml +++ b/hack/config.yaml @@ -2,6 +2,8 @@ # https://goframe.org/pages/viewpage.action?pageId=3673173 gfcli: gen: + ctrl: + dstFolder: "controller" service: dstFolder: "service" pb: diff --git a/internal/logic/ip2region/ip2region.go b/internal/logic/ip2region/ip2region.go new file mode 100644 index 0000000..e123336 --- /dev/null +++ b/internal/logic/ip2region/ip2region.go @@ -0,0 +1,104 @@ +package ip2region + +import ( + "github.com/ayflying/utility_go/service" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gfile" + "github.com/lionsoul2014/ip2region/binding/golang/xdb" + "net" + "strings" +) + +var ( + ctx = gctx.New() +) + +type sIp2region struct { + searcher *xdb.Searcher +} + +func New() *sIp2region { + s := &sIp2region{} + s.Load() + return s +} + +func init() { + service.RegisterIp2Region(New()) +} + +// Load 加载到内存中 +// +// @Description: 加载ip2region数据库到内存中。 +// @receiver s *sIp2region: sIp2region的实例。 +func (s *sIp2region) Load() { + var err error + //var dbPath = "/mnt/s3/ip2region.xdb" + var dbPath = "lib/ip2region.xdb" + + if gfile.IsEmpty(dbPath) { + //下载文件 + putData, err2 := g.Client().Discovery(nil). + Get(ctx, "https://resource.luoe.cn/pgk/ip2region.xdb") + if err2 != nil { + return + } + err = gfile.PutBytes(dbPath, putData.ReadAll()) + } + cBuff := gfile.GetBytes(dbPath) + /* + var cBuff []byte + if gres.Contains(dbPath) { + cBuff = gres.GetContent(dbPath) + } else { + cBuff = gfile.GetBytes(dbPath) + } + */ + + // 基于读取的内容,创建查询对象 + s.searcher, err = xdb.NewWithBuffer(cBuff) + if err != nil { + g.Log().Errorf(ctx, "无法创建内容为的搜索器: %s", err) + return + } + +} + +func (s *sIp2region) GetIp(ip string) (res []string) { + res = make([]string, 5) + if s.searcher == nil { + return + } + + //如果是ipv6直接跳过 + if s.isIPv6(ip) { + return + } + + region, err := s.searcher.SearchByStr(ip) + if err != nil { + return + } + res = strings.Split(region, "|") + return +} + +// isIPv6 判断输入字符串是否为IPv6地址 +// +// @Description: 通过解析输入的IP字符串判断其是否为IPv6地址。 +// @receiver s *sIp2region: 代表`sIp2region`类型的实例,本函数中未使用,可忽略。 +// @param ipStr string: 待判断的IP地址字符串。 +// @return bool: 返回true表示是IPv6地址,返回false表示不是IPv6地址。 +func (s *sIp2region) isIPv6(ipStr string) bool { + // 尝试将输入字符串解析为IP地址 + ip := net.ParseIP(ipStr) + // 尝试将IP地址转换为IPv4格式 + ipv4 := ip.To4() + // 如果转换为IPv4格式不为nil,则说明是IPv4地址,返回false + if ipv4 != nil { + return false + } + // 如果无法转换为IPv4格式,则说明是IPv6地址,返回true + return true +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go index 60212c5..0783aa0 100644 --- a/internal/logic/logic.go +++ b/internal/logic/logic.go @@ -6,6 +6,7 @@ package logic import ( _ "github.com/ayflying/utility_go/internal/logic/gameAct" + _ "github.com/ayflying/utility_go/internal/logic/ip2region" _ "github.com/ayflying/utility_go/internal/logic/logData" _ "github.com/ayflying/utility_go/internal/logic/systemCron" _ "github.com/ayflying/utility_go/internal/logic/systemLog" diff --git a/service/ip_2_region.go b/service/ip_2_region.go new file mode 100644 index 0000000..99dc649 --- /dev/null +++ b/service/ip_2_region.go @@ -0,0 +1,32 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +type ( + IIp2Region interface { + // Load 加载到内存中 + // + // @Description: 加载ip2region数据库到内存中。 + // @receiver s *sIp2region: sIp2region的实例。 + Load() + GetIp(ip string) (res []string) + } +) + +var ( + localIp2Region IIp2Region +) + +func Ip2Region() IIp2Region { + if localIp2Region == nil { + panic("implement not found for interface IIp2Region, forgot register?") + } + return localIp2Region +} + +func RegisterIp2Region(i IIp2Region) { + localIp2Region = i +}