diff --git a/go.mod b/go.mod index cee2625..f60349f 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,10 @@ require ( github.com/gosnmp/gosnmp v1.35.0 github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f github.com/matoous/go-nanoid/v2 v2.0.0 - github.com/mojocn/base64Captcha v1.3.5 + github.com/mojocn/base64Captcha v1.3.6 github.com/mssola/user_agent v0.6.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/redis/go-redis/v9 v9.1.0 + github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil/v3 v3.23.7 @@ -27,8 +27,8 @@ require ( golang.org/x/crypto v0.12.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.1 - gorm.io/gorm v1.25.2 + gorm.io/driver/mysql v1.5.2 + gorm.io/gorm v1.25.5 xorm.io/xorm v1.3.2 ) @@ -84,10 +84,10 @@ require ( github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/image v0.5.0 // indirect + golang.org/x/image v0.13.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/text v0.13.0 google.golang.org/protobuf v1.30.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/go.sum b/go.sum index 94d5243..03f74be 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= -github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -428,8 +428,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0= -github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= +github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw= +github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E= github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4= github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -495,8 +495,8 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= -github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= +github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= +github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= @@ -659,10 +659,10 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= +golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -835,8 +835,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1033,11 +1033,11 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= -gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= +gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/src/framework/utils/ip2region/binding.go b/src/framework/utils/ip2region/binding.go deleted file mode 100644 index 4782f67..0000000 --- a/src/framework/utils/ip2region/binding.go +++ /dev/null @@ -1,238 +0,0 @@ -package ip2region - -import ( - "encoding/binary" - "fmt" - "os" -) - -const ( - HeaderInfoLength = 256 - VectorIndexRows = 256 - VectorIndexCols = 256 - VectorIndexSize = 8 - SegmentIndexBlockSize = 14 -) - -// --- Index policy define - -type IndexPolicy int - -const ( - VectorIndexPolicy IndexPolicy = 1 - BTreeIndexPolicy IndexPolicy = 2 -) - -func (i IndexPolicy) String() string { - switch i { - case VectorIndexPolicy: - return "VectorIndex" - case BTreeIndexPolicy: - return "BtreeIndex" - default: - return "unknown" - } -} - -// --- Header define - -type Header struct { - // data []byte - Version uint16 - IndexPolicy IndexPolicy - CreatedAt uint32 - StartIndexPtr uint32 - EndIndexPtr uint32 -} - -func NewHeader(input []byte) (*Header, error) { - if len(input) < 16 { - return nil, fmt.Errorf("invalid input buffer") - } - - return &Header{ - Version: binary.LittleEndian.Uint16(input), - IndexPolicy: IndexPolicy(binary.LittleEndian.Uint16(input[2:])), - CreatedAt: binary.LittleEndian.Uint32(input[4:]), - StartIndexPtr: binary.LittleEndian.Uint32(input[8:]), - EndIndexPtr: binary.LittleEndian.Uint32(input[12:]), - }, nil -} - -// --- searcher implementation - -type Searcher struct { - handle *os.File - - ioCount int - - // use it only when this feature enabled. - // Preload the vector index will reduce the number of IO operations - // thus speedup the search process - vectorIndex []byte - - // content buffer. - // running with the whole xdb file cached - contentBuff []byte -} - -func baseNew(dbFile string, vIndex []byte, cBuff []byte) (*Searcher, error) { - var err error - - // content buff first - if cBuff != nil { - return &Searcher{ - vectorIndex: nil, - contentBuff: cBuff, - }, nil - } - - // open the xdb binary file - handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) - if err != nil { - return nil, err - } - - return &Searcher{ - handle: handle, - vectorIndex: vIndex, - }, nil -} - -func NewWithFileOnly(dbFile string) (*Searcher, error) { - return baseNew(dbFile, nil, nil) -} - -func NewWithVectorIndex(dbFile string, vIndex []byte) (*Searcher, error) { - return baseNew(dbFile, vIndex, nil) -} - -func NewWithBuffer(cBuff []byte) (*Searcher, error) { - return baseNew("", nil, cBuff) -} - -func (s *Searcher) Close() { - if s.handle != nil { - err := s.handle.Close() - if err != nil { - return - } - } -} - -// GetIOCount return the global io count for the last search -func (s *Searcher) GetIOCount() int { - return s.ioCount -} - -// SearchByStr find the region for the specified ip string -func (s *Searcher) SearchByStr(str string) (string, error) { - ip, err := CheckIP(str) - if err != nil { - return "", err - } - - return s.Search(ip) -} - -// Search find the region for the specified long ip -func (s *Searcher) Search(ip uint32) (string, error) { - // reset the global ioCount - s.ioCount = 0 - - // locate the segment index block based on the vector index - var il0 = (ip >> 24) & 0xFF - var il1 = (ip >> 16) & 0xFF - var idx = il0*VectorIndexCols*VectorIndexSize + il1*VectorIndexSize - var sPtr, ePtr = uint32(0), uint32(0) - if s.vectorIndex != nil { - sPtr = binary.LittleEndian.Uint32(s.vectorIndex[idx:]) - ePtr = binary.LittleEndian.Uint32(s.vectorIndex[idx+4:]) - } else if s.contentBuff != nil { - sPtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx:]) - ePtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx+4:]) - } else { - // read the vector index block - var buff = make([]byte, VectorIndexSize) - err := s.read(int64(HeaderInfoLength+idx), buff) - if err != nil { - return "", fmt.Errorf("read vector index block at %d: %w", HeaderInfoLength+idx, err) - } - - sPtr = binary.LittleEndian.Uint32(buff) - ePtr = binary.LittleEndian.Uint32(buff[4:]) - } - - // fmt.Printf("sPtr=%d, ePtr=%d", sPtr, ePtr) - - // binary search the segment index to get the region - var dataLen, dataPtr = 0, uint32(0) - var buff = make([]byte, SegmentIndexBlockSize) - var l, h = 0, int((ePtr - sPtr) / SegmentIndexBlockSize) - for l <= h { - m := (l + h) >> 1 - p := sPtr + uint32(m*SegmentIndexBlockSize) - err := s.read(int64(p), buff) - if err != nil { - return "", fmt.Errorf("read segment index at %d: %w", p, err) - } - - // decode the data step by step to reduce the unnecessary operations - sip := binary.LittleEndian.Uint32(buff) - if ip < sip { - h = m - 1 - } else { - eip := binary.LittleEndian.Uint32(buff[4:]) - if ip > eip { - l = m + 1 - } else { - dataLen = int(binary.LittleEndian.Uint16(buff[8:])) - dataPtr = binary.LittleEndian.Uint32(buff[10:]) - break - } - } - } - - //fmt.Printf("dataLen: %d, dataPtr: %d", dataLen, dataPtr) - if dataLen == 0 { - return "", nil - } - - // load and return the region data - var regionBuff = make([]byte, dataLen) - err := s.read(int64(dataPtr), regionBuff) - if err != nil { - return "", fmt.Errorf("read region at %d: %w", dataPtr, err) - } - - return string(regionBuff), nil -} - -// do the data read operation based on the setting. -// content buffer first or will read from the file. -// this operation will invoke the Seek for file based read. -func (s *Searcher) read(offset int64, buff []byte) error { - if s.contentBuff != nil { - cLen := copy(buff, s.contentBuff[offset:]) - if cLen != len(buff) { - return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) - } - } else { - _, err := s.handle.Seek(offset, 0) - if err != nil { - return fmt.Errorf("seek to %d: %w", offset, err) - } - - s.ioCount++ - rLen, err := s.handle.Read(buff) - if err != nil { - return fmt.Errorf("handle read: %w", err) - } - - if rLen != len(buff) { - return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) - } - } - - return nil -} diff --git a/src/framework/utils/ip2region/ip2region.go b/src/framework/utils/ip2region/ip2region.go index b62890c..8697b3d 100644 --- a/src/framework/utils/ip2region/ip2region.go +++ b/src/framework/utils/ip2region/ip2region.go @@ -1,59 +1,12 @@ package ip2region import ( - "embed" "strings" - "time" - - "ems.agt/src/framework/logger" ) // 网络地址(内网) const LOCAT_HOST = "127.0.0.1" -// 全局查询对象 -var searcher *Searcher - -//go:embed ip2region.xdb -var ip2regionDB embed.FS - -func init() { - // 从 dbPath 加载整个 xdb 到内存 - buf, err := ip2regionDB.ReadFile("ip2region.xdb") - if err != nil { - logger.Fatalf("failed error load xdb from : %s\n", err) - return - } - - // 用全局的 cBuff 创建完全基于内存的查询对象。 - base, err := NewWithBuffer(buf) - if err != nil { - logger.Errorf("failed error create searcher with content: %s\n", err) - return - } - - // 赋值到全局查询对象 - searcher = base -} - -// RegionSearchByIp 查询IP所在地 -// -// 国家|区域|省份|城市|ISP -func RegionSearchByIp(ip string) (string, int, int64) { - ip = ClientIP(ip) - if ip == LOCAT_HOST { - // "0|0|0|内网IP|内网IP" - return "0|0|0|app.common.noIPregion|app.common.noIPregion", 0, 0 - } - tStart := time.Now() - region, err := searcher.SearchByStr(ip) - if err != nil { - logger.Errorf("failed to SearchIP(%s): %s\n", ip, err) - return "0|0|0|0|0", 0, 0 - } - return region, 0, time.Since(tStart).Milliseconds() -} - // RealAddressByIp 地址IP所在地 // // 218.4.167.70 江苏省 苏州市 @@ -62,21 +15,7 @@ func RealAddressByIp(ip string) string { if ip == LOCAT_HOST { return "app.common.noIPregion" // 内网IP } - region, err := searcher.SearchByStr(ip) - if err != nil { - logger.Errorf("failed to SearchIP(%s): %s\n", ip, err) - return "app.common.unknown" // 未知 - } - parts := strings.Split(region, "|") - province := parts[2] - city := parts[3] - if province == "0" && city != "0" { - if city == "内网IP" { - return "app.common.noIPregion" // 内网IP - } - return city - } - return province + " " + city + return "app.common.noIPregion" // 内网IP } // ClientIP 处理客户端IP地址显示iPv4 diff --git a/src/framework/utils/ip2region/ip2region.xdb b/src/framework/utils/ip2region/ip2region.xdb deleted file mode 100644 index c78b792..0000000 Binary files a/src/framework/utils/ip2region/ip2region.xdb and /dev/null differ diff --git a/src/framework/utils/ip2region/util.go b/src/framework/utils/ip2region/util.go deleted file mode 100644 index cfef29e..0000000 --- a/src/framework/utils/ip2region/util.go +++ /dev/null @@ -1,175 +0,0 @@ -package ip2region - -import ( - "fmt" - "os" - "strconv" - "strings" -) - -var shiftIndex = []int{24, 16, 8, 0} - -func CheckIP(ip string) (uint32, error) { - var ps = strings.Split(strings.TrimSpace(ip), ".") - if len(ps) != 4 { - return 0, fmt.Errorf("invalid ip address `%s`", ip) - } - - var val = uint32(0) - for i, s := range ps { - d, err := strconv.Atoi(s) - if err != nil { - return 0, fmt.Errorf("the %dth part `%s` is not an integer", i, s) - } - - if d < 0 || d > 255 { - return 0, fmt.Errorf("the %dth part `%s` should be an integer bettween 0 and 255", i, s) - } - - val |= uint32(d) << shiftIndex[i] - } - - // convert the ip to integer - return val, nil -} - -func Long2IP(ip uint32) string { - return fmt.Sprintf("%d.%d.%d.%d", (ip>>24)&0xFF, (ip>>16)&0xFF, (ip>>8)&0xFF, ip&0xFF) -} - -func MidIP(sip uint32, eip uint32) uint32 { - return uint32((uint64(sip) + uint64(eip)) >> 1) -} - -// LoadHeader load the header info from the specified handle -func LoadHeader(handle *os.File) (*Header, error) { - _, err := handle.Seek(0, 0) - if err != nil { - return nil, fmt.Errorf("seek to the header: %w", err) - } - - var buff = make([]byte, HeaderInfoLength) - rLen, err := handle.Read(buff) - if err != nil { - return nil, err - } - - if rLen != len(buff) { - return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) - } - - return NewHeader(buff) -} - -// LoadHeaderFromFile load header info from the specified db file path -func LoadHeaderFromFile(dbFile string) (*Header, error) { - handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) - if err != nil { - return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) - } - - defer func(handle *os.File) { - _ = handle.Close() - }(handle) - - header, err := LoadHeader(handle) - if err != nil { - return nil, err - } - - return header, nil -} - -// LoadHeaderFromBuff wrap the header info from the content buffer -func LoadHeaderFromBuff(cBuff []byte) (*Header, error) { - return NewHeader(cBuff[0:256]) -} - -// LoadVectorIndex util function to load the vector index from the specified file handle -func LoadVectorIndex(handle *os.File) ([]byte, error) { - // load all the vector index block - _, err := handle.Seek(HeaderInfoLength, 0) - if err != nil { - return nil, fmt.Errorf("seek to vector index: %w", err) - } - - var buff = make([]byte, VectorIndexRows*VectorIndexCols*VectorIndexSize) - rLen, err := handle.Read(buff) - if err != nil { - return nil, err - } - - if rLen != len(buff) { - return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) - } - - return buff, nil -} - -// LoadVectorIndexFromFile load vector index from a specified file path -func LoadVectorIndexFromFile(dbFile string) ([]byte, error) { - handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) - if err != nil { - return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) - } - - defer func() { - _ = handle.Close() - }() - - vIndex, err := LoadVectorIndex(handle) - if err != nil { - return nil, err - } - - return vIndex, nil -} - -// LoadContent load the whole xdb content from the specified file handle -func LoadContent(handle *os.File) ([]byte, error) { - // get file size - fi, err := handle.Stat() - if err != nil { - return nil, fmt.Errorf("stat: %w", err) - } - - size := fi.Size() - - // seek to the head of the file - _, err = handle.Seek(0, 0) - if err != nil { - return nil, fmt.Errorf("seek to get xdb file length: %w", err) - } - - var buff = make([]byte, size) - rLen, err := handle.Read(buff) - if err != nil { - return nil, err - } - - if rLen != len(buff) { - return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) - } - - return buff, nil -} - -// LoadContentFromFile load the whole xdb content from the specified db file path -func LoadContentFromFile(dbFile string) ([]byte, error) { - handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) - if err != nil { - return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) - } - - defer func() { - _ = handle.Close() - }() - - cBuff, err := LoadContent(handle) - if err != nil { - return nil, err - } - - return cBuff, nil -} -