-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
It's all broken - trust nothing. But at least its not on my laptop an…
…ymore
- Loading branch information
Showing
15 changed files
with
24,935 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
npm-debug.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
FROM node:14 | ||
|
||
# Create app directory | ||
WORKDIR /usr/src/app | ||
|
||
# Install app dependencies | ||
# A wildcard is used to ensure both package.json AND package-lock.json are copied | ||
# where available (npm@5+) | ||
COPY package*.json ./ | ||
|
||
RUN npm install | ||
# If you are building your code for production | ||
# RUN npm ci --only=production | ||
|
||
# Bundle app source | ||
COPY . . | ||
|
||
EXPOSE 8080 | ||
CMD [ "node", "server.js" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
## TODO | ||
|
||
## Future | ||
Show ATC polys and state from controllers API | ||
|
||
### Current stats | ||
In FIR now | ||
|
||
### Stored stats | ||
Traffic heatmap (DB needed) | ||
|
||
## Credits | ||
CC BY-SA 3.0 | ||
https://commons.wikimedia.org/wiki/File:Plane_font_awesome.svg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import * as turf from '@turf/turf' | ||
import { xml2js } from 'xml-js'; | ||
import dms2dec from 'dms2dec'; | ||
import fs from 'fs'; | ||
import fetch from 'node-fetch'; | ||
import NodeCache from 'node-cache'; | ||
|
||
const cache = new NodeCache( { stdTTL: 15, checkperiod: 30 } ); | ||
|
||
export function clearCache(){ | ||
console.log('Clearing cache') | ||
cache.flushAll(); | ||
return true; | ||
} | ||
|
||
export async function getPilots(){ | ||
console.log(cache.getStats()); | ||
try{ | ||
var firs = await getFIRBoundaries('https://raw.githubusercontent.com/vatSys/australia-dataset/master/Maps/FIR_BOUNDARIES.xml'); | ||
firLineToPoly(firs); | ||
var vatsimData = await getVatsimData('https://data.vatsim.net/v3/vatsim-data.json'); | ||
}catch(err){ | ||
console.log(err) | ||
return false; | ||
} | ||
try{ | ||
return pilotsInFIR(firs, vatsimData); | ||
}catch(err){ | ||
console.log(err) | ||
return false; | ||
} | ||
} | ||
|
||
function pilotsInFIR(fir, data){ | ||
var pilotsInFIR = []; | ||
data.pilots.forEach(function(pilot) { | ||
var ppos = turf.point( | ||
[(pilot.longitude), (pilot.latitude)], | ||
{ pilot } | ||
); | ||
if(pointInFIR(ppos, fir) == true){ | ||
pilotsInFIR.push(ppos); | ||
} | ||
}); | ||
return turf.featureCollection(pilotsInFIR); | ||
} | ||
|
||
function checkHTTPStatus(res) { | ||
if (res.ok) { // res.status >= 200 && res.status < 300 | ||
return res; | ||
} else { | ||
throw HTTPError(res.statusText); | ||
} | ||
} | ||
|
||
async function getVatsimData (url) { | ||
var data = cache.get("vatsimData"); | ||
if (data == undefined) { | ||
console.log("getVatsimData cache miss") | ||
const res = await fetch(url) | ||
.then(checkHTTPStatus) | ||
.then(res => res.json()) | ||
.then( data => { | ||
return data; | ||
}) | ||
.catch(err => console.log(err)); | ||
data = res; | ||
console.log(`Cached vatsimData len ${Object.keys(data).length}`) | ||
cache.set("vatsimData", data, 15); | ||
}else{ | ||
console.log(`vatsimData len ${Object.keys(data).length}`) | ||
console.log("getVatsimData cache hit") | ||
} | ||
return data; | ||
} | ||
|
||
async function getFIRBoundaries (url) { | ||
// Extract vatSys firObjs into line arrays | ||
var firObjs = []; | ||
let xml; | ||
var data = cache.get("xml"); | ||
if (data == undefined) { | ||
console.log("getFIRBoundaries cache miss") | ||
try{ | ||
// Download and parse XML | ||
const res = await fetch(url) | ||
.then(checkHTTPStatus) | ||
.then(res => res.text()) | ||
.then( data => { | ||
return data; | ||
}) | ||
.catch(err => console.log(err)); | ||
xml = await xml2js(res, {compact: true, spaces: 4}); | ||
}catch(err){ | ||
throw ParserError(err); | ||
} | ||
|
||
// Handle single Line Map | ||
if(Array.isArray(xml.Maps.Map.Line)){ | ||
xml.Maps.Map.Line.forEach(function (line){ | ||
firObjs.push(lineToFIR(line)) | ||
}); | ||
}else{ | ||
firObjs.push(lineToFIR(xml.Maps.Map.Line)) | ||
} | ||
console.log(`Cached firObjs len ${firObjs.length}`) | ||
cache.set("xml", firObjs, 86400); | ||
}else{ | ||
console.log(`firObjs len ${firObjs.length}`) | ||
console.log("getFIRBoundaries cache hit") | ||
} | ||
return firObjs; | ||
} | ||
|
||
function firLineToPoly (firs) { | ||
// Line arrays into turf polys | ||
firs.forEach(function(fir){ | ||
var poly = turf.lineToPolygon(turf.lineString(fir.line),{mutate: true}); | ||
fir.poly = poly; | ||
// Dump GeoJSON poly for debugging in https://geojson.io | ||
// console.log(JSON.stringify(poly, null, 1)); | ||
// fs.writeFile(`./out/${fir.name}.json`, JSON.stringify(poly, null, 1), 'utf8', function(err) { | ||
// if (err) throw err; | ||
// console.log(`./out/${fir.name}.json`); | ||
// } | ||
// ); | ||
}); | ||
return firs; | ||
} | ||
|
||
function lineToFIR (line) { | ||
// Create new JS obj | ||
var fir = { | ||
name: line._attributes.Name, | ||
line: [], | ||
poly: null | ||
} | ||
// Take vatSys lines and parse into line array | ||
// ±DDMMSS.SSSS±DDDMMSS.SSSS | ||
// (?<latD>[+-][0-9]{2})(?<latM>[0-9]{2})(?<latS>[0-9]{2}\.[0-9]{3})(?<lonD>[+-][0-9]{3})(?<lonM>[0-9]{2})(?<lonS>[0-9]{2}\.[0-9]{3}) | ||
// const re = new RegExp(/(?<lat>[+-][0-9]{6}\.[0-9]{3})(?<lon>[+-][0-9]{7}\.[0-9]{3})/g); | ||
const re = new RegExp(/(?<latRef>[+-])(?<latD>[0-9]{2})(?<latM>[0-9]{2})(?<latS>[0-9]{2}\.[0-9]{3})(?<lonRef>[+-])(?<lonD>[0-9]{3})(?<lonM>[0-9]{2})(?<lonS>[0-9]{2}\.[0-9]{3})/g) | ||
var lines = [...line._text.matchAll(re)]; | ||
lines.forEach(function(l){ | ||
// Convert vaySys DMS into decimal degrees | ||
// https://github.com/vatSys/xml-tools/blob/master/DotAIPtoXML/DotAIPtoXML/Coordinate.cs#L119 | ||
var pos = { | ||
latitude: [ | ||
parseInt(l.groups.latD), | ||
parseInt(l.groups.latM), | ||
parseFloat(l.groups.latS) | ||
], | ||
latRef: (l.groups.latRef == '+') ? "N" : "S", | ||
longitude: [ | ||
parseInt(l.groups.lonD), | ||
parseInt(l.groups.lonM), | ||
parseFloat(l.groups.lonS) | ||
], | ||
lonRef: (l.groups.lonRef == '+') ? "E" : "W" | ||
} | ||
var [ latitude, longitude ] = dms2dec(pos.latitude,pos.latRef,pos.longitude,pos.lonRef); | ||
// Turf is geoJSON so we continue the stupidity here with long THEN lat. | ||
var a = [longitude, latitude] | ||
// Append extract arrays to fir.line array | ||
fir.line.push(a); | ||
}); | ||
return fir | ||
}; | ||
|
||
// Flights in FIRs | ||
function pointInFIR (point, firs) { | ||
var mappedFIRs = [ "MELBOURNE_FIR", "BRISBANE_FIR" ]; | ||
var inFIR = false; | ||
firs.forEach(function(fir){ | ||
if(mappedFIRs.includes(fir.name)) { | ||
if(turf.booleanPointInPolygon(point,fir.poly)){ | ||
console.log(`Matched in ${fir.name}`) | ||
inFIR = true; | ||
} | ||
}; | ||
}); | ||
return inFIR; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Maps> | ||
<Map Type="System" Name="FIR_BDRY" Priority="2"> | ||
<Line Name="AUSBOX"> | ||
-092400.000+1605400.000 | ||
-430000.000+1605400.000 | ||
-430000.000+0990000.000 | ||
-092400.000+0990000.000 | ||
-092400.000+1605400.000 | ||
</Line> | ||
</Map> | ||
</Maps> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
{ | ||
"general": { | ||
"version": 3, | ||
"reload": 1, | ||
"update": "20210720122320", | ||
"update_timestamp": "2021-07-20T12:23:20.5674914Z", | ||
"connected_clients": 740, | ||
"unique_users": 706 | ||
}, | ||
"pilots": [ | ||
{ | ||
"cid": 1524202, | ||
"name": "TEST 1", | ||
"callsign": "TEST-FALSE", | ||
"server": "GERMANY-1", | ||
"pilot_rating": 0, | ||
"latitude": -22.77579, | ||
"longitude": -60.05077, | ||
"altitude": 37313, | ||
"groundspeed": 484, | ||
"transponder": "1572", | ||
"heading": 227, | ||
"qnh_i_hg": 30.23, | ||
"qnh_mb": 1024, | ||
"flight_plan": { | ||
"flight_rules": "I", | ||
"aircraft": "H/B78X/B", | ||
"aircraft_faa": "H/B78X/B", | ||
"aircraft_short": "B78X", | ||
"departure": "LIRF", | ||
"arrival": "SCEL", | ||
"alternate": "EHAM", | ||
"cruise_tas": "557", | ||
"altitude": "40000", | ||
"deptime": "1603", | ||
"enroute_time": "1420", | ||
"fuel_time": "1030", | ||
"remarks": "MSFS DEFAULT GPS. ONLY TEXT ON GROUND USING PACX WITH BOARDING MUSIC. /V/", | ||
"route": "LIRF/NENI6W RF601 RF603 RF609 RF711 NENIG GILIO SUXER LABRO ARI FES NEVEK ERLAM TIXAL VALBA OBOGA MAK LISRA BIDLA OLOMA ADM TEKNA AMLOK SOLNA LAY BIPET IPERA NEMDO SVT AMDOL DIGUN 0535N DAKAP 0140W MICRO ENRUS RODOT XVT TOSAR DIKAX ATERU UMSIL DAKBU ESDER REMEK NEKAN ILPUR EGEXO AKNEL GETRA VINOS QUILI UBRIX ENVOK SIMKOK TBN60 MOLPU D358X D358P UGANO TBN PUMAR IUE15 TEGEB SCEL/ANDES8/17L", | ||
"revision_id": 11 | ||
}, | ||
"logon_time": "2021-07-19T17:04:22.5391994Z", | ||
"last_updated": "2021-07-20T12:23:17.4437642Z" | ||
}, | ||
{ | ||
"cid": 1524202, | ||
"name": "TEST 2", | ||
"callsign": "TEST-TRUE", | ||
"server": "GERMANY-1", | ||
"pilot_rating": 0, | ||
"latitude": -26.0000, | ||
"longitude": 138.6500, | ||
"altitude": 37313, | ||
"groundspeed": 484, | ||
"transponder": "1572", | ||
"heading": 227, | ||
"qnh_i_hg": 30.23, | ||
"qnh_mb": 1024, | ||
"flight_plan": { | ||
"flight_rules": "I", | ||
"aircraft": "H/B78X/B", | ||
"aircraft_faa": "H/B78X/B", | ||
"aircraft_short": "B78X", | ||
"departure": "LIRF", | ||
"arrival": "SCEL", | ||
"alternate": "EHAM", | ||
"cruise_tas": "557", | ||
"altitude": "40000", | ||
"deptime": "1603", | ||
"enroute_time": "1420", | ||
"fuel_time": "1030", | ||
"remarks": "MSFS DEFAULT GPS. ONLY TEXT ON GROUND USING PACX WITH BOARDING MUSIC. /V/", | ||
"route": "LIRF/NENI6W RF601 RF603 RF609 RF711 NENIG GILIO SUXER LABRO ARI FES NEVEK ERLAM TIXAL VALBA OBOGA MAK LISRA BIDLA OLOMA ADM TEKNA AMLOK SOLNA LAY BIPET IPERA NEMDO SVT AMDOL DIGUN 0535N DAKAP 0140W MICRO ENRUS RODOT XVT TOSAR DIKAX ATERU UMSIL DAKBU ESDER REMEK NEKAN ILPUR EGEXO AKNEL GETRA VINOS QUILI UBRIX ENVOK SIMKOK TBN60 MOLPU D358X D358P UGANO TBN PUMAR IUE15 TEGEB SCEL/ANDES8/17L", | ||
"revision_id": 11 | ||
}, | ||
"logon_time": "2021-07-19T17:04:22.5391994Z", | ||
"last_updated": "2021-07-20T12:23:17.4437642Z" | ||
} | ||
]} |
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.