From 0700293bfc16a6e4d939413b00fbcae28bd27a7d Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Mon, 28 Sep 2015 18:59:16 +0200 Subject: [PATCH] Lua function may disable REC file storage closes #27 --- README.md | 13 ++++++++++--- hooks.c | 34 ++++++++++++++++++++++++++++++++++ hooks.h | 1 + ot-recorder.c | 29 ++++++++++++++++++----------- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d0dc11d..5d260d2 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ Unless already provided by the package you installed, we recommend you create a The _recorder_ has, like _ocat_, a daunting number of options, most of which you will not require. Running either utility with the `-h` or `--help` switch will summarize their meanings. You can, for example launch with a specific storage directory, disable the HTTP server, change its port, etc. -If you require authentication or TLS to connect to your MQTT broker, pay attention to the `$OTR_` environment variables listed in the help. +If you require authentication or TLS to connect to your MQTT broker, pay attention to the `$OTR_` environment variables listed in the help. Launch the recorder: @@ -249,7 +249,7 @@ $ ./ot-recorder 'owntracks/#' Publish a location from your OwnTracks app and you should see the _recorder_ receive that on the console. If you haven't disabled Geo-lookups, you'll also see the address from which the publish originated. -The location message received by the _recorder_ will be written to storage. +The location message received by the _recorder_ will be written to storage. ### Launching `ot-recorder` for _Hosted mode_ @@ -321,7 +321,7 @@ We recommend you keep reverse-geo lookups enabled, this data (country code `cc`, ## Monitoring -In order to monitor the _recorder_, whenever an MQTT message is received, a `monitor` file located relative to STORAGEDEFAULT is maintained. It contains a single line of text: the epoch timestamp and the last received topic separated from each other by a space. +In order to monitor the _recorder_, whenever an MQTT message is received, a `monitor` file located relative to STORAGEDEFAULT is maintained. It contains a single line of text: the epoch timestamp and the last received topic separated from each other by a space. ``` 1439738692 owntracks/jjolie/ipad @@ -500,6 +500,13 @@ written by OwnTracks Recorder version 0.3.0 It is 14:10:01 in the year 2015 owntracks/jane/phone lat=48.858339 Avenue Anatole France, 75007 Paris, France ``` +### `putrec` + +An optional function you provide is called `putrec(u, d, s)`. If it exists, +it is called with the current user in `u`, the device in `d` and the payload +(which is possibly not JSON) in the string `s`. If your function returns a +non-zero value, the _recorder_ will *not* write the REC file for this publish. + ### Hooklets After running `otr_hook()`, the _recorder_ attempts to invoke a Lua function for each of the elements in the extended JSON. If, say, your Lua script contains a function called `hooklet_lat`, it will be invoked every time a `lat` is received as part of the JSON payload. Similarly with `hooklet_addr`, `hooklet_cc`, `hooklet_tst`, etc. These _hooklets_ are invoked with the same parameters as `otr_hook()`. diff --git a/hooks.c b/hooks.c index d3f64c9..93f00e1 100644 --- a/hooks.c +++ b/hooks.c @@ -185,6 +185,40 @@ static void hooks_hooklet(struct udata *ud, char *topic, JsonNode *fullo) } } +/* + * Invoked from putrec() in storage. If the Lua putrec function is available + * and it returns non-zero, do not putrec. + */ + +int hooks_norec(struct udata *ud, char *user, char *device, char *payload) +{ + struct luadata *ld = ud->luadata; + int rc; + + if (ld == NULL) + return (0); + + lua_settop(ld->L, 0); + lua_getglobal(ld->L, "putrec"); + if (lua_type(ld->L, -1) != LUA_TFUNCTION) { + return (0); + } + + lua_pushstring(ld->L, user); + lua_pushstring(ld->L, device); + lua_pushstring(ld->L, payload); + + /* Invoke `hook' function in Lua with our args */ + if (lua_pcall(ld->L, 3, 1, 0)) { + olog(LOG_ERR, "Failed to run putrec in Lua: %s", lua_tostring(ld->L, -1)); + exit(1); + } + + rc = (int)lua_tonumber(ld->L, -1); + printf("C: hooks_norec returns %d\n", rc); + return (rc); +} + void hooks_hook(struct udata *ud, char *topic, JsonNode *fullo) { do_hook("otr_hook", ud, topic, fullo); diff --git a/hooks.h b/hooks.h index 3416ef7..c14c676 100644 --- a/hooks.h +++ b/hooks.h @@ -13,6 +13,7 @@ struct luadata { struct luadata *hooks_init(struct udata *ud, char *luascript); void hooks_exit(struct luadata *, char *reason); void hooks_hook(struct udata *ud, char *topic, JsonNode *obj); +int hooks_norec(struct udata *ud, char *user, char *device, char *payload); #endif /* WITH_LUA */ diff --git a/ot-recorder.c b/ot-recorder.c index 15249e5..fb35ca3 100644 --- a/ot-recorder.c +++ b/ot-recorder.c @@ -260,18 +260,25 @@ JsonNode *csv_to_json(char *payload) #define RECFORMAT "%s\t%-18s\t%s\n" -static void putrec(time_t now, UT_string *reltopic, UT_string *username, UT_string *device, char *string) +/* + * Store payload in REC file unless our Lua putrec() function says + * we shouldn't for this particular user/device combo. + */ + +static void putrec(struct udata *ud, time_t now, UT_string *reltopic, UT_string *username, UT_string *device, char *string) { FILE *fp; - if ((fp = pathn("a", "rec", username, device, "rec")) == NULL) { - olog(LOG_ERR, "Cannot write REC for %s/%s: %m", - UB(username), UB(device)); - } + if (hooks_norec(ud, UB(username), UB(device), string) == 0) { + if ((fp = pathn("a", "rec", username, device, "rec")) == NULL) { + olog(LOG_ERR, "Cannot write REC for %s/%s: %m", + UB(username), UB(device)); + } - fprintf(fp, RECFORMAT, isotime(now), + fprintf(fp, RECFORMAT, isotime(now), UB(reltopic), string); - fclose(fp); + fclose(fp); + } } void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *m) @@ -379,7 +386,7 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m if ((json = json_decode(m->payload)) == NULL) { if ((json = csv_to_json(m->payload)) == NULL) { /* It's not JSON or it's not a location CSV; store it */ - putrec(now, reltopic, username, device, bindump(m->payload, m->payloadlen)); + putrec(ud, now, reltopic, username, device, bindump(m->payload, m->payloadlen)); return; } } @@ -420,14 +427,14 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m case T_LWT: case T_STEPS: case T_WAYPOINTS: - putrec(now, reltopic, username, device, bindump(m->payload, m->payloadlen)); + putrec(ud, now, reltopic, username, device, bindump(m->payload, m->payloadlen)); goto cleanup; case T_WAYPOINT: case T_TRANSITION: case T_LOCATION: break; default: - putrec(now, reltopic, username, device, bindump(m->payload, m->payloadlen)); + putrec(ud, now, reltopic, username, device, bindump(m->payload, m->payloadlen)); goto cleanup; } @@ -542,7 +549,7 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m if (!pingping) { if ((jsonstring = json_stringify(json, NULL)) != NULL) { - putrec(now, reltopic, username, device, jsonstring); + putrec(ud, now, reltopic, username, device, jsonstring); free(jsonstring); } }