mirror of
https://github.com/owntracks/recorder.git
synced 2024-11-15 09:58:40 -07:00
parent
dd846a3860
commit
e7f368ef04
@ -487,7 +487,7 @@ List users. If _user_ is specified, lists that user's devices. If both _user_ an
|
||||
|
||||
#### `locations`
|
||||
|
||||
Here comes the actual data. This lists users' locations and requires both _user_ and _device_. Output format is JSON unless a different _format_ is given (`json`, `geojson`, and `linestring` are supported).
|
||||
Here comes the actual data. This lists users' locations and requires both _user_ and _device_. Output format is JSON unless a different _format_ is given (`csv`, `json`, `geojson`, `xml`, and `linestring` are supported).
|
||||
|
||||
In order to limit the number of records returned, use _limit_ which causes a reverse search through the `.rec` files; this can be used to find the last N positions.
|
||||
|
||||
|
22
http.c
22
http.c
@ -270,10 +270,24 @@ static void emit_xml_line(char *line, void *param)
|
||||
mg_printf_data(conn, "\n");
|
||||
}
|
||||
|
||||
static void emit_csv_line(char *line, void *param)
|
||||
{
|
||||
struct mg_connection *conn = (struct mg_connection *)param;
|
||||
|
||||
mg_printf_data(conn, line);
|
||||
}
|
||||
|
||||
static int xml_response(struct mg_connection *conn, JsonNode *obj)
|
||||
{
|
||||
/* TODO: support fields? */
|
||||
xml_output(obj, CSV, NULL, emit_xml_line, conn);
|
||||
xml_output(obj, XML, NULL, emit_xml_line, conn);
|
||||
|
||||
json_delete(obj);
|
||||
return (MG_TRUE);
|
||||
}
|
||||
|
||||
static int csv_response(struct mg_connection *conn, JsonNode *obj)
|
||||
{
|
||||
csv_output(obj, CSV, NULL, emit_csv_line, conn);
|
||||
|
||||
json_delete(obj);
|
||||
return (MG_TRUE);
|
||||
@ -376,6 +390,8 @@ static int dispatch(struct mg_connection *conn, const char *uri)
|
||||
otype = JSON;
|
||||
else if (!strcmp(buf, "linestring"))
|
||||
otype = LINESTRING;
|
||||
else if (!strcmp(buf, "csv"))
|
||||
otype = CSV;
|
||||
else if (!strcmp(buf, "xml"))
|
||||
otype = XML;
|
||||
else {
|
||||
@ -440,6 +456,8 @@ static int dispatch(struct mg_connection *conn, const char *uri)
|
||||
|
||||
if (otype == JSON) {
|
||||
return (json_response(conn, obj));
|
||||
} else if (otype == CSV) {
|
||||
return (csv_response(conn, obj));
|
||||
} else if (otype == XML) {
|
||||
return (xml_response(conn, obj));
|
||||
} else if (otype == LINESTRING) {
|
||||
|
106
ocat.c
106
ocat.c
@ -32,36 +32,6 @@
|
||||
#include "misc.h"
|
||||
#include "version.h"
|
||||
|
||||
#define STRINGCOLUMN(x) (!strcmp(x, "addr") || !strcmp(x, "locality"))
|
||||
|
||||
/*
|
||||
* Print the value in a single JSON node. If string, easy. If number account for
|
||||
* what we call 'integer' types which shouldn't be printed as floats.
|
||||
*/
|
||||
|
||||
static void print_one(JsonNode *j, JsonNode *inttypes)
|
||||
{
|
||||
/* Check if the value should be an "integer" (ie not float) */
|
||||
if (j->tag == JSON_NUMBER) {
|
||||
if (json_find_member(inttypes, j->key)) {
|
||||
printf("%.lf", j->number_);
|
||||
} else {
|
||||
printf("%lf", j->number_);
|
||||
}
|
||||
} else if (j->tag == JSON_STRING) {
|
||||
char *quote = "";
|
||||
|
||||
if (STRINGCOLUMN(j->key)) {
|
||||
quote = "\"";
|
||||
}
|
||||
printf("%s%s%s", quote, j->string_, quote);
|
||||
} else if (j->tag == JSON_BOOL) {
|
||||
printf("%s", (j->bool_) ? "true" : "false");
|
||||
} else if (j->tag == JSON_NULL) {
|
||||
printf("null");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_xml_line(char *line, void *param)
|
||||
{
|
||||
FILE *fp = (FILE *)param;
|
||||
@ -69,78 +39,6 @@ static void print_xml_line(char *line, void *param)
|
||||
fprintf(fp, "%s\n", line);
|
||||
}
|
||||
|
||||
static void csv_title(JsonNode *node, char *column)
|
||||
{
|
||||
char *quote = "";
|
||||
|
||||
if (STRINGCOLUMN(column)) {
|
||||
quote = "\"";
|
||||
}
|
||||
printf("%s%s%s%c", quote, column, quote, (node->next) ? ',' : '\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Output location data as CSV. If `fields' is not NULL, it's a JSON
|
||||
* array of JSON elment names which should be printed instead of the
|
||||
* default ALL.
|
||||
*/
|
||||
|
||||
void csv_output(JsonNode *json, output_type otype, JsonNode *fields)
|
||||
{
|
||||
JsonNode *node, *inttypes;
|
||||
JsonNode *arr, *one, *j;
|
||||
short virgin = 1;
|
||||
|
||||
/* Prime the inttypes object with types we consider "integer" */
|
||||
inttypes = json_mkobject();
|
||||
json_append_member(inttypes, "batt", json_mkbool(1));
|
||||
json_append_member(inttypes, "vel", json_mkbool(1));
|
||||
json_append_member(inttypes, "cog", json_mkbool(1));
|
||||
json_append_member(inttypes, "tst", json_mkbool(1));
|
||||
json_append_member(inttypes, "alt", json_mkbool(1));
|
||||
json_append_member(inttypes, "dist", json_mkbool(1));
|
||||
json_append_member(inttypes, "trip", json_mkbool(1));
|
||||
|
||||
arr = json_find_member(json, "locations");
|
||||
json_foreach(one, arr) {
|
||||
/* Headings */
|
||||
if (virgin) {
|
||||
|
||||
virgin = !virgin;
|
||||
|
||||
if (fields) {
|
||||
json_foreach(node, fields) {
|
||||
csv_title(node, node->string_);
|
||||
}
|
||||
} else {
|
||||
json_foreach(node, one) {
|
||||
if (node->key)
|
||||
csv_title(node, node->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the values */
|
||||
if (fields) {
|
||||
json_foreach(node, fields) {
|
||||
if ((j = json_find_member(one, node->string_)) != NULL) {
|
||||
print_one(j, inttypes);
|
||||
printf("%c", node->next ? ',' : '\n');
|
||||
} else {
|
||||
/* specified field not in JSON for this row */
|
||||
printf("%c", node->next ? ',' : '\n');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
json_foreach(j, one) {
|
||||
print_one(j, inttypes);
|
||||
printf("%c", j->next ? ',' : '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
json_delete(inttypes);
|
||||
}
|
||||
|
||||
void usage(char *prog)
|
||||
{
|
||||
printf("Usage: %s [options..] [file ...]\n", prog);
|
||||
@ -446,7 +344,7 @@ int main(int argc, char **argv)
|
||||
JsonNode *o = json_mkobject();
|
||||
|
||||
json_append_member(o, "locations", user_array);
|
||||
csv_output(o, CSV, fields);
|
||||
csv_output(o, CSV, fields, print_xml_line, xmlp);
|
||||
json_delete(o);
|
||||
|
||||
} else if (otype == XML) {
|
||||
@ -570,7 +468,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
} else if (otype == CSV) {
|
||||
csv_output(obj, CSV, fields);
|
||||
csv_output(obj, CSV, fields, print_xml_line, xmlp);
|
||||
} else if (otype == XML) {
|
||||
xml_output(obj, XML, fields, print_xml_line, xmlp);
|
||||
} else if (otype == RAW || otype == RAWPAYLOAD) {
|
||||
|
111
storage.c
111
storage.c
@ -1282,6 +1282,117 @@ void xml_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func
|
||||
json_delete(inttypes);
|
||||
}
|
||||
|
||||
#define STRINGCOLUMN(x) (!strcmp(x, "addr") || !strcmp(x, "locality"))
|
||||
|
||||
/*
|
||||
* Print the value in a single JSON node. If string, easy. If number account for
|
||||
* what we call 'integer' types which shouldn't be printed as floats.
|
||||
*/
|
||||
|
||||
static void print_one(UT_string *line, JsonNode *j, JsonNode *inttypes, void (func)(char *line, void *param), void *param)
|
||||
{
|
||||
/* Check if the value should be an "integer" (ie not float) */
|
||||
if (j->tag == JSON_NUMBER) {
|
||||
if (json_find_member(inttypes, j->key)) {
|
||||
utstring_printf(line, "%.lf", j->number_);
|
||||
} else {
|
||||
utstring_printf(line, "%lf", j->number_);
|
||||
}
|
||||
} else if (j->tag == JSON_STRING) {
|
||||
char *quote = "";
|
||||
|
||||
if (STRINGCOLUMN(j->key)) {
|
||||
quote = "\"";
|
||||
}
|
||||
utstring_printf(line, "%s%s%s", quote, j->string_, quote);
|
||||
} else if (j->tag == JSON_BOOL) {
|
||||
utstring_printf(line, "%s", (j->bool_) ? "true" : "false");
|
||||
} else if (j->tag == JSON_NULL) {
|
||||
utstring_printf(line, "null");
|
||||
}
|
||||
}
|
||||
|
||||
static void csv_title(UT_string *line, JsonNode *node, char *column)
|
||||
{
|
||||
char *quote = "";
|
||||
|
||||
if (STRINGCOLUMN(column)) {
|
||||
quote = "\"";
|
||||
}
|
||||
utstring_printf(line, "%s%s%s%c", quote, column, quote, (node->next) ? ',' : '\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Output location data as CSV. If `fields' is not NULL, it's a JSON
|
||||
* array of JSON elment names which should be printed instead of the
|
||||
* default ALL.
|
||||
*/
|
||||
|
||||
void csv_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func)(char *s, void *param), void *param)
|
||||
{
|
||||
JsonNode *node, *inttypes;
|
||||
JsonNode *arr, *one, *j;
|
||||
short virgin = 1;
|
||||
static UT_string *line = NULL;
|
||||
|
||||
utstring_renew(line);
|
||||
|
||||
/* Prime the inttypes object with types we consider "integer" */
|
||||
inttypes = json_mkobject();
|
||||
json_append_member(inttypes, "batt", json_mkbool(1));
|
||||
json_append_member(inttypes, "vel", json_mkbool(1));
|
||||
json_append_member(inttypes, "cog", json_mkbool(1));
|
||||
json_append_member(inttypes, "tst", json_mkbool(1));
|
||||
json_append_member(inttypes, "alt", json_mkbool(1));
|
||||
json_append_member(inttypes, "dist", json_mkbool(1));
|
||||
json_append_member(inttypes, "trip", json_mkbool(1));
|
||||
|
||||
arr = json_find_member(json, "locations");
|
||||
json_foreach(one, arr) {
|
||||
/* Headings */
|
||||
if (virgin) {
|
||||
|
||||
virgin = !virgin;
|
||||
|
||||
if (fields) {
|
||||
json_foreach(node, fields) {
|
||||
csv_title(line, node, node->string_);
|
||||
}
|
||||
} else {
|
||||
json_foreach(node, one) {
|
||||
if (node->key)
|
||||
csv_title(line, node, node->key);
|
||||
}
|
||||
}
|
||||
func(UB(line), param);
|
||||
utstring_renew(line);
|
||||
}
|
||||
|
||||
/* Now the values */
|
||||
if (fields) {
|
||||
json_foreach(node, fields) {
|
||||
if ((j = json_find_member(one, node->string_)) != NULL) {
|
||||
print_one(line, j, inttypes, func, param);
|
||||
utstring_printf(line, "%c", node->next ? ',' : '\n');
|
||||
} else {
|
||||
/* specified field not in JSON for this row */
|
||||
utstring_printf(line, "%c", node->next ? ',' : '\n');
|
||||
}
|
||||
}
|
||||
func(UB(line), param);
|
||||
utstring_renew(line);
|
||||
} else {
|
||||
json_foreach(j, one) {
|
||||
print_one(line, j, inttypes, func, param);
|
||||
utstring_printf(line, "%c", j->next ? ',' : '\n');
|
||||
}
|
||||
func(UB(line), param);
|
||||
utstring_renew(line);
|
||||
}
|
||||
}
|
||||
json_delete(inttypes);
|
||||
}
|
||||
|
||||
char *storage_userphoto(char *username)
|
||||
{
|
||||
static char path[BUFSIZ];
|
||||
|
@ -48,6 +48,7 @@ void storage_init(int revgeo);
|
||||
void storage_gcache_dump(char *lmdbname);
|
||||
void storage_gcache_load(char *lmdbname);
|
||||
void xml_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func)(char *s, void *param), void *param);
|
||||
void csv_output(JsonNode *json, output_type otype, JsonNode *fields, void (*func)(char *s, void *param), void *param);
|
||||
char *storage_userphoto(char *username);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user