diff --git a/server/data/aircraft.db b/server/data/aircraft.db index c817ec7..d050ed6 100644 Binary files a/server/data/aircraft.db and b/server/data/aircraft.db differ diff --git a/server/src/adsb.mjs b/server/src/adsb.mjs index 9376234..b0bcca7 100644 --- a/server/src/adsb.mjs +++ b/server/src/adsb.mjs @@ -13,56 +13,72 @@ const SHAPES_PATH = resolve(DATA, 'shapes.json'); const history = new Map(); const MAX_HISTORY = 500; -const CSV_URL = 'https://s3.opensky-network.org/data-samples/metadata/aircraft-database-complete-2024-06.csv'; -const MIL_RANGES_URL = ':8080/db-3.14.1707/ranges.js'; +const CSV_URL = 'https://s3.opensky-network.org/data-samples/metadata/aircraft-database-complete-2024-06.csv'; +const MIL_RANGES_URL = ':8080/db-3.14.1708/ranges.js'; const MILITARY_OPERATORS = ['air force', 'army', 'navy', 'marine', 'coast guard', 'military', 'defence', 'defense', 'luftwaffe', 'RAF', 'USAF', 'USN', 'USMC']; const CARGO_OPERATORS = ['fedex', 'ups', 'dhl', 'cargo', 'freight', 'logistic', 'atlas air', 'kalitta', 'air freight']; const PASSENGER_OPERATORS = ['airlines', 'airways', 'air ', 'jet', 'easyjet', 'ryanair', 'delta', 'united', 'american', 'southwest', 'lufthansa', 'emirates', 'british']; const MILITARY_CLASSES = ['H1M', 'H2M', 'L1M', 'L2M', 'L4M', 'A0']; +const milRanges = []; let db; +async function syncMilitaryRanges() { + const { ADSB_URL } = cfg(); + try { + const res = await fetch(ADSB_URL + MIL_RANGES_URL); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const { military } = await res.json(); + + db.exec('DELETE FROM military_ranges'); + const insert = db.prepare('INSERT INTO military_ranges (start, end) VALUES (?, ?)'); + const insertMany = db.transaction(ranges => { + for (const [s, e] of ranges) insert.run(s.toUpperCase(), e.toUpperCase()); + }); + + insertMany(military); + milRanges.length = 0; + milRanges.push(...military.map(([s, e]) => [s.toUpperCase(), e.toUpperCase()])); + } catch (e) { + const rows = db.prepare('SELECT start, end FROM military_ranges').all(); + milRanges.length = 0; + milRanges.push(...rows.map(r => [r.start, r.end])); + } +} + export async function initAircraftDb() { if (!fs.existsSync(DATA)) fs.mkdirSync(DATA, { recursive: true }); const missing = !fs.existsSync(DB_PATH); - if(missing) console.log(`✈️ Building database`); + if (missing) console.log(`✈️ Building database`); db = new Database(DB_PATH); db.exec(` CREATE TABLE IF NOT EXISTS aircraft ( - icao24 TEXT PRIMARY KEY, - built TEXT, - categoryDescription TEXT, - country TEXT, - engines TEXT, - class TEXT, - manufacturer TEXT, - model TEXT, - modes TEXT, - operator TEXT, - operatorCallsign TEXT, - owner TEXT, - registration TEXT, - serialNumber TEXT, - aircraft TEXT + icao24 TEXT PRIMARY KEY, + built TEXT, + categoryDescription TEXT, + country TEXT, + engines TEXT, + class TEXT, + manufacturer TEXT, + model TEXT, + modes TEXT, + operator TEXT, + operatorCallsign TEXT, + owner TEXT, + registration TEXT, + serialNumber TEXT, + aircraft TEXT ); CREATE TABLE IF NOT EXISTS military_ranges ( - start TEXT NOT NULL, - end TEXT NOT NULL + start TEXT NOT NULL, + end TEXT NOT NULL ); - `); + `); - // Always refresh military ranges on startup - const { ADSB_URL } = cfg(); - const res = await fetch(ADSB_URL + MIL_RANGES_URL); - if (!res.ok) throw new Error(`Failed to fetch military ranges: HTTP ${res.status}`); - const { military } = await res.json(); - db.exec('DELETE FROM military_ranges'); - const insertRange = db.prepare('INSERT INTO military_ranges (start, end) VALUES (?, ?)'); - const insertRanges = db.transaction(ranges => { for (const [s, e] of ranges) insertRange.run(s.toUpperCase(), e.toUpperCase()); }); - insertRanges(military); + await syncMilitaryRanges(); if (missing) { const res = await fetch(CSV_URL); @@ -77,7 +93,7 @@ export async function initAircraftDb() { @class, @manufacturer, @model, @modes, @operator, @operatorCallsign, @owner, @registration, @serialNumber, @aircraft ) - `); + `); const insertMany = db.transaction(rows => { for (const row of rows) insert.run(row); @@ -112,8 +128,7 @@ export async function initAircraftDb() { function isIcaoInMilitaryRange(icao) { if (!icao) return false; const hex = icao.toUpperCase(); - const match = db.prepare('SELECT 1 FROM military_ranges WHERE start <= ? AND end >= ? LIMIT 1').get(hex, hex); - return !!match; + return milRanges.some(([s, e]) => hex >= s && hex <= e); } function wordMatch(text, keyword) {