/
geoip.go
92 lines (73 loc) · 1.96 KB
/
geoip.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package api
import (
"context"
"fmt"
"github.com/gnasnik/titan-explorer/core/geo"
"math"
"strconv"
"github.com/golang/geo/s2"
)
type IPCoordinate interface {
GetLatLng(ctx context.Context, ip string) (float64, float64, error)
}
type ipCoordinate struct {
// *geoip2.Reader
}
func NewIPCoordinate() IPCoordinate {
return &ipCoordinate{}
}
func (coordinate *ipCoordinate) GetLatLng(ctx context.Context, ip string) (float64, float64, error) {
//var loc model.Location
//err := statistics.GetIpLocation(ctx, ip, &loc)
//if err != nil {
// return 0, 0, err
//}
loc, err := geo.GetIpLocation(ctx, ip)
if err != nil {
return 0, 0, err
}
longitude, err := strconv.ParseFloat(loc.Longitude, 64)
if err != nil {
return 0, 0, err
}
latitude, err := strconv.ParseFloat(loc.Latitude, 64)
if err != nil {
return 0, 0, err
}
return latitude, longitude, nil
}
func calculateDistance(lat1, lon1, lat2, lon2 float64) float64 {
p1 := s2.PointFromLatLng(s2.LatLngFromDegrees(lat1, lon1))
p2 := s2.PointFromLatLng(s2.LatLngFromDegrees(lat2, lon2))
distance := s2.ChordAngleBetweenPoints(p1, p2).Angle().Radians()
distanceKm := distance * 6371.0
return distanceKm
}
func GetUserNearestIP(ctx context.Context, userIP string, ipList []string, coordinate IPCoordinate) (string, error) {
lat1, lon1, err := coordinate.GetLatLng(ctx, userIP)
if err != nil {
return "", err
}
ipDistanceMap := make(map[string]float64)
for _, ip := range ipList {
lat2, lon2, err := coordinate.GetLatLng(ctx, ip)
if err != nil {
log.Errorf("get %s latLng error %s", ip, err.Error())
continue
}
distance := calculateDistance(lat1, lon1, lat2, lon2)
ipDistanceMap[ip] = distance
}
if len(ipDistanceMap) == 0 {
return "", fmt.Errorf("can not get any ip distance")
}
var nearestIP string
minDistance := math.MaxFloat64
for ip, distance := range ipDistanceMap {
if distance < minDistance {
minDistance = distance
nearestIP = ip
}
}
return nearestIP, nil
}