github.com/influx6/npkg@v0.8.8/nnet/location.go (about) 1 package nnet 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net" 8 "net/http" 9 10 "github.com/influx6/npkg/nerror" 11 "github.com/influx6/npkg/nunsafe" 12 "xojoc.pw/useragent" 13 ) 14 15 type Agent struct { 16 *useragent.UserAgent 17 Browser string 18 } 19 20 func ParseAgent(agentString string) (*Agent, error) { 21 var agentInfo = useragent.Parse(agentString) 22 if agentInfo == nil { 23 return nil, nerror.New("failed to parse agent") 24 } 25 return &Agent{ 26 Browser: agentInfo.Name, 27 UserAgent: agentInfo, 28 }, nil 29 } 30 31 type Locations []Location 32 33 func (l Locations) Find(ip string) (Location, error) { 34 for _, lt := range l { 35 if lt.IPIsInLocation(ip) { 36 return lt, nil 37 } 38 } 39 return Location{}, nerror.New("not found") 40 } 41 42 type Location struct { 43 Type string `json:"type_"` 44 Street string `json:"street"` 45 ContinentCode string `json:"continent_code"` 46 ContinentName string `json:"continent_name"` 47 City string `json:"city"` 48 State string `json:"state"` 49 Postal string `json:"postal"` 50 Zip string `json:"zip"` 51 Zipcode string `json:"zip_code"` 52 CountryCode string `json:"country_code"` 53 CountryName string `json:"country_name"` 54 RegionCode string `json:"region_code"` 55 RegionName string `json:"region_name"` 56 Timezone string `json:"time_zone"` 57 Latitude float64 `json:"latitude"` 58 Longitude float64 `json:"longitude"` 59 MetroCode string `json:"metro_code"` 60 AreaCode string `json:"area_code"` 61 FromIP string `json:"from_ip"` 62 ToIP string `json:"to_ip"` 63 FromIPNumeric string `json:"from_ip_numeric"` 64 ToIPNumeric string `json:"to_ip_numeric"` 65 } 66 67 func (l Location) IPIsInLocation(ip string) bool { 68 var fromIP = net.ParseIP(l.FromIP) 69 if fromIP == nil { 70 return false 71 } 72 var toIP = net.ParseIP(l.ToIP) 73 if toIP == nil { 74 return false 75 } 76 var targetIP = net.ParseIP(ip) 77 if toIP == nil { 78 return false 79 } 80 return IsTargetBetween(targetIP, fromIP, toIP) 81 } 82 83 type LocationService interface { 84 Get(ip string) (Location, error) 85 } 86 87 // DudLocationService returns a default unknown location with 88 // provided address as ip. 89 type DudLocationService struct{} 90 91 func (f DudLocationService) Get(address string) (Location, error) { 92 var lt Location 93 lt.City = "Unknown" 94 lt.State = "Unknown" 95 lt.CountryName = "Unknown" 96 lt.RegionCode = "Unknown" 97 lt.RegionName = "Unknown" 98 lt.CountryCode = "Unknown" 99 lt.Zipcode = "00000" 100 return lt, nil 101 } 102 103 type CampIPService struct { 104 Addr string 105 } 106 107 func (f CampIPService) Get(address string) (Location, error) { 108 var lt Location 109 110 // Use campip service to get a JSON response 111 var response, err = http.Get(fmt.Sprintf("%s/%s", f.Addr, address)) 112 if err != nil { 113 return lt, nerror.WrapOnly(err) 114 } 115 defer response.Body.Close() 116 117 // response.Body() is a reader type. We have 118 // to use ioutil.ReadAll() to read the data 119 // in to a byte slice(string) 120 var body, berr = ioutil.ReadAll(response.Body) 121 if berr != nil { 122 return lt, nerror.WrapOnly(berr) 123 } 124 125 // Unmarshal the JSON byte slice to a GeoIP struct 126 err = json.Unmarshal(body, <) 127 if err != nil { 128 return lt, nerror.WrapOnly(err).Add("body", nunsafe.Bytes2String(body)) 129 } 130 131 return lt, nil 132 } 133 134 type IPStackService struct { 135 Token string 136 } 137 138 func (f IPStackService) Get(address string) (Location, error) { 139 var lt Location 140 141 // Use freegeoip.net to get a JSON response 142 // There is also /xml/ and /csv/ formats available 143 var response, err = http.Get(fmt.Sprintf("http://api.ipstack.com/%s?access_key=%s", address, f.Token)) 144 if err != nil { 145 return lt, nerror.WrapOnly(err) 146 } 147 defer response.Body.Close() 148 149 // response.Body() is a reader type. We have 150 // to use ioutil.ReadAll() to read the data 151 // in to a byte slice(string) 152 var body, berr = ioutil.ReadAll(response.Body) 153 if berr != nil { 154 return lt, nerror.WrapOnly(berr) 155 } 156 157 // Unmarshal the JSON byte slice to a GeoIP struct 158 err = json.Unmarshal(body, <) 159 if err != nil { 160 return lt, nerror.WrapOnly(err).Add("body", nunsafe.Bytes2String(body)) 161 } 162 163 return lt, nil 164 }