mirror of
https://github.com/TeaOSLab/EdgeCommon.git
synced 2025-11-03 04:10:25 +08:00
198 lines
4.0 KiB
Go
198 lines
4.0 KiB
Go
// Copyright 2022 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
|
|
|
package iplibrary
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"errors"
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
|
"io"
|
|
"math/big"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type WriterV1 struct {
|
|
writer *hashWriter
|
|
meta *Meta
|
|
|
|
lastIPFrom uint64 // 上一次的IP
|
|
lastCountryId int64
|
|
lastProvinceId int64
|
|
lastCityId int64
|
|
lastTownId int64
|
|
lastProviderId int64
|
|
}
|
|
|
|
func NewWriterV1(writer io.Writer, meta *Meta) *WriterV1 {
|
|
if meta == nil {
|
|
meta = &Meta{}
|
|
}
|
|
meta.Version = Version2
|
|
meta.CreatedAt = time.Now().Unix()
|
|
|
|
var libWriter = &WriterV1{
|
|
writer: newHashWriter(writer),
|
|
meta: meta,
|
|
}
|
|
return libWriter
|
|
}
|
|
|
|
func (this *WriterV1) WriteMeta() error {
|
|
metaJSON, err := json.Marshal(this.meta)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = this.writer.Write(metaJSON)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = this.writer.Write([]byte("\n"))
|
|
return err
|
|
}
|
|
|
|
func (this *WriterV1) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
|
|
// validate IP
|
|
var fromIP = net.ParseIP(ipFrom)
|
|
if fromIP == nil {
|
|
return errors.New("invalid 'ipFrom': '" + ipFrom + "'")
|
|
}
|
|
var fromIsIPv4 = configutils.IsIPv4(fromIP)
|
|
var toIP = net.ParseIP(ipTo)
|
|
if toIP == nil {
|
|
return errors.New("invalid 'ipTo': " + ipTo)
|
|
}
|
|
var toIsIPv4 = configutils.IsIPv4(toIP)
|
|
if fromIsIPv4 != toIsIPv4 {
|
|
return errors.New("'ipFrom(" + ipFrom + ")' and 'ipTo(" + ipTo + ")' should have the same IP version")
|
|
}
|
|
|
|
var pieces = []string{}
|
|
|
|
// 0
|
|
if fromIsIPv4 {
|
|
pieces = append(pieces, "")
|
|
} else {
|
|
pieces = append(pieces, "6")
|
|
|
|
// we do NOT support v6 yet
|
|
return nil
|
|
}
|
|
|
|
// 1
|
|
var fromIPLong = this.ip2long(fromIP)
|
|
var toIPLong = this.ip2long(toIP)
|
|
|
|
if toIPLong < fromIPLong {
|
|
fromIPLong, toIPLong = toIPLong, fromIPLong
|
|
}
|
|
|
|
if this.lastIPFrom > 0 && fromIPLong > this.lastIPFrom {
|
|
pieces = append(pieces, "+"+this.formatUint64(fromIPLong-this.lastIPFrom))
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(fromIPLong))
|
|
}
|
|
this.lastIPFrom = fromIPLong
|
|
if ipFrom == ipTo {
|
|
// 2
|
|
pieces = append(pieces, "")
|
|
} else {
|
|
// 2
|
|
pieces = append(pieces, this.formatUint64(toIPLong-fromIPLong))
|
|
}
|
|
|
|
// 3
|
|
if countryId > 0 {
|
|
if countryId == this.lastCountryId {
|
|
pieces = append(pieces, "+")
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(uint64(countryId)))
|
|
}
|
|
} else {
|
|
pieces = append(pieces, "")
|
|
}
|
|
this.lastCountryId = countryId
|
|
|
|
// 4
|
|
if provinceId > 0 {
|
|
if provinceId == this.lastProvinceId {
|
|
pieces = append(pieces, "+")
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(uint64(provinceId)))
|
|
}
|
|
} else {
|
|
pieces = append(pieces, "")
|
|
}
|
|
this.lastProvinceId = provinceId
|
|
|
|
// 5
|
|
if cityId > 0 {
|
|
if cityId == this.lastCityId {
|
|
pieces = append(pieces, "+")
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(uint64(cityId)))
|
|
}
|
|
} else {
|
|
pieces = append(pieces, "")
|
|
}
|
|
this.lastCityId = cityId
|
|
|
|
// 6
|
|
if townId > 0 {
|
|
if townId == this.lastTownId {
|
|
pieces = append(pieces, "+")
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(uint64(townId)))
|
|
}
|
|
} else {
|
|
pieces = append(pieces, "")
|
|
}
|
|
this.lastTownId = townId
|
|
|
|
// 7
|
|
if providerId > 0 {
|
|
if providerId == this.lastProviderId {
|
|
pieces = append(pieces, "+")
|
|
} else {
|
|
pieces = append(pieces, this.formatUint64(uint64(providerId)))
|
|
}
|
|
} else {
|
|
pieces = append(pieces, "")
|
|
}
|
|
this.lastProviderId = providerId
|
|
|
|
_, err := this.writer.Write([]byte(strings.TrimRight(strings.Join(pieces, "|"), "|")))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = this.writer.Write([]byte("\n"))
|
|
return err
|
|
}
|
|
|
|
func (this *WriterV1) Sum() string {
|
|
return this.writer.Sum()
|
|
}
|
|
|
|
func (this *WriterV1) formatUint64(i uint64) string {
|
|
return strconv.FormatUint(i, 32)
|
|
}
|
|
|
|
func (this *WriterV1) ip2long(netIP net.IP) uint64 {
|
|
if len(netIP) == 0 {
|
|
return 0
|
|
}
|
|
|
|
var b4 = netIP.To4()
|
|
if b4 != nil {
|
|
return uint64(binary.BigEndian.Uint32(b4.To4()))
|
|
}
|
|
|
|
var i = big.NewInt(0)
|
|
i.SetBytes(netIP.To16())
|
|
return i.Uint64()
|
|
}
|