From 4fc1a083edd0e68f2d476bad5b842152691b0ef9 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Fri, 14 Jun 2024 21:22:45 +0100 Subject: [PATCH] issue #313: handle out-of-order location notification When receiving a location update check that it is newer than the last update from the same device before updating the 'last' record. This ensures the 'last' record is always the most recent update from the device in the event updates arrive out of order. --- recorder.c | 62 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/recorder.c b/recorder.c index ea889ce..78aa7ab 100644 --- a/recorder.c +++ b/recorder.c @@ -765,6 +765,32 @@ unsigned char *decrypt(struct udata *ud, char *topic, char *p64, char *username, } #endif /* ENCRYPT */ +static bool is_newer_than_last(JsonNode *json) +{ + bool is_newer = true; + JsonNode *last_array; + JsonNode *fields = json_mkarray(); + json_append_element(fields, json_mkstring("tst")); + JsonNode *usernode = json_find_member(json, "username"); + JsonNode *devicenode = json_find_member(json, "device"); + if (usernode != NULL && devicenode != NULL) { + if ((last_array = last_users(usernode->string_, devicenode->string_, fields)) != NULL) { + JsonNode *lastrec = json_first_child(last_array); + if (lastrec != NULL) { + JsonNode *tst = json_find_member(lastrec, "tst"); + if (tst != NULL) { + double last = number(lastrec, "tst"); + double current = number(json, "tst"); + is_newer = last < current; + } + } + json_delete(last_array); + } + } + json_delete(fields); + return is_newer; +} + /* * if `jnode' will be set to a JsonNode object with results added to the * outgoing HTTP payload; the caller (in http.c) will delete the object @@ -1315,32 +1341,38 @@ void handle_message(void *userdata, char *topic, char *payload, size_t payloadle json_append_member(json, "ghash", json_mkstring(UB(ghash))); if (_type == T_LOCATION || _type == T_WAYPOINT) { - char *component; + char *component = NULL; utstring_renew(filename); if (_type == T_LOCATION) { + if (is_newer_than_last(json)) { component = "last"; utstring_printf(filename, "%s-%s.json", UB(username), UB(device)); + } else { + olog(LOG_DEBUG, "Location out-of-order, skipping 'last' update"); + } } else if (_type == T_WAYPOINT) { - component = "waypoints"; - utstring_printf(filename, "%s.json", isotime(tst)); + component = "waypoints"; + utstring_printf(filename, "%s.json", isotime(tst)); } - if ((jsonstring = json_stringify(json, NULL)) != NULL) { - utstring_printf(ts, "%s/%s/%s/%s", - STORAGEDIR, - component, - UB(username), - UB(device)); - if (mkpath(UB(ts)) < 0) { - olog(LOG_ERR, "Cannot mkdir %s: %m", UB(ts)); - } + if (component != NULL) { + if ((jsonstring = json_stringify(json, NULL)) != NULL) { + utstring_printf(ts, "%s/%s/%s/%s", + STORAGEDIR, + component, + UB(username), + UB(device)); + if (mkpath(UB(ts)) < 0) { + olog(LOG_ERR, "Cannot mkdir %s: %m", UB(ts)); + } - utstring_printf(ts, "/%s", UB(filename)); - safewrite(UB(ts), jsonstring); - free(jsonstring); + utstring_printf(ts, "/%s", UB(filename)); + safewrite(UB(ts), jsonstring); + free(jsonstring); + } } }