From 704af819968157b8a63f10fe751df629024da0ec Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Tue, 23 Oct 2018 14:09:32 +0200 Subject: [PATCH] NEW: add support for revgeod closes #263 --- README.md | 4 +++- geo.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8bb0b09..e170a0d 100644 --- a/README.md +++ b/README.md @@ -269,10 +269,11 @@ This section lists the most important options of the Recorder with their long na `--precision` overrides the compiled-in default. (See "Precision" later.) -`--geokey` sets the API key for reverse geo lookups. We support Google (legacy) and OpenCage which we recommend [OpenCage](doc/OPENCAGE.md). You will require an API key for both. For backwards-compatibility the API key for Google is used "as is", whereas you prefix the OpenCage API key with the string `"opencage:"`: +`--geokey` sets the API key for reverse geo lookups. We support Google (legacy) and OpenCage which we recommend [OpenCage](doc/OPENCAGE.md). We also support [revgeod]. You will require an API key for the first two. For backwards-compatibility the API key for Google is used "as is", whereas you prefix the OpenCage API key with the string `"opencage:"`: ``` --geokey "opencage:xxxxxxxxxxxxxxxxxxxxxx" # for OpenCage --geokey "xxxxxxxxxxxxxxxxxxxxxx" # for Google +--geokey "revgeod:localhost:8865" # for Revgeod (host:port) ``` (The rules of the game for using Google as reverse geocoder changed in May 2018; make sure to check Google's Map Project documentation before using this) @@ -969,3 +970,4 @@ It actually is possible to gateway location publishes arriving via HTTP into MQT If a payload is received with an element called `_geoprec` it contains an override for the Recorder's configured reverse-geo precision. So, for example, if Recorder is running with precision 7, say, and the received payload contains `"_geoprec" : 2` the 2 will be used for this particular publish. This is not used in the OwnTracks apps, but it can be used with payloads you generate otherwise. If `_geoprec` is negative, new reverse geo lookups will not be performed, but cached entries of `abs(_geoprec)` will be used. + [revgeod]: https://github.com/jpmens/revgeod diff --git a/geo.c b/geo.c index 0b8c73d..140a4e8 100644 --- a/geo.c +++ b/geo.c @@ -29,13 +29,16 @@ typedef enum { GOOGLE, - OPENCAGE + OPENCAGE, + REVGEOD } geocoder; #define GOOGLE_URL "https://maps.googleapis.com/maps/api/geocode/json?latlng=%lf,%lf&sensor=false&language=EN&key=%s" #define OPENCAGE_URL "https://api.opencagedata.com/geocode/v1/json?q=%lf+%lf&key=%s&abbrv=1&no_record=1&limit=1&format=json" +#define REVGEOD_URL "http://%s/rev?lat=%lf&lon=%lf" /* "host:port", lat, lon */ + static CURL *curl; static size_t writemem(void *contents, size_t size, size_t nmemb, void *userp) @@ -139,6 +142,43 @@ static int goog_decode(UT_string *geodata, UT_string *addr, UT_string *cc, UT_st return (1); } +static int revgeod_decode(UT_string *geodata, UT_string *addr, UT_string *cc, UT_string *locality) +{ + JsonNode *json, *village, *j, *a; + + /* + * We are parsing this data returned from revgeod(1): + * + * {"address":{"village":"La Terre Noire, 77510 Sablonnières, France","locality":"Sablonnières","cc":"FR","s":"lmdb"}} + * + */ + + if ((json = json_decode(UB(geodata))) == NULL) { + return (0); + } + + if ((a = json_find_member(json, "address")) != NULL) { + if ((village = json_find_member(a, "village")) != NULL) { + if (village->tag == JSON_STRING) { + utstring_printf(addr, "%s", village->string_); + } + } + if ((j = json_find_member(a, "locality")) != NULL) { + if (j->tag == JSON_STRING) { + utstring_printf(locality, "%s", j->string_); + } + } + if ((j = json_find_member(a, "cc")) != NULL) { + if (j->tag == JSON_STRING) { + utstring_printf(cc, "%s", j->string_); + } + } + } + + json_delete(json); + return (1); +} + static int opencage_decode(UT_string *geodata, UT_string *addr, UT_string *cc, UT_string *locality) { JsonNode *json, *results, *address, *ac, *zeroth; @@ -267,12 +307,16 @@ JsonNode *revgeo(struct udata *ud, double lat, double lon, UT_string *addr, UT_s if (strncmp(ud->geokey, "opencage:", strlen("opencage:")) == 0) { utstring_printf(url, OPENCAGE_URL, lat, lon, ud->geokey + strlen("opencage:")); geocoder = OPENCAGE; + } else if (strncmp(ud->geokey, "revgeod:", strlen("revgeod:")) == 0) { + /* revgeod:localhost:8865 */ + utstring_printf(url, REVGEOD_URL, ud->geokey + strlen("revgeod:"), lat, lon); + geocoder = REVGEOD; } else { utstring_printf(url, GOOGLE_URL, lat, lon, ud->geokey); geocoder = GOOGLE; } - // printf("--------------- %s\n", UB(url)); + // fprintf(stderr, "--------------- %s\n", UB(url)); curl_easy_setopt(curl, CURLOPT_URL, UB(url)); curl_easy_setopt(curl, CURLOPT_USERAGENT, "OwnTracks-Recorder/1.0"); @@ -302,6 +346,9 @@ JsonNode *revgeo(struct udata *ud, double lat, double lon, UT_string *addr, UT_s case OPENCAGE: rc = opencage_decode(cbuf, addr, cc, locality); break; + case REVGEOD: + rc = revgeod_decode(cbuf, addr, cc, locality); + break; } if (!rc) {