From 6dd03bb0e6a5cc68e6e39c84d464991ce9960254 Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Sat, 19 Sep 2015 16:11:53 +0200 Subject: [PATCH] New feature: Lua hooks --- Makefile | 10 +- README.md | 68 ++++++++++++++ assets/ot-recorder.png | Bin 41312 -> 42239 bytes config.mk.in | 6 ++ etc/example.lua | 13 +++ hooks.c | 201 +++++++++++++++++++++++++++++++++++++++++ hooks.h | 19 ++++ ocat.c | 3 + ot-recorder.c | 117 ++++++++++++++++-------- udata.h | 3 + 10 files changed, 401 insertions(+), 39 deletions(-) create mode 100644 etc/example.lua create mode 100644 hooks.c create mode 100644 hooks.h diff --git a/Makefile b/Makefile index 9a05849..280ebac 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,13 @@ CFLAGS += -DGHASHPREC=$(GHASHPREC) ifeq ($(HAVE_PING),yes) CFLAGS += -DHAVE_PING=1 endif + +ifeq ($(WITH_LUA),yes) + CFLAGS += -DWITH_LUA=1 $(LUA_CFLAGS) + LIBS += $(LUA_LIBS) + OTR_OBJS += hooks.o +endif + ifeq ($(HAVE_KILL),yes) CFLAGS += -DHAVE_KILL=1 endif @@ -60,7 +67,7 @@ ocat: ocat.o $(OTR_OBJS) $(CC) $(CFLAGS) -o ocat ocat.o $(OTR_OBJS) $(LIBS) -ot-recorder.o: ot-recorder.c storage.h util.h Makefile geo.h udata.h json.h http.h gcache.h config.mk +ot-recorder.o: ot-recorder.c storage.h util.h Makefile geo.h udata.h json.h http.h gcache.h config.mk hooks.h geo.o: geo.h geo.c udata.h Makefile config.mk geohash.o: geohash.h geohash.c udata.h Makefile config.mk base64.o: base64.h base64.c @@ -71,6 +78,7 @@ util.o: util.c util.h Makefile config.mk mongoose.o: mongoose.c mongoose.h ocat.o: ocat.c storage.h util.h config.mk version.h storage.o: storage.c storage.h util.h gcache.h config.mk +hooks.o: hooks.c udata.h hooks.h util.h version.h clean: diff --git a/README.md b/README.md index ee5aa42..36eceb9 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ You will require: * [libmosquitto](http://mosquitto.org) * [libCurl](http://curl.haxx.se/libcurl/) * [lmdb](http://symas.com/mdb) included +* Optionally [Lua](http://lua.org) Obtain and download the software, either [as a package, if available](https://packagecloud.io/owntracks/ot-recorder), via [our Homebrew Tap](https://github.com/owntracks/homebrew-recorder) on Mac OS X, directly as a clone of the repository, or as a [tar ball](https://github.com/owntracks/recorder/releases) which you unpack. Copy the included `config.mk.in` file to `config.mk` and edit that. You specify the features or tweaks you need. (The file is commented.) Pay particular attention to the installation directory and the value of the _store_ (`STORAGEDEFAULT`): that is where the recorder will store its files. `DOCROOT` is the root of the directory from which the _recorder_'s HTTP server will serve files. @@ -417,6 +418,73 @@ curl 'http://127.0.0.1:8083/api/0/kill?user=ngin&device=ojo' ``` The response contains a list of removed `.rec` files, and file system operations are logged to syslog. +## Lua hook + +If _recorder_ is compiled with Lua support, a Lua script you provide is launched at startup. Lua is _a powerful, fast, lightweight, embeddable scripting language_. You can use this to process location publishes in any way you desire: your imagination (and Lua-scripting knowhow) set the limits. Some examples: + +* insert publishes into a database of your choice +* switch on the coffee machine when your OwnTracks device reports you're entering home (but see also [mqttwarn](http://jpmens.net/2014/02/17/introducing-mqttwarn-a-pluggable-mqtt-notifier/) +* write a file with data in a format of your choice (see `etc/example.lua`) + +Run the _recorder_ with the path to your Lua script specified in its `--lua-script` option (there is no default). If the script cannot be loaded (e.g. because it cannot be read or contains syntax errors), the _recorder_ unloads Lua and continues *without* your script. + +Your Lua program is automatically provided with a table which contains the following members: + +* `otr.version` is a read-only string with the _recorder_ version (example: `"0.3.2"`) +* `otr.log()` is a function which takes a string which is logged to syslog at the _recorder_'s facility and log level INFO. +* `otr.strftime(fmt, t)` is a function which takes a format string (see `strftime(3)`) and an integer number of seconds and returns a string with the formatted UTC time. If `t` is 0 or negative, the current system time is used. + +Your Lua script must provide the following functions: + +### `otr_init` + +This is invoked at start of _recorder_. If the function returns a non-zero value, _recorder_ unloads Lua and disables its processing; i.e. the `hook()` will *not* be invoked on location publishes. + +### `otr_exit` + +This is invoked when the _recorder_ stops, which it doesn't really do unless you CTRL-C it. + +### `otr_hook` + +This function is invoked at every location publish processed by the _recorder_. Your function is passed three arguments: + +1. _topic_ is the topic published to (e.g. `owntracks/jane/phone`) +2. _type_ is the type of MQTT message. This is the `_type` in our JSON messages (e.g. `location`) or `"unknown"`. +3. _location_ is a [Lua table](http://www.lua.org/pil/2.5.html) (associative array) with all the elements obtained in the JSON message. In the case of _type_ being `location`, we also add country code (`cc`) and the location's address (`addr`) unless reverse-geo lookups have been disabled in _recorder_. + +Assume the following small example Lua script in `example.lua`: + +```lua +local file + +function otr_init() + otr.log("example.lua starting; writing to /tmp/lua.out") + file = io.open("/tmp/lua.out", "a") + file:write("written by OwnTracks Recorder version " .. otr.version .. "\n") +end + +function otr_hook(topic, _type, data) + local timestr = otr.strftime("It is %T in the year %Y", 0) + print("L: " .. topic .. " -> " .. _type) + file:write(timestr .. " " .. topic .. " lat=" .. data['lat'] .. data['addr'] .. "\n") +end +``` + +When _recorder_ is launched with `--lua-script example.lua` it invokes `otr_init()` which opens a file. Then, for each location received, it calls `otr_hook()` which updates the file. + +Assuming an OwnTracks device publishes this payload + +```json +{"cog":-1,"batt":-1,"lon":2.29513,"acc":5,"vel":-1,"vac":-1,"lat":48.85833,"t":"u","tst":1441984413,"alt":0,"_type":"location","tid":"JJ"} +``` + +the file `/tmp/lua.out` would contain + +```txt +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 +``` + #### Environment The following environment variables control _ocat_'s behaviour: diff --git a/assets/ot-recorder.png b/assets/ot-recorder.png index c3eac9c4344c93a020c11760dcbe3837561ae175..7367fd81311e32bfb3922db2539fafcef80cbbf2 100644 GIT binary patch literal 42239 zcmbTecQo7oA3rJyVn%C~nynps)ZR*|O|7D$YSrG<3{|bY_o`W?cI}c-MaCAWv@E5UF38=OzbtX^|8|F=~S+&>cd#NTU61&aAN(3`msk{ZlXSpZ?XbgGh`$t z1M=O<+S}Sbo_qhSm?+mV;?OARhyTA9N2#&rvlCC{%wPZbI*K+F0;ERR-TR)N#-6(} zyO(BBvsr4^dO!g?Pr47jDR!?xs5pfq?%0Aa>mIg;W;2Fa^P)Sfr&_$4>wA|EN)u}w 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 g!1G1OpKpK%V(>PQN?eMe-+uQ%m4rY literal 41312 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 diff --git a/config.mk.in b/config.mk.in index 62200d8..39c7a5c 100644 --- a/config.mk.in +++ b/config.mk.in @@ -8,6 +8,9 @@ HAVE_HTTP ?= yes # Do you want to use reverse-geo caching? (Highly recommended) HAVE_LMDB ?= yes +# Do you have Lua libraries installed and want the Lua hook integration? +WITH_LUA ?= no + # Do you want support for the `pingping' monitoring feature? HAVE_PING ?= yes @@ -51,3 +54,6 @@ APIKEY ?= MOSQUITTO_INC = -I/usr/include MOSQUITTO_LIB = -L/usr/lib MORELIBS = # -lssl + +LUA_CFLAGS = +LUA_LIBS = -llua diff --git a/etc/example.lua b/etc/example.lua new file mode 100644 index 0000000..404effa --- /dev/null +++ b/etc/example.lua @@ -0,0 +1,13 @@ +local file + +function otr_init() + otr.log("example.lua starting; writing to /tmp/lua.out") + file = io.open("/tmp/lua.out", "a") + file:write("written by OwnTracks Recorder version " .. otr.version .. "\n") +end + +function otr_hook(topic, _type, data) + local timestr = otr.strftime("It is %T in the year %Y", 0) + print("L: " .. topic .. " -> " .. _type) + file:write(timestr .. " " .. topic .. " lat=" .. data['lat'] .. data['addr'] .. "\n") +end diff --git a/hooks.c b/hooks.c new file mode 100644 index 0000000..91fda0d --- /dev/null +++ b/hooks.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include + +#ifdef WITH_LUA +# include +# include +# include "util.h" +# include "udata.h" +# include "hooks.h" +# include "lua.h" +# include "lualib.h" +# include "lauxlib.h" +# include "json.h" +# include "version.h" + +static int otr_log(lua_State *lua); +static int otr_strftime(lua_State *lua); + +/* + * Invoke the function `name' in the Lua script, which _may_ return + * an integer that we, in turn, return to caller. + */ + +static int l_function(lua_State *L, char *name) +{ + int rc = 0; + + lua_getglobal(L, name); + if (lua_type(L, -1) != LUA_TFUNCTION) { + olog(LOG_ERR, "Cannot invoke Lua function %s: %s\n", name, lua_tostring(L, -1)); + rc = 1; + } else { + lua_call(L, 0, 1); + rc = (int)lua_tonumber(L, -1); + } + lua_settop(L, 0); + return (rc); +} + +struct luadata *hooks_init(char *script) +{ + struct luadata *ld; + int rc; + + if ((ld = malloc(sizeof(struct luadata))) == NULL) + return (NULL); + + ld->script = strdup(script); + // ld->L = lua_open(); + ld->L = luaL_newstate(); + luaL_openlibs(ld->L); + + /* + * Set up a global with some values. + */ + + lua_newtable(ld->L); + lua_pushstring(ld->L, VERSION); + lua_setfield(ld->L, -2, "version"); + + // lua_pushstring(ld->L, "/Users/jpm/Auto/projects/on-github/owntracks/recorder/lua"); + // lua_setfield(ld->L, -2, "luapath"); + + lua_pushcfunction(ld->L, otr_log); + lua_setfield(ld->L, -2, "log"); + + lua_pushcfunction(ld->L, otr_strftime); + lua_setfield(ld->L, -2, "strftime"); + + lua_setglobal(ld->L, "otr"); + + + olog(LOG_DEBUG, "initializing Lua hooks at %s", script); + + /* Load the Lua script */ + if (luaL_dofile(ld->L, ld->script)) { + olog(LOG_ERR, "Cannot load Lua from %s: %s", ld->script, lua_tostring(ld->L, -1)); + hooks_exit(ld, "failed to load script"); + return (NULL); + } + + rc = l_function(ld->L, "otr_init"); + if (rc != 0) { + + /* + * After all this work (sigh), the Script has decided we shouldn't use + * hooks, so unload the whole Lua stuff and NULL back. + */ + + hooks_exit(ld, "otr_init() returned non-zero"); + ld = NULL; + } + + + return (ld); +} + +void hooks_exit(struct luadata *ld, char *reason) +{ + if (ld) { + olog(LOG_NOTICE, "unloading Lua: %s", reason); + free(ld->script); + lua_close(ld->L); + free(ld); + } +} + +void hooks_hook(struct udata *ud, char *topic, JsonNode *fullo) +{ + struct luadata *ld = ud->luadata; + char *_type = "unknown"; + JsonNode *j; + + lua_getglobal(ld->L, "otr_hook"); + if (lua_type(ld->L, -1) != LUA_TFUNCTION) { + olog(LOG_NOTICE, "cannot invoke otr_hook in Lua script"); + return; + } + + lua_pushstring(ld->L, topic); /* arg1: topic */ + + if ((j = json_find_member(fullo, "_type")) != NULL) { + if (j->tag == JSON_STRING) + _type = j->string_; + } + + lua_pushstring(ld->L, _type); /* arg2: record type */ + + lua_newtable(ld->L); /* arg3: table */ + json_foreach(j, fullo) { + lua_pushstring(ld->L, j->key); /* table key */ + if (j->tag == JSON_STRING) { + lua_pushstring(ld->L, j->string_); + } else if (j->tag == JSON_NUMBER) { + lua_pushnumber(ld->L, j->number_); + } else if (j->tag == JSON_NULL) { + lua_pushnil(ld->L); + } else if (j->tag == JSON_BOOL) { + lua_pushboolean(ld->L, j->bool_); + } + lua_rawset(ld->L, -3); + + } + + /* Invoke `hook' function in Lua with our args */ + if (lua_pcall(ld->L, 3, 1, 0)) { + olog(LOG_ERR, "Failed to run script: %s", lua_tostring(ld->L, -1)); + exit(1); + } + + // rc = (int)lua_tonumber(ld->L, -1); + // printf("C: FILTER returns %d\n", rc); +} + +/* + * --- Here come the functions we provide to Lua scripts. + */ + +static int otr_log(lua_State *lua) +{ + const char *str; + + if (lua_gettop(lua) >= 1) { + str = lua_tostring(lua, 1); + olog(LOG_INFO, "%s", str); + } + return 0; +} + +/* + * otr.strftime(format, seconds) + * Perform a strtime(3) for Lua with the specified format and + * seconds, and return the string result to Lua. As a special + * case, if `seconds' is negative, use current time. + */ + +static int otr_strftime(lua_State *lua) +{ + const char *fmt; + long secs; + struct tm *tm; + char buf[BUFSIZ]; + + if (lua_gettop(lua) >= 1) { + fmt = lua_tostring(lua, 1); + if ((secs = lua_tonumber(lua, 2)) < 1) + secs = time(0); + + if ((tm = gmtime(&secs)) != NULL) { + strftime(buf, sizeof(buf), fmt, tm); + + lua_pushstring(lua, buf); + return (1); + } + } + return (0); +} + +#endif /* WITH_LUA */ diff --git a/hooks.h b/hooks.h new file mode 100644 index 0000000..0c6acfe --- /dev/null +++ b/hooks.h @@ -0,0 +1,19 @@ +#ifndef HOOKS_H_INCLUDED +# define HOOKS_H_INCLUDED + +#ifdef WITH_LUA +# include "lua.h" + + +struct luadata { + char *script; /* Path to Lua script in --lua-script */ + lua_State *L; /* The Lua machine */ +}; + +struct luadata *hooks_init(char *luascript); +void hooks_exit(struct luadata *, char *reason); +void hooks_hook(struct udata *ud, char *topic, JsonNode *obj); + +#endif /* WITH_LUA */ + +#endif diff --git a/ocat.c b/ocat.c index b050f9f..b056139 100644 --- a/ocat.c +++ b/ocat.c @@ -173,6 +173,9 @@ void print_versioninfo() #ifdef HAVE_LMDB printf("\tHAVE_LMDB = yes\n"); #endif +#ifdef WITH_LUA + printf("\tWITH_LUA = yes\n"); +#endif #ifdef HAVE_HTTP printf("\tHAVE_HTTP = yes\n"); #endif diff --git a/ot-recorder.c b/ot-recorder.c index 079bef3..55909a1 100644 --- a/ot-recorder.c +++ b/ot-recorder.c @@ -45,6 +45,9 @@ #ifdef HAVE_HTTP # include "http.h" #endif +#ifdef WITH_LUA +# include "hooks.h" +#endif #define SSL_VERIFY_PEER (1) @@ -357,7 +360,7 @@ JsonNode *csv(char *payload, char *tid, char *t, double *lat, double *lon, long void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *m) { - JsonNode *json; + JsonNode *json, *fullo, *geo = NULL; char tid[BUFSIZ], t[BUFSIZ], *p; double lat, lon; long tst; @@ -510,7 +513,7 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m cached = FALSE; if (ud->revgeo == TRUE) { - JsonNode *geo, *j; + JsonNode *j; if ((geo = gcache_json_get(ud->gc, utstring_body(ghash))) != NULL) { /* Habemus cached data */ @@ -523,11 +526,9 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m if ((j = json_find_member(geo, "addr")) != NULL) { utstring_printf(addr, "%s", j->string_); } - json_delete(geo); } else { if ((geo = revgeo(lat, lon, addr, cc)) != NULL) { gcache_json_put(ud->gc, utstring_body(ghash), geo); - json_delete(geo); } else { /* We didn't obtain reverse Geo, maybe because of over * quota; make a note of the missing geohash */ @@ -551,45 +552,51 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m * We have exactly three topic parts (owntracks/user/device), and valid JSON. */ + /* + * Create a new location object containing all the bits and + * pieces we need and push that into connected Websockets. + * and/or into Lua hooks. + */ + + fullo = json_mkobject(); + json_copy_to_object(fullo, json, TRUE); + + if (geo != NULL) { + json_copy_to_object(fullo, geo, FALSE); + json_delete(geo); + } + + /* + * I need a unique "key" in the Websocket clients to keep track + * of which device is being updated; use topic. + */ + + json_append_member(fullo, "topic", json_mkstring(m->topic)); + + /* + * We have to know which user/device this is for in order to + * determine whether a connected Websocket client is authorized + * to see this. Add user/device + */ + + json_append_member(fullo, "user", json_mkstring(utstring_body(username))); + json_append_member(fullo, "device", json_mkstring(utstring_body(device))); + #ifdef HAVE_HTTP if (ud->mgserver && !pingping) { - /* - * Create a new location object containing all the bits and - * pieces we need and push that into connected Websockets. - * TODO: clean up - */ - JsonNode *geo, *wso = json_mkobject(); - - json_copy_to_object(wso, json, TRUE); - - if ((geo = gcache_json_get(ud->gc, utstring_body(ghash))) != NULL) { - json_copy_to_object(wso, geo, FALSE); - json_delete(geo); - } - - /* - * I need a unique "key" in the Websocket clients to keep track - * of which device is being updated; use topic. - */ - - json_append_member(wso, "topic", json_mkstring(m->topic)); - - /* - * We have to know which user/device this is for in order to - * determine whether a connected Websocket client is authorized - * to see this. Add user/device - */ - - json_append_member(wso, "user", json_mkstring(utstring_body(username))); - json_append_member(wso, "device", json_mkstring(utstring_body(device))); - - http_ws_push_json(ud->mgserver, wso); - json_delete(wso); + http_ws_push_json(ud->mgserver, fullo); } #endif +#ifdef WITH_LUA + if (ud->luadata && !pingping) { + hooks_hook(ud, m->topic, fullo); + } +#endif + json_delete(fullo); + if ((jsonstring = json_stringify(json, NULL)) != NULL) { char *js; @@ -685,8 +692,7 @@ void on_disconnect(struct mosquitto *mosq, void *userdata, int reason) static void catcher(int sig) { fprintf(stderr, "Going down on signal %d\n", sig); - - exit(1); + run = 0; } void usage(char *prog) @@ -707,6 +713,9 @@ void usage(char *prog) printf(" --http-host HTTP addr to bind to (localhost)\n"); printf(" --http-port -A HTTP port (8083); 0 to disable HTTP\n"); printf(" --doc-root document root (%s)\n", DOCROOT); +#endif +#ifdef WITH_LUA + printf(" --lua-script path to Lua script. If unset, no Lua hooks\n"); #endif printf(" --precision ghash precision (dflt: %d)\n", GHASHPREC); printf(" --hosted use OwnTracks Hosted\n"); @@ -732,6 +741,9 @@ int main(int argc, char **argv) struct mosquitto *mosq = NULL; char err[1024], *p, *username, *password, *cafile, *device; char *hostname = "localhost", *logfacility = "local0"; +#ifdef WITH_LUA + char *luascript = NULL; +#endif int port = 1883; int rc, i, ch, hosted = FALSE; static struct udata udata, *ud = &udata; @@ -755,6 +767,9 @@ int main(int argc, char **argv) #ifdef HAVE_HTTP udata.mgserver = NULL; #endif +#ifdef WITH_LUA + udata.luadata = NULL; +#endif if ((p = getenv("OTR_HOST")) != NULL) { hostname = strdup(p); @@ -790,6 +805,9 @@ int main(int argc, char **argv) { "logfacility", required_argument, 0, 4}, { "precision", required_argument, 0, 5}, { "hosted", no_argument, 0, 6}, +#ifdef WITH_LUA + { "lua-script", required_argument, 0, 7}, +#endif #ifdef HAVE_HTTP { "http-host", required_argument, 0, 3}, { "http-port", required_argument, 0, 'A'}, @@ -804,6 +822,12 @@ int main(int argc, char **argv) break; switch (ch) { +#ifdef WITH_LUA + case 7: + /* FIXME: check existence of script file */ + luascript = strdup(optarg); + break; +#endif case 6: hosted = TRUE; break; @@ -911,6 +935,18 @@ int main(int argc, char **argv) openlog("ot-recorder", LOG_PID | LOG_PERROR, syslog_facility_code(logfacility)); +#ifdef WITH_LUA + /* + * If option for lua-script has not been given, ignore all hooks. + */ + + if (luascript) { + if ((udata.luadata = hooks_init(luascript)) == NULL) + olog(LOG_NOTICE, "proceeding sans Lua"); + free(luascript); + } +#endif + #ifdef HAVE_HTTP if (http_port) { if (!is_directory(doc_root)) { @@ -946,6 +982,7 @@ int main(int argc, char **argv) signal(SIGINT, catcher); + signal(SIGTERM, catcher); mosq = mosquitto_new(utstring_body(clientid), CLEAN_SESSION, (void *)&udata); if (!mosq) { @@ -1059,6 +1096,10 @@ int main(int argc, char **argv) #ifdef HAVE_HTTP mg_destroy_server(&udata.mgserver); #endif + +#ifdef WITH_LUA + hooks_exit(ud->luadata, "recorder stops"); +#endif mosquitto_disconnect(mosq); mosquitto_destroy(mosq); diff --git a/udata.h b/udata.h index 6206ad1..6c23a35 100644 --- a/udata.h +++ b/udata.h @@ -24,6 +24,9 @@ struct udata { #ifdef HAVE_HTTP struct mg_server *mgserver; /* Mongoose */ #endif +#ifdef WITH_LUA + struct luadata *luadata; /* Lua stuff */ +#endif }; #endif