receiver.json support, internal webserver cleanup.

Add data/receiver.json (generated once) and support for it in script.js.

Internal webserver rearrangement to support multiple json files.
This commit is contained in:
Oliver Jowett 2014-12-10 17:05:22 +00:00
parent f707f2cdce
commit 9fa09e0e92
5 changed files with 138 additions and 58 deletions

2
debian/changelog vendored
View file

@ -5,6 +5,8 @@ dump1090-mutability (1.08.2302.14+1mu-3) UNRELEASED; urgency=medium
* Be much more cautious about missing config settings so we don't explode * Be much more cautious about missing config settings so we don't explode
so badly if something is omitted. so badly if something is omitted.
* Use the package version as the version number compiled into the binary. * Use the package version as the version number compiled into the binary.
* Add data/receiver.json (generated once) and support for it in script.js.
* Internal webserver rearrangement to support multiple json files.
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 10 Dec 2014 02:01:27 +0000 -- Oliver Jowett <oliver@mutability.co.uk> Wed, 10 Dec 2014 02:01:27 +0000

View file

@ -634,14 +634,15 @@ void backgroundTasks(void) {
} }
} }
if (Modes.json_path && Modes.json_interval > 0) { if (Modes.json_aircraft_path && Modes.json_interval > 0) {
time_t now = time(NULL); time_t now = time(NULL);
if (now >= next_json) { if (now >= next_json) {
modesWriteJson(Modes.json_path); writeJsonToFile(Modes.json_aircraft_path, generateAircraftJson);
next_json = now + Modes.json_interval; next_json = now + Modes.json_interval;
} }
} }
} }
// //
//========================================================================= //=========================================================================
// //
@ -837,9 +838,13 @@ int main(int argc, char **argv) {
#ifndef _WIN32 #ifndef _WIN32
} else if (!strcmp(argv[j], "--write-json") && more) { } else if (!strcmp(argv[j], "--write-json") && more) {
++j; ++j;
Modes.json_path = malloc(strlen(argv[j]) + 15); Modes.json_aircraft_path = malloc(strlen(argv[j]) + 15);
strcpy(Modes.json_path, argv[j]); strcpy(Modes.json_aircraft_path, argv[j]);
strcat(Modes.json_path, "/aircraft.json"); strcat(Modes.json_aircraft_path, "/aircraft.json");
Modes.json_metadata_path = malloc(strlen(argv[j]) + 15);
strcpy(Modes.json_metadata_path, argv[j]);
strcat(Modes.json_metadata_path, "/receiver.json");
} else if (!strcmp(argv[j], "--write-json-every") && more) { } else if (!strcmp(argv[j], "--write-json-every") && more) {
Modes.json_interval = atoi(argv[++j]); Modes.json_interval = atoi(argv[++j]);
#endif #endif
@ -908,6 +913,10 @@ int main(int argc, char **argv) {
} }
if (Modes.net) modesInitNet(); if (Modes.net) modesInitNet();
if (Modes.json_metadata_path && Modes.json_interval > 0) {
writeJsonToFile(Modes.json_metadata_path, generateReceiverJson); // once only on startup
}
// If the user specifies --net-only, just run in order to serve network // If the user specifies --net-only, just run in order to serve network
// clients without reading data from the RTL device // clients without reading data from the RTL device
while (Modes.net_only) { while (Modes.net_only) {

View file

@ -369,8 +369,9 @@ struct { // Internal state
int mlat; // Use Beast ascii format for raw data output, i.e. @...; iso *...; int mlat; // Use Beast ascii format for raw data output, i.e. @...; iso *...;
int interactive_rtl1090; // flight table in interactive mode is formatted like RTL1090 int interactive_rtl1090; // flight table in interactive mode is formatted like RTL1090
int no_decode; // Disable decoding and aircraft tracking int no_decode; // Disable decoding and aircraft tracking
char *json_path; // Path to json data file to write, or NULL not to. char *json_aircraft_path; // Path to json aircraft file to write, or NULL not to.
int json_interval; // Interval between rewriting the json data file char *json_metadata_path; // Path to json metadata file to write, or NULL not to.
int json_interval; // Interval between rewriting the json aircraft file
// User details // User details
double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location double fUserLat; // Users receiver/antenna lat/lon needed for initial surface location
@ -495,7 +496,10 @@ void modesInitNet (void);
void modesQueueOutput (struct modesMessage *mm); void modesQueueOutput (struct modesMessage *mm);
void modesReadFromClient(struct client *c, char *sep, int(*handler)(struct client *, char *)); void modesReadFromClient(struct client *c, char *sep, int(*handler)(struct client *, char *));
void modesNetPeriodicWork (void); void modesNetPeriodicWork (void);
void modesWriteJson (const char *path);
void writeJsonToFile(const char *path, char * (*generator) (int*));
char *generateAircraftJson(int *len);
char *generateReceiverJson(int *len);
#ifdef __cplusplus #ifdef __cplusplus
} }

120
net_io.c
View file

@ -667,7 +667,7 @@ int decodeHexMessage(struct client *c, char *hex) {
// //
// Return a description of planes in json. No metric conversion // Return a description of planes in json. No metric conversion
// //
char *aircraftsToJson(int *len) { char *generateAircraftJson(int *len) {
time_t now = time(NULL); time_t now = time(NULL);
struct aircraft *a = Modes.aircrafts; struct aircraft *a = Modes.aircrafts;
int buflen = 1024; // The initial buffer is incremented as needed int buflen = 1024; // The initial buffer is incremented as needed
@ -727,15 +727,40 @@ char *aircraftsToJson(int *len) {
return buf; return buf;
} }
// Write JSON state to json_path //
void modesWriteJson(const char *path) // Return a description of the receiver in json.
//
char *generateReceiverJson(int *len)
{
char *buf = (char *) malloc(1024), *p = buf;
p += sprintf(p, "{ " \
"\"version\" : \"%s\", "
"\"refresh\" : %d",
MODES_DUMP1090_VERSION, Modes.json_interval * 1000);
if (Modes.fUserLat != 0.0 || Modes.fUserLon != 0.0) {
p += sprintf(p, ", " \
"\"lat\" : %.2f, "
"\"lon\" : %.2f",
Modes.fUserLat, Modes.fUserLon); // round to 2dp - about 0.5-1km accuracy - for privacy reasons
}
p += sprintf(p, " }\n");
*len = (p - buf);
return buf;
}
// Write JSON to file
void writeJsonToFile(const char *path, char * (*generator) (int*))
{ {
#ifndef _WIN32 #ifndef _WIN32
char tmppath[PATH_MAX]; char tmppath[PATH_MAX];
int fd; int fd;
int len = 0; int len = 0;
char *content;
mode_t mask; mode_t mask;
char *content;
snprintf(tmppath, PATH_MAX, "%s.XXXXXX", path); snprintf(tmppath, PATH_MAX, "%s.XXXXXX", path);
tmppath[PATH_MAX-1] = 0; tmppath[PATH_MAX-1] = 0;
@ -747,27 +772,29 @@ void modesWriteJson(const char *path)
umask(mask); umask(mask);
fchmod(fd, 0644 & ~mask); fchmod(fd, 0644 & ~mask);
content = aircraftsToJson(&len); content = generator(&len);
if (write(fd, content, len) != len) if (write(fd, content, len) != len)
goto error_1; goto error_1;
if (close(fd) < 0) if (close(fd) < 0)
goto error_2; goto error_2;
free(content);
rename(tmppath, path); rename(tmppath, path);
free(content);
return; return;
error_1: error_1:
close(fd); close(fd);
error_2: error_2:
free(content);
unlink(tmppath); unlink(tmppath);
free(content);
return; return;
#endif #endif
} }
// //
//========================================================================= //=========================================================================
// //
@ -775,6 +802,17 @@ void modesWriteJson(const char *path)
#define MODES_CONTENT_TYPE_CSS "text/css;charset=utf-8" #define MODES_CONTENT_TYPE_CSS "text/css;charset=utf-8"
#define MODES_CONTENT_TYPE_JSON "application/json;charset=utf-8" #define MODES_CONTENT_TYPE_JSON "application/json;charset=utf-8"
#define MODES_CONTENT_TYPE_JS "application/javascript;charset=utf-8" #define MODES_CONTENT_TYPE_JS "application/javascript;charset=utf-8"
static struct {
char *path;
char * (*handler)(int*);
char *content_type;
} url_handlers[] = {
{ "/data/aircraft.json", generateAircraftJson, MODES_CONTENT_TYPE_JSON },
{ "/data/receiver.json", generateReceiverJson, MODES_CONTENT_TYPE_JSON },
{ NULL, NULL, NULL }
};
// //
// Get an HTTP request header and write the response to the client. // Get an HTTP request header and write the response to the client.
// gain here we assume that the socket buffer is enough without doing // gain here we assume that the socket buffer is enough without doing
@ -788,10 +826,10 @@ int handleHTTPRequest(struct client *c, char *p) {
int clen, hdrlen; int clen, hdrlen;
int httpver, keepalive; int httpver, keepalive;
int statuscode = 500; int statuscode = 500;
char *url, *content; char *url, *content = NULL;
char ctype[48];
char getFile[1024];
char *ext; char *ext;
char *content_type;
int i;
if (Modes.debug & MODES_DEBUG_NET) if (Modes.debug & MODES_DEBUG_NET)
printf("\nHTTP request: %s\n", c->buf); printf("\nHTTP request: %s\n", c->buf);
@ -820,23 +858,30 @@ int handleHTTPRequest(struct client *c, char *p) {
printf("HTTP requested URL: %s\n\n", url); printf("HTTP requested URL: %s\n\n", url);
} }
if (strlen(url) < 2) { statuscode = 404;
snprintf(getFile, sizeof getFile, "%s/gmap.html", HTMLPATH); // Default file for (i = 0; url_handlers[i].path; ++i) {
} else { if (!strcmp(url, url_handlers[i].path)) {
snprintf(getFile, sizeof getFile, "%s/%s", HTMLPATH, url); content_type = url_handlers[i].content_type;
content = url_handlers[i].handler(&clen);
statuscode = 200;
if (Modes.debug & MODES_DEBUG_NET) {
printf("HTTP: 200: %s -> internal (%d bytes, %s)\n", url, clen, content_type);
}
break;
}
} }
// Select the content to send, we have just two so far: if (!content) {
// "/" -> Our google map application.
// "/aircraft.json" -> Our ajax request to update planes.
if (strstr(url, "/data/aircraft.json")) {
statuscode = 200;
content = aircraftsToJson(&clen);
//snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON);
} else {
struct stat sbuf; struct stat sbuf;
int fd = -1; int fd = -1;
char rp[PATH_MAX], hrp[PATH_MAX]; char rp[PATH_MAX], hrp[PATH_MAX];
char getFile[1024];
if (strlen(url) < 2) {
snprintf(getFile, sizeof getFile, "%s/gmap.html", HTMLPATH); // Default file
} else {
snprintf(getFile, sizeof getFile, "%s/%s", HTMLPATH, url);
}
if (!realpath(getFile, rp)) if (!realpath(getFile, rp))
rp[0] = 0; rp[0] = 0;
@ -866,22 +911,27 @@ int handleHTTPRequest(struct client *c, char *p) {
if (fd != -1) { if (fd != -1) {
close(fd); close(fd);
} }
}
// Get file extension and content type // Get file extension and content type
snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_HTML); // Default content type content_type = MODES_CONTENT_TYPE_HTML; // Default content type
ext = strrchr(getFile, '.'); ext = strrchr(getFile, '.');
if (strlen(ext) > 0) { if (strlen(ext) > 0) {
if (strstr(ext, ".json")) { if (strstr(ext, ".json")) {
snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JSON); content_type = MODES_CONTENT_TYPE_JSON;
} else if (strstr(ext, ".css")) { } else if (strstr(ext, ".css")) {
snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_CSS); content_type = MODES_CONTENT_TYPE_CSS;
} else if (strstr(ext, ".js")) { } else if (strstr(ext, ".js")) {
snprintf(ctype, sizeof ctype, MODES_CONTENT_TYPE_JS); content_type = MODES_CONTENT_TYPE_JS;
}
}
if (Modes.debug & MODES_DEBUG_NET) {
printf("HTTP: %d: %s -> %s (%d bytes, %s)\n", statuscode, url, rp, clen, content_type);
} }
} }
// Create the header and send the reply // Create the header and send the reply
hdrlen = snprintf(hdr, sizeof(hdr), hdrlen = snprintf(hdr, sizeof(hdr),
"HTTP/1.1 %d \r\n" "HTTP/1.1 %d \r\n"
@ -893,7 +943,7 @@ int handleHTTPRequest(struct client *c, char *p) {
"Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n" "Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n"
"\r\n", "\r\n",
statuscode, statuscode,
ctype, content_type,
keepalive ? "keep-alive" : "close", keepalive ? "keep-alive" : "close",
clen); clen);

View file

@ -17,6 +17,9 @@ CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON; CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON;
ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL; ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
Dump1090Version = "unknown version";
RefreshInterval = 1000;
function fetchData() { function fetchData() {
$.getJSON('data/aircraft.json', function(data) { $.getJSON('data/aircraft.json', function(data) {
PlanesOnMap = 0 PlanesOnMap = 0
@ -32,15 +35,10 @@ function fetchData() {
var plane = jQuery.extend(true, {}, planeObject); var plane = jQuery.extend(true, {}, planeObject);
} }
/* For special squawk tests // Set SpecialSquawk-value
if (data[j].hex == '48413x') { if (data[j].squawk == '7500' || data[j].squawk == '7600' || data[j].squawk == '7700') {
data[j].squawk = '7700'; SpecialSquawk = true;
} //*/ }
// Set SpecialSquawk-value
if (data[j].squawk == '7500' || data[j].squawk == '7600' || data[j].squawk == '7700') {
SpecialSquawk = true;
}
// Call the function update // Call the function update
plane.funcUpdateData(data[j]); plane.funcUpdateData(data[j]);
@ -53,8 +51,25 @@ function fetchData() {
}); });
} }
// Initalizes the map and starts up our timers to call various functions
function initialize() { function initialize() {
// Get receiver metadata, reconfigure using it, then continue
// with initialization
$.getJSON('data/receiver.json')
.done(function(data) {
if (typeof data.receiverlat !== "undefined") {
SiteShow = true;
SiteLat = data.receiverlat;
SiteLon = data.receiverlon;
}
Dump1090Version = data.version;
RefreshInterval = data.refresh;
})
.always(initialize_after_config);
}
// Initalizes the map and starts up our timers to call various functions
function initialize_after_config() {
// Make a list of all the available map IDs // Make a list of all the available map IDs
var mapTypeIds = []; var mapTypeIds = [];
for(var type in google.maps.MapTypeId) { for(var type in google.maps.MapTypeId) {
@ -209,7 +224,7 @@ function initialize() {
refreshSelected(); refreshSelected();
reaper(); reaper();
extendedPulse(); extendedPulse();
}, 1000); }, RefreshInterval);
} }
// This looks for planes to reap out of the master Planes variable // This looks for planes to reap out of the master Planes variable
@ -257,7 +272,7 @@ function refreshSelected() {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' + html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' +
selected.flight + '</b>'; selected.flight + '</b>';
} else { } else {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090</b>'; html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090 ' + Dump1090Version + '</b>';
} }
if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking