diff --git a/go.mod b/go.mod index bd7ab8d..08844ca 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 + github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 go.etcd.io/bbolt v1.3.5 golang.org/x/image v0.0.0-20200801110659-972c09e46d76 golang.org/x/sys v0.0.0-20200819035508-9a32b3aa38f5 // indirect diff --git a/go.sum b/go.sum index dd9a90c..f088a16 100644 --- a/go.sum +++ b/go.sum @@ -212,6 +212,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 h1:UFHFmFfixpmfRBcxuu+LA9l8MdURWVdVNUHxO5n1d2w= +github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26/go.mod h1:IGhd0qMDsUa9acVjsbsT7bu3ktadtGOHI79+idTew/M= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/web/helpers.go b/web/helpers.go index 169379c..5a0f97c 100644 --- a/web/helpers.go +++ b/web/helpers.go @@ -5,11 +5,12 @@ import ( "encoding/json" "fmt" "io/ioutil" - "math" "net/http" "strconv" "strings" + "github.com/umahmood/haversine" + "github.com/librespeed/speedtest/config" "github.com/librespeed/speedtest/results" @@ -17,7 +18,7 @@ import ( ) var ( - serverLat, serverLng float64 + serverCoord haversine.Coord ) func getRandomData(length int) []byte { @@ -67,95 +68,89 @@ func getIPInfo(addr string) results.IPInfoResponse { return ret } -func SetServerLocation(conf *config.Config) (float64, float64) { +func SetServerLocation(conf *config.Config) { if conf.ServerLat > 0 && conf.ServerLng > 0 { log.Infof("Configured server coordinates: %.6f, %.6f", conf.ServerLat, conf.ServerLng) - return conf.ServerLat, conf.ServerLng + serverCoord.Lat = conf.ServerLat + serverCoord.Lon = conf.ServerLng + return } var ret results.IPInfoResponse resp, err := http.DefaultClient.Get(getIPInfoURL("")) if err != nil { log.Errorf("Error getting repsonse from ipinfo.io: %s", err) - return 0, 0 + return } raw, err := ioutil.ReadAll(resp.Body) if err != nil { log.Errorf("Error reading response from ipinfo.io: %s", err) - return 0, 0 + return } defer resp.Body.Close() if err := json.Unmarshal(raw, &ret); err != nil { log.Errorf("Error parsing response from ipinfo.io: %s", err) - return 0, 0 + return } - var lat, lng float64 if ret.Location != "" { - lat, lng = parseLocationString(ret.Location) + serverCoord, err = parseLocationString(ret.Location) + if err != nil { + log.Errorf("Cannot get server coordinates: %s", err) + return + } } - log.Infof("Fetched server coordinates: %.6f, %.6f", lat, lng) - - return lat, lng + log.Infof("Fetched server coordinates: %.6f, %.6f", serverCoord.Lat, serverCoord.Lon) } -func parseLocationString(location string) (float64, float64) { +func parseLocationString(location string) (haversine.Coord, error) { + var coord haversine.Coord + parts := strings.Split(location, ",") if len(parts) != 2 { - log.Errorf("Unknown location format: %s", location) - return 0, 0 + err := fmt.Errorf("unknown location format: %s", location) + log.Error(err) + return coord, err } lat, err := strconv.ParseFloat(parts[0], 64) if err != nil { log.Errorf("Error parsing latitude: %s", parts[0]) - return 0, 0 + return coord, err } lng, err := strconv.ParseFloat(parts[1], 64) if err != nil { log.Errorf("Error parsing longitude: %s", parts[0]) - return 0, 0 + return coord, err } - return lat, lng + coord.Lat = lat + coord.Lon = lng + + return coord, nil } func calculateDistance(clientLocation string, unit string) string { - clientLat, clientLng := parseLocationString(clientLocation) - - radlat1 := float64(math.Pi * serverLat / 180) - radlat2 := float64(math.Pi * clientLat / 180) - - theta := float64(serverLng - clientLng) - radtheta := float64(math.Pi * theta / 180) - - dist := math.Sin(radlat1)*math.Sin(radlat2) + math.Cos(radlat1)*math.Cos(radlat2)*math.Cos(radtheta) - - if dist > 1 { - dist = 1 + clientCoord, err := parseLocationString(clientLocation) + if err != nil { + log.Errorf("Error parsing client coordinates: %s", err) + return "" } - dist = math.Acos(dist) - dist = dist * 180 / math.Pi - dist = dist * 60 * 1.1515 - + dist, km := haversine.Distance(clientCoord, serverCoord) unitString := " mi" + switch unit { case "km": - dist = dist * 1.609344 + dist = km unitString = " km" case "NM": - dist = dist * 0.8684 + dist = km * 0.539957 unitString = " NM" } - return fmt.Sprintf("%d%s", round(dist), unitString) -} - -func round(v float64) int { - r := int(math.Round(v)) - return 10 * ((r + 9) / 10) + return fmt.Sprintf("%.2f%s", dist, unitString) }