Input handling and general cleanup

This commit is contained in:
30hours 2024-03-17 07:56:53 +00:00
parent 2ac180714e
commit ad19fe9754
11 changed files with 129 additions and 38 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
**/__pycache__/ **/__pycache__/
save/

View file

@ -13,4 +13,4 @@ EXPOSE 5000
ENV FLASK_APP=api.py ENV FLASK_APP=api.py
# run Gunicorn instead of the default Flask development server # run Gunicorn instead of the default Flask development server
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--timeout", "60", "main:app"] CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--timeout", "60", "api:app"]

View file

@ -9,21 +9,32 @@ import os
import requests import requests
import time import time
import asyncio import asyncio
import yaml
from common.Message import Message from common.Message import Message
app = Flask(__name__) app = Flask(__name__)
# init config file
try:
with open('config/config.yml', 'r') as file:
config = yaml.safe_load(file)
radar_data = config['radar']
except FileNotFoundError:
print("Error: Configuration file not found.")
except yaml.YAMLError as e:
print("Error reading YAML configuration:", e)
# store state data # store state data
servers = [ servers = []
{"name": "radar4", "url": "radar4.30hours.dev"}, for radar in radar_data:
{"name": "radar5", "url": "radar5.30hours.dev"}, if radar['name'] and radar['url']:
{"name": "radar6", "url": "radar6.30hours.dev"} servers.append({'name': radar['name'], 'url': radar['url']})
]
associators = [ associators = [
{"name": "ADSB Associator", "id": "adsb-associator"} {"name": "ADSB Associator", "id": "adsb-associator"}
] ]
# todo: ellipse conic int (analytic), SX, arc length
localisations = [ localisations = [
{"name": "Ellipse Parametric (Mean)", "id": "ellipse-parametric-mean"}, {"name": "Ellipse Parametric (Mean)", "id": "ellipse-parametric-mean"},
{"name": "Ellipse Parametric (Min)", "id": "ellipse-parametric-min"}, {"name": "Ellipse Parametric (Min)", "id": "ellipse-parametric-min"},
@ -31,11 +42,19 @@ localisations = [
{"name": "Ellipsoid Parametric (Min)", "id": "ellipsoid-parametric-min"}, {"name": "Ellipsoid Parametric (Min)", "id": "ellipsoid-parametric-min"},
{"name": "Spherical Intersection", "id": "spherical-intersection"} {"name": "Spherical Intersection", "id": "spherical-intersection"}
] ]
adsbs = [ adsbs = [
{"name": "adsb.30hours.dev", "url": "adsb.30hours.dev"}, {"name": "adsb.30hours.dev", "url": "adsb.30hours.dev"},
{"name": "None", "url": ""} {"name": "None", "url": ""}
] ]
# store valid ids
valid = {}
valid['servers'] = [item['url'] for item in servers]
valid['associators'] = [item['id'] for item in associators]
valid['localisations'] = [item['id'] for item in localisations]
valid['adsbs'] = [item['url'] for item in adsbs]
# message received callback # message received callback
async def callback_message_received(msg): async def callback_message_received(msg):
print(f"Callback: Received message in main.py: {msg}", flush=True) print(f"Callback: Received message in main.py: {msg}", flush=True)
@ -58,6 +77,20 @@ def serve_static(file):
@app.route("/api") @app.route("/api")
def api(): def api():
api = request.query_string.decode('utf-8') api = request.query_string.decode('utf-8')
# input protection
servers_api = request.args.getlist('server')
associators_api = request.args.getlist('associator')
localisations_api = request.args.getlist('localisation')
adsbs_api = request.args.getlist('adsb')
if not all(item in valid['servers'] for item in servers_api):
return 'Invalid server'
if not all(item in valid['associators'] for item in associators_api):
return 'Invalid associator'
if not all(item in valid['localisations'] for item in localisations_api):
return 'Invalid localisation'
if not all(item in valid['adsbs'] for item in adsbs_api):
return 'Invalid ADSB']
# send to event handler
try: try:
reply_chunks = message_api_request.send_message(api) reply_chunks = message_api_request.send_message(api)
reply = ''.join(reply_chunks) reply = ''.join(reply_chunks)

View file

@ -179,6 +179,27 @@ if (cesiumCredit) {
return pointEntity; return pointEntity;
} }
function is_localhost(ip) {
if (ip === 'localhost') {
return true;
}
ip = ip.replace(/^https?:\/\//, "");
const localRanges = ['127.0.0.1', '192.168.0.0/16', '10.0.0.0/8', '172.16.0.0/12'];
const ipToInt = ip => ip.split('.').reduce((acc, octet) => (acc << 8) + +octet, 0) >>> 0;
return localRanges.some(range => {
const [rangeStart, rangeSize = 32] = range.split('/');
const start = ipToInt(rangeStart);
const end = (start | (1 << (32 - +rangeSize))) >>> 0;
return ipToInt(ip) >= start && ipToInt(ip) <= end;
});
}
// global vars // global vars
var adsb_url; var adsb_url;
var adsbEntities = {}; var adsbEntities = {};
@ -193,13 +214,14 @@ window.addEventListener('load', function () {
// add radar points // add radar points
const radar_names = new URLSearchParams( const radar_names = new URLSearchParams(
window.location.search).getAll('server'); window.location.search).getAll('server');
console.log(radar_names);
var radar_config_url = radar_names.map( var radar_config_url = radar_names.map(
url => `http://${url}/api/config`); url => `http://${url}/api/config`);
if (this.window.location.protocol === "https:") { radar_config_url.forEach(function(url) {
radar_config_url = radar_config_url.map( if (!is_localhost(url)) {
radar_config_url = radar_config_url.map(
url => url.replace(/^http:/, 'https:')); url => url.replace(/^http:/, 'https:'));
} }
});
var style_radar = {}; var style_radar = {};
style_radar.color = 'rgba(0, 0, 0, 1.0)'; style_radar.color = 'rgba(0, 0, 0, 1.0)';
style_radar.pointSize = 10; style_radar.pointSize = 10;
@ -241,19 +263,16 @@ window.addEventListener('load', function () {
} }
}) })
.catch(error => { .catch(error => {
// Handle errors during fetch
console.error('Error during fetch:', error); console.error('Error during fetch:', error);
}); });
}); });
// get detection data URL
// get truth URL // get truth URL
adsb_url = new URLSearchParams( adsb_url = new URLSearchParams(
window.location.search).get('adsb').split('&'); window.location.search).get('adsb').split('&');
adsb_url = adsb_url.map( adsb_url = adsb_url.map(
url => `http://${url}/data/aircraft.json`); url => `http://${url}/data/aircraft.json`);
if (this.window.location.protocol === "https:") { if (!is_localhost(adsb_url[0])) {
adsb_url = adsb_url.map( adsb_url = adsb_url.map(
url => url.replace(/^http:/, 'https:')); url => url.replace(/^http:/, 'https:'));
} }

View file

@ -1,3 +1,4 @@
Flask==3.0.1 Flask==3.0.1
gunicorn==21.2.0 gunicorn==21.2.0
requests==2.31.0 requests==2.31.0
PyYAML==6.0.1

26
config/config.yml Normal file
View file

@ -0,0 +1,26 @@
radar:
- name: radar4
url: radar4.30hours.dev
- name: radar5
url: radar5.30hours.dev
- name: radar6
url: radar6.30hours.dev
associate:
adsb:
tar1090: 'adsb.30hours.dev'
tDelete: 5
localisation:
ellipse:
nSamples: 100
threshold: 500
nDisplay: 50
ellipsoid:
nSamples: 60
threshold: 500
nDisplay: 50
3lips:
save: true
tDelete: 60

View file

@ -16,6 +16,7 @@ services:
networks: networks:
- 3lips - 3lips
volumes: volumes:
- ./config:/app/config
- ./common:/app/common - ./common:/app/common
container_name: 3lips-api container_name: 3lips-api
@ -28,6 +29,7 @@ services:
networks: networks:
- 3lips - 3lips
volumes: volumes:
- ./config:/app/config
- ./common:/app/common - ./common:/app/common
- ./test:/app/test - ./test:/app/test
- ./save:/app/save - ./save:/app/save

View file

@ -49,15 +49,11 @@ class EllipseParametric:
for target in assoc_detections: for target in assoc_detections:
print(target, flush=True)
target_samples = {} target_samples = {}
target_samples[target] = {} target_samples[target] = {}
for radar in assoc_detections[target]: for radar in assoc_detections[target]:
print(radar["radar"], flush=True)
print(radar["delay"], flush=True)
# create ellipsoid for radar # create ellipsoid for radar
ellipsoid = next(( ellipsoid = next((
item for item in self.ellipsoids item for item in self.ellipsoids

View file

@ -46,15 +46,11 @@ class EllipsoidParametric:
for target in assoc_detections: for target in assoc_detections:
print(target, flush=True)
target_samples = {} target_samples = {}
target_samples[target] = {} target_samples[target] = {}
for radar in assoc_detections[target]: for radar in assoc_detections[target]:
print(radar["radar"], flush=True)
print(radar["delay"], flush=True)
# create ellipsoid for radar # create ellipsoid for radar
ellipsoid = next(( ellipsoid = next((
item for item in self.ellipsoids item for item in self.ellipsoids
@ -142,9 +138,6 @@ class EllipsoidParametric:
output[target] = {} output[target] = {}
output[target]["points"] = [] output[target]["points"] = []
print('test', flush=True)
print(samples_intersect, flush=True)
for i in range(len(samples_intersect)): for i in range(len(samples_intersect)):
samples_intersect[i] = Geometry.ecef2lla( samples_intersect[i] = Geometry.ecef2lla(
samples_intersect[i][0], samples_intersect[i][0],

View file

@ -13,6 +13,7 @@ import copy
import json import json
import hashlib import hashlib
import os import os
import yaml
from algorithm.associator.AdsbAssociator import AdsbAssociator from algorithm.associator.AdsbAssociator import AdsbAssociator
from algorithm.localisation.EllipseParametric import EllipseParametric from algorithm.localisation.EllipseParametric import EllipseParametric
@ -23,19 +24,36 @@ from common.Message import Message
from data.Ellipsoid import Ellipsoid from data.Ellipsoid import Ellipsoid
from algorithm.geometry.Geometry import Geometry from algorithm.geometry.Geometry import Geometry
# init config file
try:
with open('config/config.yml', 'r') as file:
config = yaml.safe_load(file)
nSamplesEllipse = config['localisation']['ellipse']['nSamples']
thresholdEllipse = config['localisation']['ellipse']['threshold']
nDisplayEllipse = config['localisation']['ellipse']['nDisplay']
nSamplesEllipsoid = config['localisation']['ellipsoid']['nSamples']
thresholdEllipsoid = config['localisation']['ellipsoid']['threshold']
nDisplayEllipsoid = config['localisation']['ellipsoid']['nDisplay']
tDeleteAdsb = config['associate']['adsb']['tDelete']
save = config['3lips']['save']
tDelete = config['3lips']['tDelete']
except FileNotFoundError:
print("Error: Configuration file not found.")
except yaml.YAMLError as e:
print("Error reading YAML configuration:", e)
# init event loop # init event loop
api = [] api = []
# init config # init config
tDelete = 60 tDelete = tDelete
adsbAssociator = AdsbAssociator() adsbAssociator = AdsbAssociator()
ellipseParametricMean = EllipseParametric("mean", 150, 500) ellipseParametricMean = EllipseParametric("mean", nSamplesEllipse, thresholdEllipse)
ellipseParametricMin = EllipseParametric("min", 150, 500) ellipseParametricMin = EllipseParametric("min", nSamplesEllipse, thresholdEllipse)
ellipsoidParametricMean = EllipsoidParametric("mean", 60, 800) ellipsoidParametricMean = EllipsoidParametric("mean", nSamplesEllipsoid, thresholdEllipsoid)
ellipsoidParametricMin = EllipsoidParametric("min", 60, 800) ellipsoidParametricMin = EllipsoidParametric("min", nSamplesEllipsoid, thresholdEllipsoid)
sphericalIntersection = SphericalIntersection() sphericalIntersection = SphericalIntersection()
adsbTruth = AdsbTruth(5) adsbTruth = AdsbTruth(tDeleteAdsb)
save = True
saveFile = '/app/save/' + str(int(time.time())) + '.ndjson' saveFile = '/app/save/' + str(int(time.time())) + '.ndjson'
async def event(): async def event():
@ -139,6 +157,9 @@ async def event():
for key, value in associated_dets.items() for key, value in associated_dets.items()
if isinstance(value, list) and len(value) >= 3 if isinstance(value, list) and len(value) >= 3
} }
if associated_dets_3_radars:
print('Detections from 3 or more radars availble.')
print(associated_dets_3_radars)
associated_dets_2_radars = { associated_dets_2_radars = {
key: value key: value
for key, value in associated_dets.items() for key, value in associated_dets.items()
@ -176,7 +197,7 @@ async def event():
[x_rx, y_rx, z_rx], [x_rx, y_rx, z_rx],
radar["radar"] radar["radar"]
) )
points = localisation.sample(ellipsoid, radar["delay"]*1000, 50) points = localisation.sample(ellipsoid, radar["delay"]*1000, nDisplayEllipse)
for i in range(len(points)): for i in range(len(points)):
lat, lon, alt = Geometry.ecef2lla(points[i][0], points[i][1], points[i][2]) lat, lon, alt = Geometry.ecef2lla(points[i][0], points[i][1], points[i][2])
if item["localisation"] == "ellipsoid-parametric-mean" or \ if item["localisation"] == "ellipsoid-parametric-mean" or \
@ -239,8 +260,6 @@ def short_hash(input_string, length=10):
# message received callback # message received callback
async def callback_message_received(msg): async def callback_message_received(msg):
#print(f"Callback: Received message in event.py: {msg}", flush=True)
timestamp = int(time.time()*1000) timestamp = int(time.time()*1000)
# update timestamp if API entry exists # update timestamp if API entry exists

View file

@ -1,2 +1,3 @@
numpy==1.26.4 numpy==1.26.4
requests==2.31.0 requests==2.31.0
PyYAML==6.0.1