Proof of concept for an aircraft metadata DB.
This commit is contained in:
parent
d7c5047fd3
commit
da2fff8531
118
public_html/dbloader.js
Normal file
118
public_html/dbloader.js
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
// -*- mode: javascript; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||||
|
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// dbloader.js: load aircraft metadata from static json files
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _aircraft_cache = {};
|
||||||
|
|
||||||
|
function getAircraftData(icao) {
|
||||||
|
var defer;
|
||||||
|
|
||||||
|
icao = icao.toUpperCase();
|
||||||
|
|
||||||
|
if (icao in _aircraft_cache) {
|
||||||
|
defer = _aircraft_cache[icao];
|
||||||
|
} else {
|
||||||
|
// load from blocks:
|
||||||
|
defer = _aircraft_cache[icao] = $.Deferred();
|
||||||
|
request_from_db(icao, 1, defer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function request_from_db(icao, level, defer) {
|
||||||
|
var bkey = icao.substring(0, level);
|
||||||
|
var dkey = icao.substring(level);
|
||||||
|
var req = db_ajax(bkey);
|
||||||
|
|
||||||
|
req.done(function(data) {
|
||||||
|
var subkey;
|
||||||
|
|
||||||
|
if ("children" in data) {
|
||||||
|
subkey = bkey + dkey.substring(0,1);
|
||||||
|
if (data.children.indexOf(subkey) == -1) {
|
||||||
|
defer.reject();
|
||||||
|
} else {
|
||||||
|
request_from_db(icao, level+1, defer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dkey in data) {
|
||||||
|
defer.resolve(data[dkey]);
|
||||||
|
} else {
|
||||||
|
defer.reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
req.fail(function(jqXHR,textStatus,errorThrown) {
|
||||||
|
defer.reject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var _request_count = 0;
|
||||||
|
var _request_queue = [];
|
||||||
|
var _request_cache = {};
|
||||||
|
|
||||||
|
var MAX_REQUESTS = 2;
|
||||||
|
|
||||||
|
function db_ajax(bkey) {
|
||||||
|
var defer;
|
||||||
|
|
||||||
|
if (bkey in _request_cache) {
|
||||||
|
return _request_cache[bkey];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_request_count < MAX_REQUESTS) {
|
||||||
|
// just do ajax directly
|
||||||
|
++_request_count;
|
||||||
|
defer = _request_cache[bkey] = $.ajax({ url: 'db/' + bkey + '.json',
|
||||||
|
cache: true,
|
||||||
|
timeout: 5000,
|
||||||
|
dataType : 'json' });
|
||||||
|
defer.always(db_ajax_request_complete);
|
||||||
|
} else {
|
||||||
|
// put it in the queue
|
||||||
|
defer = _request_cache[bkey] = $.Deferred();
|
||||||
|
defer.bkey = bkey;
|
||||||
|
_request_queue.push(defer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function db_ajax_request_complete() {
|
||||||
|
var req;
|
||||||
|
var ajaxreq;
|
||||||
|
|
||||||
|
if (_request_queue.length == 0) {
|
||||||
|
--_request_count;
|
||||||
|
} else {
|
||||||
|
req = _request_queue.shift();
|
||||||
|
ajaxreq = $.ajax({ url: 'db/' + req.bkey + '.json',
|
||||||
|
cache: true,
|
||||||
|
timeout: 5000,
|
||||||
|
dataType : 'json' });
|
||||||
|
ajaxreq.done(function(data) { req.resolve(data); });
|
||||||
|
ajaxreq.fail(function(jqxhr, status, error) { req.reject(jqxhr, status, error); });
|
||||||
|
ajaxreq.always(db_ajax_request_complete);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry"></script>
|
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry"></script>
|
||||||
<script type="text/javascript" src="config.js"></script>
|
<script type="text/javascript" src="config.js"></script>
|
||||||
<script type="text/javascript" src="markers.js"></script>
|
<script type="text/javascript" src="markers.js"></script>
|
||||||
|
<script type="text/javascript" src="dbloader.js"></script>
|
||||||
<script type="text/javascript" src="planeObject.js"></script>
|
<script type="text/javascript" src="planeObject.js"></script>
|
||||||
<script type="text/javascript" src="formatter.js"></script>
|
<script type="text/javascript" src="formatter.js"></script>
|
||||||
<script type="text/javascript" src="script.js"></script>
|
<script type="text/javascript" src="script.js"></script>
|
||||||
|
@ -114,6 +115,8 @@
|
||||||
<span id="selected_icao"></span>
|
<span id="selected_icao"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<span id="selected_registration"></span>
|
||||||
|
<span id="selected_icaotype"></span>
|
||||||
<span id="selected_emergency"></span>
|
<span id="selected_emergency"></span>
|
||||||
<span id="selected_links">
|
<span id="selected_links">
|
||||||
<a id="selected_fr24_link" href="" target="_blank">[FR24]</a>
|
<a id="selected_fr24_link" href="" target="_blank">[FR24]</a>
|
||||||
|
|
|
@ -36,6 +36,23 @@ function PlaneObject(icao) {
|
||||||
this.marker = null;
|
this.marker = null;
|
||||||
this.icon = { type: 'generic',
|
this.icon = { type: 'generic',
|
||||||
fillOpacity: 0.9 };
|
fillOpacity: 0.9 };
|
||||||
|
|
||||||
|
// request metadata
|
||||||
|
this.registration = null;
|
||||||
|
this.icaotype = null;
|
||||||
|
getAircraftData(this.icao).done(function(data) {
|
||||||
|
if ("r" in data) {
|
||||||
|
this.registration = data.r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("t" in data) {
|
||||||
|
this.icaotype = data.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selected) {
|
||||||
|
refreshSelected();
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends data to the running track so we can get a visual tail on the plane
|
// Appends data to the running track so we can get a visual tail on the plane
|
||||||
|
|
|
@ -554,7 +554,19 @@ function refreshSelected() {
|
||||||
$('#selected_callsign').text('n/a');
|
$('#selected_callsign').text('n/a');
|
||||||
$('#selected_links').css('display','none');
|
$('#selected_links').css('display','none');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selected.registration !== null) {
|
||||||
|
$('#selected_registration').text(selected.registration);
|
||||||
|
} else {
|
||||||
|
$('#selected_registration').text("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.icaotype !== null) {
|
||||||
|
$('#selected_icaotype').text(selected.icaotype);
|
||||||
|
} else {
|
||||||
|
$('#selected_icaotype').text("");
|
||||||
|
}
|
||||||
|
|
||||||
var emerg = document.getElementById('selected_emergency');
|
var emerg = document.getElementById('selected_emergency');
|
||||||
if (selected.squawk in SpecialSquawks) {
|
if (selected.squawk in SpecialSquawks) {
|
||||||
emerg.className = SpecialSquawks[selected.squawk].cssClass;
|
emerg.className = SpecialSquawks[selected.squawk].cssClass;
|
||||||
|
|
|
@ -34,6 +34,8 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right:
|
||||||
.infoblock_body { font-size: small; }
|
.infoblock_body { font-size: small; }
|
||||||
|
|
||||||
#selected_icao { font-size: x-small; }
|
#selected_icao { font-size: x-small; }
|
||||||
|
#selected_registration { font-size: x-small; }
|
||||||
|
#selected_icaotype { font-size: x-small; }
|
||||||
|
|
||||||
.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
|
.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
|
||||||
|
|
||||||
|
|
66
tools/vrs-basicaircraft-to-json.py
Executable file
66
tools/vrs-basicaircraft-to-json.py
Executable file
|
@ -0,0 +1,66 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
#
|
||||||
|
# Converts a Virtual Radar Server BasicAircraftLookup.sqb database
|
||||||
|
# into a bunch of json files suitable for use by the webmap
|
||||||
|
#
|
||||||
|
|
||||||
|
import sqlite3, json
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
|
def extract(dbfile, todir, blocklimit):
|
||||||
|
ac_count = 0
|
||||||
|
block_count = 0
|
||||||
|
|
||||||
|
blocks = {}
|
||||||
|
for i in xrange(16):
|
||||||
|
blocks['%01X' % i] = {}
|
||||||
|
|
||||||
|
print 'Reading', dbfile
|
||||||
|
with closing(sqlite3.connect(dbfile)) as db:
|
||||||
|
with closing(db.execute('SELECT a.Icao, a.Registration, m.Icao FROM Aircraft a, Model m WHERE a.ModelID = m.ModelID')) as c:
|
||||||
|
for icao24, reg, icaotype in c:
|
||||||
|
bkey = icao24[0:1].upper()
|
||||||
|
dkey = icao24[1:].upper()
|
||||||
|
blocks[bkey][dkey] = {}
|
||||||
|
if reg: blocks[bkey][dkey]['r'] = reg
|
||||||
|
if icaotype: blocks[bkey][dkey]['t'] = icaotype
|
||||||
|
ac_count += 1
|
||||||
|
print 'Read', ac_count, 'aircraft'
|
||||||
|
|
||||||
|
queue = list(blocks.keys())
|
||||||
|
while queue:
|
||||||
|
bkey = queue[0]
|
||||||
|
del queue[0]
|
||||||
|
|
||||||
|
blockdata = blocks[bkey]
|
||||||
|
if len(blockdata) > blocklimit:
|
||||||
|
print 'Splitting block', bkey, 'with', len(blockdata), 'entries..',
|
||||||
|
children = {}
|
||||||
|
for dkey in blockdata.keys():
|
||||||
|
new_bkey = bkey + dkey[0]
|
||||||
|
new_dkey = dkey[1:]
|
||||||
|
|
||||||
|
if new_bkey not in children: blocks[new_bkey] = children[new_bkey] = {}
|
||||||
|
children[new_bkey][new_dkey] = blockdata[dkey]
|
||||||
|
|
||||||
|
print len(children), 'children'
|
||||||
|
queue.extend(children.keys())
|
||||||
|
blockdata = blocks[bkey] = { 'children' : sorted(children.keys()) }
|
||||||
|
|
||||||
|
path = todir + '/' + bkey + '.json'
|
||||||
|
print 'Writing', len(blockdata), 'entries to', path
|
||||||
|
block_count += 1
|
||||||
|
with closing(open(path, 'w')) as f:
|
||||||
|
json.dump(obj=blockdata, fp=f, check_circular=False, separators=(',',':'), sort_keys=True)
|
||||||
|
|
||||||
|
print 'Wrote', block_count, 'blocks'
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print 'Syntax: %s <path to BasicAircraftLookup.sqb> <path to DB dir>' % sys.argv[0]
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
extract(sys.argv[1], sys.argv[2], 1000)
|
||||||
|
sys.exit(0)
|
Loading…
Reference in a new issue