From 91ab81759fc5f6a5424bcefa71a1d51a70749fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20H=C3=A5rek=20Andreassen?= Date: Sun, 29 Sep 2024 21:20:46 +0200 Subject: [PATCH] feat: Add reverse nominatim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim HĂ„rek Andreassen --- internal/nominatim/nominatim.go | 74 ++++++++++++++++++++++++++++ internal/nominatim/nominatim_test.go | 18 +++++++ internal/nominatim/types.go | 1 + 3 files changed, 93 insertions(+) diff --git a/internal/nominatim/nominatim.go b/internal/nominatim/nominatim.go index 618420a..a5fc7e7 100644 --- a/internal/nominatim/nominatim.go +++ b/internal/nominatim/nominatim.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "reflect" "strconv" ) @@ -54,7 +55,44 @@ func (n *Nominatim) Search(q string) (*SearchResults, error) { } return &result, nil +} +func (n *Nominatim) Reverse(lat, lon float64) (*ReverseResult, error) { + url := fmt.Sprintf("https://nominatim.openstreetmap.org/reverse?lat=%.16f&lon=%.16f&format=jsonv2", lat, lon) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + req.Header.Set("User-Agent", n.siteName) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s", resp.Status) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := ReverseResult{} + err = json.Unmarshal(body, &result) + if err != nil { + return nil, err + } + + if allFieldsNil(result) { + return nil, fmt.Errorf("No result") + } + + return &result, nil } type LookupResult struct { @@ -92,3 +130,39 @@ func (n *Nominatim) Lookup(q string) (*LookupResult, error) { }, }, nil } + +func (n *Nominatim) ReverseLookup(lat, lon float64) (*LookupResult, error) { + r, err := n.Reverse(lat, lon) + + if err != nil { + return nil, err + } + + return &LookupResult{ + Location: *r.Name, + Coordinates: Coordinates{ + Latitude: lat, + Longitude: lon, + }, + }, nil +} + +func allFieldsNil(s interface{}) bool { + v := reflect.ValueOf(s) + + // Check if the passed value is a struct + if v.Kind() != reflect.Struct { + return false + } + + // Iterate through all fields in the struct + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + + // Check if the field is a pointer and is nil + if field.Kind() == reflect.Ptr && !field.IsNil() { + return false + } + } + return true +} diff --git a/internal/nominatim/nominatim_test.go b/internal/nominatim/nominatim_test.go index 441c7e3..c7e69d6 100644 --- a/internal/nominatim/nominatim_test.go +++ b/internal/nominatim/nominatim_test.go @@ -55,3 +55,21 @@ func TestLookup(t *testing.T) { _, err = c.Lookup("") assert.Error(err) } + +func TestReverse(t *testing.T) { + assert := assert.New(t) + c, err := New("my siteName") + assert.NoError(err) + + r, err := c.Reverse(60.3943055, 5.3259192) + assert.NoError(err) + + assert.NotEmpty(r) + + assert.Equal("5.325973", *r.Longitude) + assert.Equal("60.394487", *r.Latitude) + assert.Equal("", *r.Name) + + _, err = c.Reverse(-10000, -10000) + assert.Error(err) +} diff --git a/internal/nominatim/types.go b/internal/nominatim/types.go index d12be7f..ea1427e 100644 --- a/internal/nominatim/types.go +++ b/internal/nominatim/types.go @@ -32,6 +32,7 @@ type SearchResult struct { } type SearchResults = []SearchResult +type ReverseResult = SearchResult type Coordinates struct { Latitude float64 `json:"latitude"`