diff --git a/trackdirect-apache.dockerfile b/Dockerfile
similarity index 87%
rename from trackdirect-apache.dockerfile
rename to Dockerfile
index 44d045222378bbc71dca97e56354d60d5ee8f5c9..f948dd8ade4bb881ff089d965f2cab1bbda6d3dd 100644
--- a/trackdirect-apache.dockerfile
+++ b/Dockerfile
@@ -21,3 +21,7 @@ RUN chmod a+rx / && chmod a+rx -R /root
RUN chmod 777 /root/trackdirect/htdocs/public/symbols
RUN chmod 777 /root/trackdirect/htdocs/public/heatmaps
+VOLUME /root/trackdirect/config
+VOLUME /root/trackdirect/htdocs/public/heatmaps
+
+EXPOSE 80
diff --git a/aprsc.dockerfile b/aprsc.dockerfile
deleted file mode 100644
index da2e51c9cda8d9b4fe0540c63ee05de25b690db0..0000000000000000000000000000000000000000
--- a/aprsc.dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-FROM ubuntu:20.04
-
-RUN apt-get update && apt-get install -y \
- gnupg \
- && rm -rf /var/lib/apt/lists/*
-
-RUN printf "deb http://aprsc-dist.he.fi/aprsc/apt focal main" >> /etc/apt/sources.list
-RUN gpg --keyserver keyserver.ubuntu.com --recv C51AA22389B5B74C3896EF3CA72A581E657A2B8D
-RUN gpg --export C51AA22389B5B74C3896EF3CA72A581E657A2B8D | apt-key add -
-
-RUN apt-get update && apt-get install -y \
- aprsc \
- && rm -rf /var/lib/apt/lists/*
-
-EXPOSE 10152
-EXPOSE 14580
-EXPOSE 10155
-EXPOSE 14501
-
-WORKDIR /opt/aprsc
-USER aprsc
-
-CMD /opt/aprsc/sbin/aprsc -c /opt/aprsc/etc/aprsc.conf
diff --git a/config/aprsc.conf b/config/aprsc.conf
deleted file mode 100755
index 48d5927d5a10a43f1a8a4b2a21fb86698268a9dd..0000000000000000000000000000000000000000
--- a/config/aprsc.conf
+++ /dev/null
@@ -1,30 +0,0 @@
-# Note that server id and passcode needs to be changed
-ServerId MY-SERVER-ID
-PassCode 11111
-
-MyAdmin "My Name, MySignal"
-MyEmail me@domain.com
-
-disallow_unverified false
-RunDir data
-LogRotate 10 5
-UpstreamTimeout 15s
-ClientTimeout 48h
-
-Listen "Full feed" fullfeed tcp :: 10152
-Listen "Client-Defined Filters" igate tcp :: 14580
-Listen "Duplicate packets" dupefeed tcp :: 10155
-
-### Select aprs source (only one)
-Uplink "Core rotate" ro tcp rotate.aprs.net 10152
-#Uplink "Core rotate" ro tcp cwop.aprs.net 10152
-#Uplink "Core rotate" ro tcp aprs.glidernet.org 10152
-
-HTTPStatus 0.0.0.0 14501
-HTTPStatusOptions ShowEmail=1
-
-### Operator attention span qualification run ###########
-# After configuring the rest of the settings, remove this bad command
-# from the configuration file. It's here only to avoid starting the
-# server up accidentally with an invalid configuration.
-MagicBadness 42.7
diff --git a/config/trackdirect.ini b/config/trackdirect.ini
index 0a38d5e28f0ea18eaecbecf1736b81f87a6db73b..073c45edeb8c1114389a1f34a5fe6863161d684d 100644
--- a/config/trackdirect.ini
+++ b/config/trackdirect.ini
@@ -4,9 +4,9 @@
[website]
-title="APRS Track Direct"
-owner_name="Unknown"
-owner_email="no@name.com"
+title="Digipex Hub"
+owner_name="Jeffrey Phillips Freeman (WI2ARD)"
+owner_email="the@JeffreyFreeman.me"
;maptiler_key="<insert map key here if you want to activate maptiler for vector tiles>"
;google_key="<insert google key here if you want to activate google maps>"
@@ -32,18 +32,18 @@ coverage_percentile="95"
;; Basic database settings
;; If using docker, set host to "db"
-host="127.0.0.1"
-database="trackdirect"
+host="swarm-db-default-postgres.cjvkhc5ajvev.us-east-1.rds.amazonaws.com"
+database="digipex_hub"
;; If using docker, activate username and set to "root"
-;username="username"
-password="foobar"
+username="digipex_hub_user"
+password=""
port="5432"
;; Settings for the remover script
-days_to_save_position_data="10"
-days_to_save_station_data="30"
-days_to_save_weather_data="10"
-days_to_save_telemetry_data="10"
+days_to_save_position_data="10000"
+days_to_save_station_data="30000"
+days_to_save_weather_data="10000"
+days_to_save_telemetry_data="10000"
;; If this setting is enabled, OGN stations that we are not allowed to reveal the identity of will be given a random name similar to "UNKNOWN123"
;; If disabled we will drop all packets regarding stations that we should not reveal the identity of.
@@ -73,7 +73,7 @@ frequency_limit="0"
;; First APRS IS server for the websocket server to connect to.
;; Important: Please set up your own APRS IS server, do not use a public server.
;; If using docker, set aprs_host1 to "aprsc"
-aprs_host1="127.0.0.1"
+aprs_host1="igate.digipex.io"
aprs_port1="14580"
;; Important that you set the correct source, otherwise it might be handled incorrect
@@ -92,7 +92,7 @@ aprs_source_id1="1"
;; Allow time travel
;; Use this settings to disable/enable data requests with a time interval (this must be disabled for the OGN network)
-allow_time_travel="0"
+allow_time_travel="1"
;; Max default time in minutes (how old packets that will be included in the response)
;; This setting should be no more than 1440 for for the OGN network.
@@ -103,7 +103,7 @@ max_default_time="1440"
max_filter_time="1440"
;; Time in minutes until idle client is disconnected
-max_client_idle_time="60"
+max_client_idle_time="20160"
;; Max age in seconds for real time packets waiting to be sent to client (dropping packets if limit is excceded)
max_queued_realtime_packets="30"
@@ -112,7 +112,7 @@ max_queued_realtime_packets="30"
[collector0]
;; If using docker, set host to "aprsc"
-host="127.0.0.1"
+host="igate.digipex.io"
port_full="10152"
port_filtered="14580"
@@ -125,21 +125,21 @@ port_filtered="14580"
source_id="1"
;; Your callsign and passcode
-callsign="NOCALL"
-passcode="-1"
+callsign="DIGIHUB"
+passcode="31415"
;; Database inserts is done in batches
numbers_in_batch="50"
;; Packets received more frequently than the configured frequency limit will not be shown on map (limit is specified in seconds)
;; Set to "0" to disable the frequency limit (note that the limit must be 20s or more when receiving data from OGN network)).
-frequency_limit="5"
+frequency_limit="0"
;; If save_fast_packets is set to "0", packets that is received to frequently will not be saved (useful for OGN, but not recommended for APRS-IS).
save_fast_packets="1"
;; If detect_duplicates is set to "1" we will try to detect duplicates and ignore them.
-detect_duplicates="1"
+detect_duplicates="0"
;; Collector error log
error_log="~/trackdirect/server/log/collector.log"
diff --git a/db.dockerfile b/db.dockerfile
deleted file mode 100644
index 4d037867d41ea4f65c982eac29d00658f642c1d3..0000000000000000000000000000000000000000
--- a/db.dockerfile
+++ /dev/null
@@ -1,3 +0,0 @@
-FROM postgres
-COPY misc/database/tables/* /docker-entrypoint-initdb.d/
-VOLUME /var/lib/postgresql/data
diff --git a/docker-compose.yml b/docker-compose.yml
index ac2d8fd60fcb3497cbfb5d1ad921af1449008625..758c366f7d3f6758014da180153f988f3ea13622 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,60 +1,28 @@
version: "3.9"
services:
- aprsc:
- build:
- context: .
- dockerfile: aprsc.dockerfile
- ports:
- - "10152:10152"
- - "14580:14580"
- - "10155:10155"
- - "14501:14501"
- volumes:
- - $PWD/config/aprsc.conf:/opt/aprsc/etc/aprsc.conf
-
collector:
+ image: 'registry.qoto.org/digipex/hub:latest'
build:
context: .
- dockerfile: trackdirect-python.dockerfile
+ dockerfile: collector.dockerfile
volumes:
- $PWD/config/trackdirect.ini:/root/trackdirect/config/trackdirect.ini
- command: /root/trackdirect/server/scripts/collector.sh trackdirect.ini 0
- depends_on:
- - "db"
- - "aprsc"
websocket:
build:
context: .
- dockerfile: trackdirect-python.dockerfile
+ dockerfile: websocket.dockerfile
volumes:
- $PWD/config/trackdirect.ini:/root/trackdirect/config/trackdirect.ini
- command: /root/trackdirect/server/scripts/wsserver.sh trackdirect.ini
ports:
- "9000:9000"
- depends_on:
- - "db"
- - "aprsc"
web:
build:
context: .
- dockerfile: trackdirect-apache.dockerfile
+ dockerfile: web.dockerfile
volumes:
- $PWD/config/trackdirect.ini:/root/trackdirect/config/trackdirect.ini
- $PWD/heatmaps:/root/trackdirect/htdocs/public/heatmaps
ports:
- "80:80"
- depends_on:
- - "db"
-
- db:
- build:
- context: .
- dockerfile: db.dockerfile
- environment:
- POSTGRES_USER: root
- POSTGRES_PASSWORD: foobar
- POSTGRES_DB: trackdirect
- volumes:
- - $PWD/db:/var/lib/postgresql/data
diff --git a/misc/database/tables/01_map.sql b/misc/database/tables/01_map.sql
deleted file mode 100644
index 840056becd91d912189e88be33d88ccae29651ca..0000000000000000000000000000000000000000
--- a/misc/database/tables/01_map.sql
+++ /dev/null
@@ -1,22 +0,0 @@
-create table map (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-insert into map(id, name) values(1, 'Show on map');
-insert into map(id, name) values(2, 'Hide, same position as newer packet');
-insert into map(id, name) values(3, 'Hide, duplicate packet');
-insert into map(id, name) values(4, 'Hide, failed to find marker id');
-insert into map(id, name) values(5, 'Hide, faulty gps position');
-insert into map(id, name) values(6, 'Hide, packet received to late');
-insert into map(id, name) values(7, 'Hide, moves to fast');
-insert into map(id, name) values(8, 'Hide, packet is less than 5 seconds after previous');
-insert into map(id, name) values(9, 'Hide, abnormal position');
-insert into map(id, name) values(10, 'Hide, has no position');
-insert into map(id, name) values(11, 'Hide, unsupported format');
-insert into map(id, name) values (12, 'Hide, same position as newer packet (but later date)');
-insert into map(id, name) values (13, 'Hide, same position as newer packet (and faulty gps position)');
-insert into map(id, name) values (14, 'Hide, killed object/item');
-insert into map(id, name) values (15, 'Stealth/No tracking');
-insert into map(id, name) values (16, 'Faulty network, APRS packet digipeated by a CWOP-station');
diff --git a/misc/database/tables/02_marker.sql b/misc/database/tables/02_marker.sql
deleted file mode 100644
index 42b103adb1ff06d425b390c525933d1155c32957..0000000000000000000000000000000000000000
--- a/misc/database/tables/02_marker.sql
+++ /dev/null
@@ -1 +0,0 @@
-CREATE SEQUENCE marker_seq INCREMENT BY 1 MINVALUE 2;
diff --git a/misc/database/tables/03_ogn_address_type.sql b/misc/database/tables/03_ogn_address_type.sql
deleted file mode 100644
index 48f0364649ed3ff8f1eadb605b1f342d3edbb60e..0000000000000000000000000000000000000000
--- a/misc/database/tables/03_ogn_address_type.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-create table ogn_address_type (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-insert into ogn_address_type(id, name) values(1, 'ICAO');
-insert into ogn_address_type(id, name) values(2, 'FLARM');
-insert into ogn_address_type(id, name) values(3, 'OGN');
diff --git a/misc/database/tables/04_ogn_aircraft_type.sql b/misc/database/tables/04_ogn_aircraft_type.sql
deleted file mode 100644
index f5089435359834777044d6593632c9f50394d0ad..0000000000000000000000000000000000000000
--- a/misc/database/tables/04_ogn_aircraft_type.sql
+++ /dev/null
@@ -1,22 +0,0 @@
-create table ogn_aircraft_type (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-insert into ogn_aircraft_type(id, name) values(1, 'Glider');
-insert into ogn_aircraft_type(id, name) values(2, 'Tow Plane');
-insert into ogn_aircraft_type(id, name) values(3, 'Helicopter');
-insert into ogn_aircraft_type(id, name) values(4, 'Parachute');
-insert into ogn_aircraft_type(id, name) values(5, 'Drop Plane');
-insert into ogn_aircraft_type(id, name) values(6, 'Hang Glider');
-insert into ogn_aircraft_type(id, name) values(7, 'Para Glider');
-insert into ogn_aircraft_type(id, name) values(8, 'Powered Aircraft');
-insert into ogn_aircraft_type(id, name) values(9, 'Jet Aircraft');
-insert into ogn_aircraft_type(id, name) values(10, 'UFO');
-insert into ogn_aircraft_type(id, name) values(11, 'Balloon');
-insert into ogn_aircraft_type(id, name) values(12, 'Airship');
-insert into ogn_aircraft_type(id, name) values(13, 'UAV');
-insert into ogn_aircraft_type(id, name) values(14, '');
-insert into ogn_aircraft_type(id, name) values(15, 'Static Object');
-
diff --git a/misc/database/tables/05_ogn_device.sql b/misc/database/tables/05_ogn_device.sql
deleted file mode 100644
index 22e01e03a04829941f8b454975c6a44440ecaa4a..0000000000000000000000000000000000000000
--- a/misc/database/tables/05_ogn_device.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-create table if not exists ogn_device (
- "device_type" text not null,
- "device_id" text not null,
- "aircraft_model" text not null,
- "registration" text not null,
- "cn" text not null,
- "tracked" text not null,
- "identified" text not null,
- "ddb_aircraft_type" text not null
-);
diff --git a/misc/database/tables/06_ogn_hidden_station.sql b/misc/database/tables/06_ogn_hidden_station.sql
deleted file mode 100644
index 0b311556fab2ba46eb7b4697bf85c043f7a1aaf4..0000000000000000000000000000000000000000
--- a/misc/database/tables/06_ogn_hidden_station.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-create table ogn_hidden_station (
- "id" bigserial not null,
- "hashed_name" text not null,
- primary key (id)
-);
-
-create index ogn_hidden_station_hashed_name_idx on ogn_hidden_station(hashed_name);
diff --git a/misc/database/tables/07_packet_type.sql b/misc/database/tables/07_packet_type.sql
deleted file mode 100644
index c72b01c4769193e2cd02cc83fa72cf68ff1dfbcf..0000000000000000000000000000000000000000
--- a/misc/database/tables/07_packet_type.sql
+++ /dev/null
@@ -1,18 +0,0 @@
-create table packet_type (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-
-insert into packet_type(id, name) values(1, 'position');
-insert into packet_type(id, name) values(2, 'direction');
-insert into packet_type(id, name) values(3, 'weather');
-insert into packet_type(id, name) values(4, 'object');
-insert into packet_type(id, name) values(5, 'item');
-insert into packet_type(id, name) values(6, 'telemetry');
-insert into packet_type(id, name) values(7, 'message');
-insert into packet_type(id, name) values(8, 'query');
-insert into packet_type(id, name) values(9, 'response');
-insert into packet_type(id, name) values(10, 'status');
-insert into packet_type(id, name) values(11, 'other');
diff --git a/misc/database/tables/08_sender.sql b/misc/database/tables/08_sender.sql
deleted file mode 100644
index d042c3172fbd0a7013b243b531fb9c1d484dec32..0000000000000000000000000000000000000000
--- a/misc/database/tables/08_sender.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-create table sender (
- "id" bigserial not null,
- "name" text not null,
- primary key (id)
-);
-
-create index sender_name_idx on sender(name);
diff --git a/misc/database/tables/09_source.sql b/misc/database/tables/09_source.sql
deleted file mode 100644
index 42bac07a5a4dc94366c99db00876cb890c43e543..0000000000000000000000000000000000000000
--- a/misc/database/tables/09_source.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-create table source (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-
-insert into source(id, name) values(1, 'APRS');
-insert into source(id, name) values(2, 'CWOP');
-insert into source(id, name) values(3, 'CBAPRS');
-insert into source(id, name) values(4, 'HUBHAB');
-insert into source(id, name) values(5, 'OGN');
diff --git a/misc/database/tables/10_station_type.sql b/misc/database/tables/10_station_type.sql
deleted file mode 100644
index 8ca498462120633440c4ed893698f247a96f3af5..0000000000000000000000000000000000000000
--- a/misc/database/tables/10_station_type.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-create table station_type (
- "id" smallint not null,
- "name" text not null,
- primary key (id)
-);
-
-
-insert into station_type(id, name) values(1, 'Station');
-insert into station_type(id, name) values(2, 'Object');
diff --git a/misc/database/tables/11_station.sql b/misc/database/tables/11_station.sql
deleted file mode 100644
index 6b0a5e57c99f86a4723ab34e71b35a817156f40b..0000000000000000000000000000000000000000
--- a/misc/database/tables/11_station.sql
+++ /dev/null
@@ -1,51 +0,0 @@
-create table station (
- "id" bigserial not null,
- "name" text null,
- "latest_sender_id" bigint null,
- "station_type_id" smallint not null,
- "source_id" smallint not null,
-
- "latest_location_packet_id" bigint null,
- "latest_location_packet_timestamp" bigint null,
- "latest_location_marker_id" bigint null,
- "latest_location_symbol" text null,
- "latest_location_symbol_table" text null,
- "latest_location_latitude" double precision null,
- "latest_location_longitude" double precision null,
-
- "latest_confirmed_packet_id" bigint null,
- "latest_confirmed_packet_timestamp" bigint null,
- "latest_confirmed_marker_id" bigint null,
- "latest_confirmed_symbol" text null,
- "latest_confirmed_symbol_table" text null,
- "latest_confirmed_latitude" double precision null,
- "latest_confirmed_longitude" double precision null,
-
- "latest_packet_id" bigint null,
- "latest_packet_timestamp" bigint null,
-
- "latest_weather_packet_id" bigint null,
- "latest_weather_packet_timestamp" bigint null,
- "latest_weather_packet_comment" text null,
-
- "latest_telemetry_packet_id" bigint null,
- "latest_telemetry_packet_timestamp" bigint null,
-
- "latest_ogn_packet_id" bigint null,
- "latest_ogn_packet_timestamp" bigint null,
- "latest_ogn_sender_address" text null,
- "latest_ogn_aircraft_type_id" smallint null,
- "latest_ogn_address_type_id" smallint null,
-
- primary key (id),
- foreign key(latest_sender_id) references sender(id),
- foreign key(station_type_id) references station_type(id),
- foreign key(source_id) references source(id),
- foreign key(latest_ogn_aircraft_type_id) references ogn_aircraft_type(id),
- foreign key(latest_ogn_address_type_id) references ogn_address_type(id)
-);
-
-create index station_name_idx on station(name);
-create index station_latest_sender_id_idx on station(latest_sender_id);
-create index station_pos_timestamp_idx on station(latest_confirmed_latitude, latest_confirmed_longitude, latest_confirmed_packet_timestamp);
-create index station_ogn_sender_address_idx on station(latest_ogn_sender_address);
diff --git a/misc/database/tables/12_station_telemetry_bits.sql b/misc/database/tables/12_station_telemetry_bits.sql
deleted file mode 100644
index e6d181f30016ffabf5ac327ae97d5603af5fc2e6..0000000000000000000000000000000000000000
--- a/misc/database/tables/12_station_telemetry_bits.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-create table station_telemetry_bits (
- "id" bigserial not null,
- "station_id" bigint null,
- "created_ts" bigint default extract(epoch from now()),
- "latest_ts" bigint default extract(epoch from now()),
- "valid_to_ts" bigint null,
- "bits" text null,
- "title" text null,
- primary key (id),
- foreign key(station_id) references station(id)
-);
-
-create index station_telemetry_bits_station_id_idx on station_telemetry_bits(station_id, valid_to_ts, latest_ts);
diff --git a/misc/database/tables/13_station_telemetry_eqns.sql b/misc/database/tables/13_station_telemetry_eqns.sql
deleted file mode 100644
index 40d2c89fc71c826ed668aff9ab2d17aba56375bf..0000000000000000000000000000000000000000
--- a/misc/database/tables/13_station_telemetry_eqns.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-create table station_telemetry_eqns (
- "id" bigserial not null,
- "station_id" bigint null,
- "created_ts" bigint default extract(epoch from now()),
- "latest_ts" bigint default extract(epoch from now()),
- "valid_to_ts" bigint null,
-
- "a1" real null,
- "b1" real null,
- "c1" real null,
-
- "a2" real null,
- "b2" real null,
- "c2" real null,
-
- "a3" real null,
- "b3" real null,
- "c3" real null,
-
- "a4" real null,
- "b4" real null,
- "c4" real null,
-
- "a5" real null,
- "b5" real null,
- "c5" real null,
-
- primary key (id),
- foreign key(station_id) references station(id)
-);
-
-create index station_telemetry_eqns_station_id_idx on station_telemetry_eqns(station_id, valid_to_ts, latest_ts);
diff --git a/misc/database/tables/14_station_telemetry_param.sql b/misc/database/tables/14_station_telemetry_param.sql
deleted file mode 100644
index 97bd4336e4bd3f7eafa7a606ac1d7065da4161c2..0000000000000000000000000000000000000000
--- a/misc/database/tables/14_station_telemetry_param.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-create table station_telemetry_param (
- "id" bigserial not null,
- "station_id" bigint null,
- "created_ts" bigint default extract(epoch from now()),
- "latest_ts" bigint default extract(epoch from now()),
- "valid_to_ts" bigint null,
- "p1" text null,
- "p2" text null,
- "p3" text null,
- "p4" text null,
- "p5" text null,
- "b1" text null,
- "b2" text null,
- "b3" text null,
- "b4" text null,
- "b5" text null,
- "b6" text null,
- "b7" text null,
- "b8" text null,
- primary key (id),
- foreign key(station_id) references station(id)
-);
-
-create index station_telemetry_param_station_id_idx on station_telemetry_param(station_id, valid_to_ts, latest_ts);
diff --git a/misc/database/tables/15_station_telemetry_unit.sql b/misc/database/tables/15_station_telemetry_unit.sql
deleted file mode 100644
index 167a174bbe23cb727ed4037f1d90f2bea8d5cb96..0000000000000000000000000000000000000000
--- a/misc/database/tables/15_station_telemetry_unit.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-create table station_telemetry_unit (
- "id" bigserial not null,
- "station_id" bigint null,
- "created_ts" bigint default extract(epoch from now()),
- "latest_ts" bigint default extract(epoch from now()),
- "valid_to_ts" bigint null,
- "u1" text null,
- "u2" text null,
- "u3" text null,
- "u4" text null,
- "u5" text null,
- "l1" text null,
- "l2" text null,
- "l3" text null,
- "l4" text null,
- "l5" text null,
- "l6" text null,
- "l7" text null,
- "l8" text null,
- primary key (id),
- foreign key(station_id) references station(id)
-);
-
-create index station_telemetry_unit_station_id_idx on station_telemetry_unit(station_id, valid_to_ts, latest_ts);
diff --git a/misc/database/tables/16_packet.sql b/misc/database/tables/16_packet.sql
deleted file mode 100644
index c14e79daf76f6a7cd5693461fab4601d8b08bc8d..0000000000000000000000000000000000000000
--- a/misc/database/tables/16_packet.sql
+++ /dev/null
@@ -1,42 +0,0 @@
-create table packet (
- "id" bigserial not null,
- "station_id" bigint not null,
- "sender_id" bigint not null,
- "marker_id" bigint null,
- "marker_counter" int null,
- "packet_type_id" smallint not null,
- "timestamp" bigint not null,
- "reported_timestamp" bigint null,
- "position_timestamp" bigint null,
- "latitude" double precision null,
- "longitude" double precision null,
- "posambiguity" smallint null,
- "symbol" text null,
- "symbol_table" text null,
- "map_sector" int null,
- "related_map_sectors" int array null,
- "map_id" smallint default 1,
- "source_id" smallint default 1,
- "speed" real null,
- "course" real null,
- "altitude" real null,
- "rng" real null,
- "latest_rng_timestamp" bigint null,
- "phg" int null,
- "latest_phg_timestamp" bigint null,
- "packet_tail_timestamp" bigint null,
- "is_moving" smallint null,
- "comment" text null,
- "raw_path" text null,
- "raw" text null,
- primary key (id),
- foreign key(packet_type_id) references packet_type(id),
- foreign key(station_id) references station(id),
- foreign key(sender_id) references sender(id),
- foreign key(map_id) references map(id),
- foreign key(source_id) references source(id)
-);
-
-
-
-
diff --git a/misc/database/tables/17_packet_weather.sql b/misc/database/tables/17_packet_weather.sql
deleted file mode 100644
index 8d2857012a088d9bd2d0f3f986ed0dbe28e52910..0000000000000000000000000000000000000000
--- a/misc/database/tables/17_packet_weather.sql
+++ /dev/null
@@ -1,20 +0,0 @@
-create table packet_weather (
- "id" bigserial not null,
- "packet_id" bigint not null,
- "station_id" bigint not null,
- "timestamp" bigint not null,
- "humidity" int null,
- "pressure" real null,
- "rain_1h" real null,
- "rain_24h" real null,
- "rain_since_midnight" real null,
- "temperature" real null,
- "wind_direction" int null,
- "wind_gust" real null,
- "wind_speed" real null,
- "luminosity" real null,
- "snow" real null,
- "wx_raw_timestamp" bigint null,
- primary key (id),
- foreign key(station_id) references station(id)
-);
diff --git a/misc/database/tables/18_packet_telemetry.sql b/misc/database/tables/18_packet_telemetry.sql
deleted file mode 100644
index 20547386bb93acbfc90ec78ac623d22183a579c7..0000000000000000000000000000000000000000
--- a/misc/database/tables/18_packet_telemetry.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-create table packet_telemetry (
- "id" bigserial not null,
- "packet_id" bigint not null,
- "station_id" bigint not null,
- "timestamp" bigint not null,
- "val1" real null,
- "val2" real null,
- "val3" real null,
- "val4" real null,
- "val5" real null,
- "bits" text null,
- "seq" int null,
- "station_telemetry_param_id" bigint null,
- "station_telemetry_unit_id" bigint null,
- "station_telemetry_eqns_id" bigint null,
- "station_telemetry_bits_id" bigint null,
- primary key (id),
- foreign key(station_id) references station(id),
- foreign key(station_telemetry_param_id) references station_telemetry_param(id),
- foreign key(station_telemetry_unit_id) references station_telemetry_unit(id),
- foreign key(station_telemetry_eqns_id) references station_telemetry_eqns(id),
- foreign key(station_telemetry_bits_id) references station_telemetry_bits(id)
-);
diff --git a/misc/database/tables/19_packet_path.sql b/misc/database/tables/19_packet_path.sql
deleted file mode 100644
index 824d728a91ef342ecb8ba1c13275e66745c5fb6d..0000000000000000000000000000000000000000
--- a/misc/database/tables/19_packet_path.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-create table packet_path (
- "id" bigserial not null,
- "packet_id" bigint not null,
- "station_id" bigint not null,
- "latitude" double precision null,
- "longitude" double precision null,
- "timestamp" bigint null,
- "distance" int null,
- "number" smallint,
- "sending_station_id" bigint not null,
- "sending_latitude" double precision null,
- "sending_longitude" double precision null,
- primary key (id),
- foreign key(station_id) references station(id),
- foreign key(sending_station_id) references station(id)
-);
diff --git a/misc/database/tables/20_packet_ogn.sql b/misc/database/tables/20_packet_ogn.sql
deleted file mode 100644
index 83208eb5d28ae041b1f97be61c94dcd9fb876bf6..0000000000000000000000000000000000000000
--- a/misc/database/tables/20_packet_ogn.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-create table packet_ogn (
- "id" bigserial not null,
- "packet_id" bigint not null,
- "station_id" bigint not null,
- "timestamp" bigint not null,
- "ogn_sender_address" text null,
- "ogn_address_type_id" smallint null,
- "ogn_aircraft_type_id" smallint null,
- "ogn_climb_rate" int null,
- "ogn_turn_rate" float null,
- "ogn_signal_to_noise_ratio" float null,
- "ogn_bit_errors_corrected" int null,
- "ogn_frequency_offset" float null,
- primary key (id),
- foreign key(station_id) references station(id)
-);
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 2a592dacdb7807b368d831d8e8995116459fb4a6..0000000000000000000000000000000000000000
--- a/requirements.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-psycopg2-binary
-wheel
-setuptools
-autobahn[twisted]
-twisted
-pympler
-image_slicer
-jsmin
-psutil
-git+https://github.com/rossengeorgiev/aprs-python
\ No newline at end of file
diff --git a/server/bin/collector.py b/server/bin/collector.py
deleted file mode 100644
index 7025864c22d54e015219745602e6cb0e5cb73f1a..0000000000000000000000000000000000000000
--- a/server/bin/collector.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import sys
-import os.path
-import logging
-import logging.handlers
-import trackdirect
-
-if __name__ == '__main__':
-
- if (len(sys.argv) < 2):
- print("\n" + sys.argv[0] + ' [config.ini] [collector number]')
- sys.exit()
- elif (sys.argv[1].startswith("/")):
- if (not os.path.isfile(sys.argv[1])):
- print(f"\n File {sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini] [collector number]')
- sys.exit()
- elif (not os.path.isfile(os.path.expanduser('~/trackdirect/config/' + sys.argv[1]))):
- print(f"\n File ~/trackdirect/config/{sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini] [collector number]')
- sys.exit()
-
- config = trackdirect.TrackDirectConfig()
- config.populate(sys.argv[1])
-
- if (len(sys.argv) < 3):
- collectorNumber = 0
- else:
- collectorNumber = int(sys.argv[2])
- collectorOptions = config.collector[collectorNumber]
-
- saveOgnStationsWithMissingIdentity = False
- if (config.saveOgnStationsWithMissingIdentity):
- saveOgnStationsWithMissingIdentity = True
-
- fh = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
- collectorOptions['error_log']), mode='a', maxBytes=1000000, backupCount=10)
-
- formatter = logging.Formatter(
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- fh.setFormatter(formatter)
-
- consoleHandler = logging.StreamHandler()
- consoleHandler.setFormatter(formatter)
-
- trackDirectLogger = logging.getLogger('trackdirect')
- trackDirectLogger.addHandler(fh)
- trackDirectLogger.addHandler(consoleHandler)
- trackDirectLogger.setLevel(logging.INFO)
-
- aprslibLogger = logging.getLogger('aprslib.IS')
- aprslibLogger.addHandler(fh)
- aprslibLogger.addHandler(consoleHandler)
- aprslibLogger.setLevel(logging.INFO)
-
- trackDirectLogger.warning("Starting (Collecting from " + collectorOptions['host'] + ":" + str(
- collectorOptions['port_full']) + " using " + collectorOptions['callsign'] + " and " + str(collectorOptions['passcode']) + ")")
-
- try:
- trackDirectDataCollector = trackdirect.TrackDirectDataCollector(
- collectorOptions,
- saveOgnStationsWithMissingIdentity)
- trackDirectDataCollector.run()
- except Exception as e:
- trackDirectLogger.error(e, exc_info=1)
diff --git a/server/bin/remover.py b/server/bin/remover.py
deleted file mode 100644
index 0d80f5b8791a6a554822333f75e427308f45b5c0..0000000000000000000000000000000000000000
--- a/server/bin/remover.py
+++ /dev/null
@@ -1,248 +0,0 @@
-import sys
-import os.path
-import logging
-import logging.handlers
-import datetime
-import time
-import trackdirect
-
-from trackdirect.database.DatabaseConnection import DatabaseConnection
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.repositories.PacketRepository import PacketRepository
-
-if __name__ == '__main__':
-
- if (len(sys.argv) < 2):
- print("\n" + sys.argv[0] + ' [config.ini]')
- sys.exit()
- elif (sys.argv[1].startswith("/")):
- if (not os.path.isfile(sys.argv[1])):
- print(f"\n File {sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini]')
- sys.exit()
- elif (not os.path.isfile(os.path.expanduser('~/trackdirect/config/' + sys.argv[1]))):
- print(f"\n File ~/trackdirect/config/{sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini]')
- sys.exit()
-
- config = trackdirect.TrackDirectConfig()
- config.populate(sys.argv[1])
-
- maxDaysToSavePositionData = int(config.daysToSavePositionData)
- maxDaysToSaveStationData = int(config.daysToSaveStationData)
- maxDaysToSaveWeatherData = int(config.daysToSaveWeatherData)
- maxDaysToSaveTelemetryData = int(config.daysToSaveTelemetryData)
-
- try:
- fh = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
- '~/trackdirect/server/log/remover_' + config.dbName + '.log'), mode='a', maxBytes=1000000, backupCount=10)
-
- formatter = logging.Formatter(
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- fh.setFormatter(formatter)
-
- consoleHandler = logging.StreamHandler()
- consoleHandler.setFormatter(formatter)
-
- trackDirectLogger = logging.getLogger('trackdirect')
- trackDirectLogger.addHandler(fh)
- trackDirectLogger.addHandler(consoleHandler)
- trackDirectLogger.setLevel(logging.INFO)
-
- trackDirectLogger.info("Starting")
- trackDirectLogger.info(
- "Saving position data for %s days" % (maxDaysToSavePositionData))
- trackDirectLogger.info(
- "Saving station data for %s days" % (maxDaysToSaveStationData))
- trackDirectLogger.info(
- "Saving weather data for %s days" % (maxDaysToSaveWeatherData))
- trackDirectLogger.info(
- "Saving telemetry data for %s days" % (maxDaysToSaveTelemetryData))
-
- trackDirectDb = DatabaseConnection()
- dbNoAutoCommit = trackDirectDb.getConnection(False)
- db = trackDirectDb.getConnection(True)
- db.set_isolation_level(0)
- cursor = db.cursor()
- cursor.execute("SET statement_timeout = '240s'")
-
- trackDirectDbObjectFinder = DatabaseObjectFinder(db)
-
- packetRepository = PacketRepository(db)
-
- #
- # Loop over the latest days and delete packets that is not needed any more
- #
- for x in range(2, 16):
- prevDay = datetime.date.today() - datetime.timedelta(x) # today minus x days
- prevDayTimestamp = prevDay.strftime("%s")
- prevDayFormat = datetime.datetime.utcfromtimestamp(
- int(prevDayTimestamp)).strftime('%Y%m%d')
- packetTable = "packet" + prevDayFormat
-
- if (trackDirectDbObjectFinder.checkTableExists(packetTable)):
- deletedRows = None
- doFullVacuum = False
- while (deletedRows is None or deletedRows >= 5000):
- sql = """delete from """ + packetTable + \
- """ where id in (select id from """ + packetTable + \
- """ where map_id not in (1,12) limit 5000)"""
- cursor.execute(sql)
- deletedRows = cursor.rowcount
- trackDirectLogger.info(
- "Deleted %s %s" % (deletedRows, packetTable))
- if (deletedRows > 0):
- doFullVacuum = True
- time.sleep(0.5)
- if (doFullVacuum):
- cursor.execute("""VACUUM FULL """ +
- packetTable + """_path""")
- cursor.execute("""REINDEX TABLE """ +
- packetTable + """_path""")
- cursor.execute("""VACUUM FULL """ + packetTable)
- cursor.execute("""REINDEX TABLE """ + packetTable)
-
- #
- # Drop packet_weather
- #
- for x in range(maxDaysToSaveWeatherData, maxDaysToSaveWeatherData+100):
- prevDay = datetime.date.today() - datetime.timedelta(x) # today minus x days
- prevDayTimestamp = prevDay.strftime("%s")
- prevDayFormat = datetime.datetime.utcfromtimestamp(
- int(prevDayTimestamp)).strftime('%Y%m%d')
- packetTable = "packet" + prevDayFormat
-
- if (trackDirectDbObjectFinder.checkTableExists(packetTable + "_weather")):
- cursor.execute("""drop table """ +
- packetTable + """_weather""")
- trackDirectLogger.info(
- "Dropped table %s_weather" % (packetTable))
-
- #
- # Drop packet_telemetry
- #
- for x in range(maxDaysToSaveTelemetryData, maxDaysToSaveTelemetryData+100):
- prevDay = datetime.date.today() - datetime.timedelta(x) # today minus x days
- prevDayTimestamp = prevDay.strftime("%s")
- prevDayFormat = datetime.datetime.utcfromtimestamp(
- int(prevDayTimestamp)).strftime('%Y%m%d')
- packetTable = "packet" + prevDayFormat
-
- if (trackDirectDbObjectFinder.checkTableExists(packetTable + "_telemetry")):
- cursor.execute("""drop table """ +
- packetTable + """_telemetry""")
- trackDirectLogger.info(
- "Dropped table %s_telemetry" % (packetTable))
-
- #
- # Drop packets
- #
- for x in range(maxDaysToSavePositionData, maxDaysToSavePositionData+100):
- prevDay = datetime.date.today() - datetime.timedelta(x) # today minus x days
- prevDayTimestamp = prevDay.strftime("%s")
- prevDayFormat = datetime.datetime.utcfromtimestamp(
- int(prevDayTimestamp)).strftime('%Y%m%d')
- packetTable = "packet" + prevDayFormat
-
- # Drop packet_ogn table
- if (trackDirectDbObjectFinder.checkTableExists(packetTable + "_ogn")):
- cursor.execute("""drop table """ + packetTable + """_ogn""")
- trackDirectLogger.info("Dropped table %s_ogn" % (packetTable))
-
- #
- # Drop packet_path table
- #
- if (trackDirectDbObjectFinder.checkTableExists(packetTable + "_path")):
- cursor.execute("""drop table """ + packetTable + """_path""")
- trackDirectLogger.info("Dropped table %s_path" % (packetTable))
-
- #
- # Drop packet table
- #
- if (trackDirectDbObjectFinder.checkTableExists(packetTable)):
- cursor.execute("""drop table """ + packetTable)
- trackDirectLogger.info("Dropped table %s" % (packetTable))
-
- #
- # Delete old stations
- #
- timestampLimit = int(time.time()) - (60*60*24*maxDaysToSaveStationData)
- deletedRows = 0
- sql = """select station.id, station.latest_sender_id, station.name
- from station
- where latest_packet_timestamp < %s
- and (
- exists (
- select 1
- from sender
- where sender.id = station.latest_sender_id
- and sender.name != station.name
- )
- or
- not exists (
- select 1
- from station station2, sender
- where sender.id = station.latest_sender_id
- and station2.latest_sender_id = sender.id
- and station2.name != sender.name
- )
- )
- order by latest_packet_timestamp"""
-
- selectStationCursor = db.cursor()
- selectStationCursor.execute(sql, (timestampLimit,))
- for record in selectStationCursor:
- trackDirectLogger.info("Trying to delete station %s (%s)" % (
- record["name"], record["id"]))
- try:
- deleteCursor = dbNoAutoCommit.cursor()
-
- sql = """delete from station_telemetry_bits where station_id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from station_telemetry_eqns where station_id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from station_telemetry_param where station_id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from station_telemetry_unit where station_id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from station_city where station_id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from station where id = %s"""
- deleteCursor.execute(sql, (record["id"],))
-
- sql = """delete from sender where id = %s and not exists (select 1 from station where latest_sender_id = sender.id)"""
- deleteCursor.execute(sql, (record["latest_sender_id"],))
-
- dbNoAutoCommit.commit()
- deleteCursor.close()
- deletedRows += 1
- time.sleep(0.5)
- except Exception as e:
- # Something went wrong
- #trackDirectLogger.error(e, exc_info=1)
- dbNoAutoCommit.rollback()
- deleteCursor.close()
-
- selectStationCursor.close()
- if (deletedRows > 0):
- trackDirectLogger.info("Deleted %s stations" % (deletedRows))
-
- cursor.execute("""VACUUM ANALYZE station""")
- cursor.execute("""REINDEX TABLE station""")
- cursor.execute("""VACUUM ANALYZE sender""")
- cursor.execute("""REINDEX TABLE sender""")
-
- #
- # Close DB connection
- #
- cursor.close()
- db.close()
- trackDirectLogger.info("Done!")
-
- except Exception as e:
- trackDirectLogger.error(e, exc_info=1)
diff --git a/server/bin/stationremover.py b/server/bin/stationremover.py
deleted file mode 100644
index 6e13a2eb0a1336393edf6be4dfd74ce2dc7f190b..0000000000000000000000000000000000000000
--- a/server/bin/stationremover.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import sys
-import os.path
-import logging
-import logging.handlers
-import datetime
-import time
-import trackdirect
-
-from trackdirect.database.DatabaseConnection import DatabaseConnection
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-
-if __name__ == '__main__':
-
- if (len(sys.argv) < 3):
- print("\n" + sys.argv[0] + ' [config.ini] [staion id]')
- sys.exit()
- elif (sys.argv[1].startswith("/")):
- if (not os.path.isfile(sys.argv[1])):
- print(f"\n File {sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini] [staion id]')
- sys.exit()
- elif (not os.path.isfile(os.path.expanduser('~/trackdirect/config/' + sys.argv[1]))):
- print(f"\n File ~/trackdirect/config/{sys.argv[1]} does not exists")
- print("\n" + sys.argv[0] + ' [config.ini] [staion id]')
- sys.exit()
-
- stationId = sys.argv[2]
-
- config = trackdirect.TrackDirectConfig()
- config.populate(sys.argv[1])
-
- try:
- fh = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
- '~/trackdirect/server/log/stationremover.log'), mode='a', maxBytes=1000000, backupCount=10)
-
- formatter = logging.Formatter(
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
- fh.setFormatter(formatter)
-
- consoleHandler = logging.StreamHandler()
- consoleHandler.setFormatter(formatter)
-
- trackDirectLogger = logging.getLogger('trackdirect')
- trackDirectLogger.addHandler(fh)
- trackDirectLogger.addHandler(consoleHandler)
- trackDirectLogger.setLevel(logging.INFO)
-
- trackDirectLogger.info("Starting")
-
- trackDirectDb = DatabaseConnection()
- db = trackDirectDb.getConnection(True)
- db.set_isolation_level(0)
- cursor = db.cursor()
- cursor.execute("SET statement_timeout = '120s'")
-
- trackDirectDbObjectFinder = DatabaseObjectFinder(db)
-
- # If saving longer than 365 days, modify range
- for x in range(0, 365):
- prevDay = datetime.date.today() - datetime.timedelta(x) # today minus x days
- prevDayTimestamp = prevDay.strftime("%s")
- prevDayFormat = datetime.datetime.utcfromtimestamp(
- int(prevDayTimestamp)).strftime('%Y%m%d')
-
- packetTable = "packet" + prevDayFormat
- packetPathTable = "packet" + prevDayFormat + "_path"
- packetWeatherTable = "packet" + prevDayFormat + "_weather"
- packetTelemetryTable = "packet" + prevDayFormat + "_telemetry"
-
- if (trackDirectDbObjectFinder.checkTableExists(packetPathTable)):
-
- # Delete paths for this station
- sql = """delete from """ + packetPathTable + \
- """ where packet_id in (select id from """ + \
- packetTable + """ where station_id = %s)"""
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info("Deleted %s rows in %s" % (
- cursor.rowcount or 0, packetPathTable))
- time.sleep(0.5)
-
- # Delete paths related to this station
- sql = """delete from """ + packetPathTable + """ where station_id = %s"""
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info("Deleted %s related rows in %s" % (
- cursor.rowcount or 0, packetPathTable))
- time.sleep(0.5)
-
- if (trackDirectDbObjectFinder.checkTableExists(packetTelemetryTable)):
- # Delete telemetry for this station
- sql = """delete from """ + packetTelemetryTable + """ where station_id = %s"""
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info("Deleted %s rows in %s" % (
- cursor.rowcount or 0, packetTelemetryTable))
- time.sleep(0.5)
-
- if (trackDirectDbObjectFinder.checkTableExists(packetWeatherTable)):
- # Delete weather for this station
- sql = """delete from """ + packetWeatherTable + """ where station_id = %s"""
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info("Deleted %s rows in %s" % (
- cursor.rowcount or 0, packetWeatherTable))
- time.sleep(0.5)
-
- if (trackDirectDbObjectFinder.checkTableExists(packetTable)):
- # Delete packets for this station
- sql = """delete from """ + packetTable + """ where station_id = %s"""
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info("Deleted %s rows in %s" % (
- cursor.rowcount or 0, packetTable))
- time.sleep(0.5)
-
- # Delete station
- sql = "delete from station where id = %s"
- cursor.execute(sql, (stationId,))
- trackDirectLogger.info(
- "Deleted %s rows from station" % (cursor.rowcount or 0))
- time.sleep(0.5)
-
- cursor.close()
- db.close()
- trackDirectLogger.info("Done!")
-
- except Exception as e:
- trackDirectLogger.error(e, exc_info=1)
diff --git a/server/bin/wsserver.py b/server/bin/wsserver.py
deleted file mode 100644
index 890ce097ee02f6ff0859db4b64bf5cc09c220e6a..0000000000000000000000000000000000000000
--- a/server/bin/wsserver.py
+++ /dev/null
@@ -1,151 +0,0 @@
-from autobahn.twisted.websocket import WebSocketServerFactory
-from autobahn.twisted.resource import WebSocketResource
-from autobahn.websocket.compress import PerMessageDeflateOffer, PerMessageDeflateOfferAccept
-import trackdirect
-import argparse
-import psutil
-import sys
-import os.path
-import logging
-import logging.handlers
-from twisted.internet import reactor
-from twisted.web.server import Site
-from twisted.web.static import File
-from socket import AF_INET
-
-
-def master(options, trackDirectLogger):
- """
- Start of the master process.
- """
- config = trackdirect.TrackDirectConfig()
- config.populate(options.config)
-
- workerPid = os.getpid()
- p = psutil.Process(workerPid)
- p.cpu_affinity([0])
- trackDirectLogger.warning("Starting master with PID " + str(workerPid) + " (on CPU id(s): " + ','.join(map(str, p.cpu_affinity())) + ")")
-
- try:
- factory = WebSocketServerFactory()
- factory.protocol = trackdirect.TrackDirectWebsocketServer
-
- resource = WebSocketResource(factory)
- root = File(".")
- root.putChild(b"ws", resource)
- site = Site(root)
-
- port = reactor.listenTCP(config.websocketPort, site)
-
- for i in range(1, options.workers):
- args = [sys.executable, "-u", __file__]
- args.extend(sys.argv[1:])
- args.extend(["--fd", str(port.fileno()), "--cpuid", str(i)])
-
- reactor.spawnProcess(
- None, sys.executable, args,
- childFDs={0: 0, 1: 1, 2: 2, port.fileno(): port.fileno()},
- env=os.environ)
-
- options.fd = port.fileno()
- listen(options, trackDirectLogger)
-
- except Exception as e:
- trackDirectLogger.error(e, exc_info=1)
-
-
-def worker(options, trackDirectLogger):
- """
- Start background worker process.
- """
- config = trackdirect.TrackDirectConfig()
- config.populate(options.config)
-
- try:
- workerPid = os.getpid()
- p = psutil.Process(workerPid)
- p.cpu_affinity([options.cpuid])
-
- trackDirectLogger.warning("Starting worker with PID " + str(workerPid) + " (on CPU id(s): " + ','.join(map(str, p.cpu_affinity())) + ")")
-
- listen(options, trackDirectLogger)
-
- except Exception as e:
- trackDirectLogger.error(e, exc_info=1)
-
-
-def listen(options, trackDirectLogger) :
- """
- Start to listen on websocket requests.
- """
- config = trackdirect.TrackDirectConfig()
- config.populate(options.config)
-
- factory = WebSocketServerFactory(
- "ws://" + config.websocketHostname + ":" + str(config.websocketPort),
- externalPort = config.websocketExternalPort)
- factory.protocol = trackdirect.TrackDirectWebsocketServer
-
- # Enable WebSocket extension "permessage-deflate".
- # Function to accept offers from the client ..
- def accept(offers):
- for offer in offers:
- if isinstance(offer, PerMessageDeflateOffer):
- return PerMessageDeflateOfferAccept(offer)
- factory.setProtocolOptions(perMessageCompressionAccept=accept)
-
- reactor.suggestThreadPoolSize(25)
-
- # Socket already created, just start listening and accepting
- reactor.adoptStreamPort(options.fd, AF_INET, factory)
-
- reactor.run()
-
-
-if __name__ == '__main__':
- DEFAULT_WORKERS = psutil.cpu_count()
-
- parser = argparse.ArgumentParser(
- description='Track Direct WebSocket Server')
- parser.add_argument('--config', dest='config', type=str, default=None,
- help='The Track Direct config file, e.g. trackdirect.ini')
- parser.add_argument('--workers', dest='workers', type=int, default=DEFAULT_WORKERS,
- help='Number of workers to spawn - should fit the number of (physical) CPU cores.')
- parser.add_argument('--fd', dest='fd', type=int, default=None,
- help='If given, this is a worker which will use provided FD and all other options are ignored.')
- parser.add_argument('--cpuid', dest='cpuid', type=int, default=None,
- help='If given, this is a worker which will use provided CPU core to set its affinity.')
-
- options = parser.parse_args()
- config = trackdirect.TrackDirectConfig()
- config.populate(options.config)
-
- formatter = logging.Formatter(
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
-
- fh = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
- config.errorLog), mode='a', maxBytes=1000000, backupCount=10)
- fh.setFormatter(formatter)
-
- consoleHandler = logging.StreamHandler()
- consoleHandler.setFormatter(formatter)
-
- trackDirectLogger = logging.getLogger('trackdirect')
- trackDirectLogger.addHandler(fh)
- trackDirectLogger.addHandler(consoleHandler)
- trackDirectLogger.setLevel(logging.INFO)
-
- fh2 = logging.handlers.RotatingFileHandler(filename=os.path.expanduser(
- config.errorLog), mode='a', maxBytes=1000000, backupCount=10)
- # aprslib is logging non important "socket error on ..." using ERROR-level
- fh2.setFormatter(formatter)
-
- aprslibLogger = logging.getLogger('aprslib.IS')
- aprslibLogger.addHandler(fh2)
- aprslibLogger.addHandler(consoleHandler)
- aprslibLogger.setLevel(logging.INFO)
-
- if options.fd is not None:
- worker(options, trackDirectLogger)
- else:
- master(options, trackDirectLogger)
diff --git a/server/log/.gitignore b/server/log/.gitignore
deleted file mode 100644
index 5e7d2734cfc60289debf74293817c0a8f572ff32..0000000000000000000000000000000000000000
--- a/server/log/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# Ignore everything in this directory
-*
-# Except this file
-!.gitignore
diff --git a/server/scripts/collector.sh b/server/scripts/collector.sh
deleted file mode 100755
index 50bd14ddfd9d66e06cfe2a1a74e8bbf0450318cd..0000000000000000000000000000000000000000
--- a/server/scripts/collector.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [config file] [collector number]"
- exit
-fi
-
-CONFIGFILE=$1
-COLLECTORNUMBER=$2
-
-if ps -ef | grep -v grep | grep "bin/collector.py $CONFIGFILE $COLLECTORNUMBER" ; then
- exit 0
-else
- CURRENTDIR=$(dirname $0)
-
- export PYTHONPATH=$PYTHONPATH:$CURRENTDIR/../trackdirect
- cd $CURRENTDIR/..
- python $CURRENTDIR/../bin/collector.py $CONFIGFILE $COLLECTORNUMBER
- exit 0
-fi
diff --git a/server/scripts/db_setup.sh b/server/scripts/db_setup.sh
deleted file mode 100755
index acea6638e202648a49c5a878f7b0b4179014eaa7..0000000000000000000000000000000000000000
--- a/server/scripts/db_setup.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [dbname] [dbport] [sqlpath]"
- exit
-fi
-
-DATABASE=$1
-PORT=$2
-SQLPATH=$3
-
-# Assumes .pgpass is correctly set
-psql -p $PORT $DATABASE << EOF
-
-begin transaction;
-
-\i $SQLPATH/01_map.sql
-\i $SQLPATH/02_marker.sql
-\i $SQLPATH/03_ogn_address_type.sql
-\i $SQLPATH/04_ogn_aircraft_type.sql
-\i $SQLPATH/05_ogn_device.sql
-\i $SQLPATH/06_ogn_hidden_station.sql
-\i $SQLPATH/07_packet_type.sql
-\i $SQLPATH/08_sender.sql
-\i $SQLPATH/09_source.sql
-\i $SQLPATH/10_station_type.sql
-\i $SQLPATH/11_station.sql
-\i $SQLPATH/12_station_telemetry_bits.sql
-\i $SQLPATH/13_station_telemetry_eqns.sql
-\i $SQLPATH/14_station_telemetry_param.sql
-\i $SQLPATH/15_station_telemetry_unit.sql
-\i $SQLPATH/16_packet.sql
-\i $SQLPATH/17_packet_weather.sql
-\i $SQLPATH/18_packet_telemetry.sql
-\i $SQLPATH/19_packet_path.sql
-\i $SQLPATH/20_packet_ogn.sql
-
-commit;
-
-EOF
-
-
-exit 0
diff --git a/server/scripts/ogn_devices_install.sh b/server/scripts/ogn_devices_install.sh
deleted file mode 100755
index 5859bc1a39ff4ccf1dbf7c14886483aba128d415..0000000000000000000000000000000000000000
--- a/server/scripts/ogn_devices_install.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [dbname] [dbport]"
- exit
-fi
-
-DATABASE=$1
-PORT=$2
-
-pushd `dirname $0` > /dev/null
-SCRIPTPATH=`pwd -P`
-popd > /dev/null
-
-# Create dir and remove old stuff (keep zip-file since it may be equal to latest)
-mkdir -p $SCRIPTPATH/ogndevices
-mkdir -p $SCRIPTPATH/ogndevices/${DATABASE}
-rm $SCRIPTPATH/ogndevices/${DATABASE}/*.csv
-rm $SCRIPTPATH/ogndevices/${DATABASE}/*.txt
-cd $SCRIPTPATH/ogndevices/${DATABASE}
-
-# Download latest csv file (but only if newer)
-wget -N http://ddb.glidernet.org/download/?t=1 -O ogndevices.csv
-
-if test `find "ogndevices.csv" -cmin +30`
-then
- echo "File is not updated, skip reload of database."
-else
-
-
-# Remove comments in file
-sed '/^#/ d' < ogndevices.csv > ogndevices2.csv
-
-# Load file into database (assumes .pgpass is correctly set)
-psql -p $PORT $DATABASE << EOF
-
-create table if not exists ogn_device (
- "device_type" text not null,
- "device_id" text not null,
- "aircraft_model" text not null,
- "registration" text not null,
- "cn" text not null,
- "tracked" text not null,
- "identified" text not null,
- "ddb_aircraft_type" text not null
-);
-
-begin transaction;
-
-drop index if exists ogn_device_device_id_idx;
-truncate ogn_device;
-\copy ogn_device from '$SCRIPTPATH/ogndevices/$DATABASE/ogndevices2.csv' DELIMITERS ',' CSV QUOTE '''';
-create index ogn_device_device_id_idx on ogn_device(device_id);
-
-insert into ogn_device(device_type, device_id, aircraft_model, registration, cn, tracked, identified, ddb_aircraft_type) values ('F', '3FEF6F', '', '', '', 'N', 'N', 1);
-commit;
-
-EOF
-
-fi
-
-exit 0
diff --git a/server/scripts/remover.sh b/server/scripts/remover.sh
deleted file mode 100755
index ccb0cae108ffce298477e29787a43cc9b82ba732..0000000000000000000000000000000000000000
--- a/server/scripts/remover.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [config file path]"
- exit
-fi
-
-CONFIGFILE=$1
-
-if ps -ef | grep -v grep | grep "bin/remover.py $CONFIGFILE" ; then
- exit 0
-else
- CURRENTDIR=$(dirname $0)
-
- export PYTHONPATH=$PYTHONPATH:$CURRENTDIR/../trackdirect
- cd $CURRENTDIR/..
- python $CURRENTDIR/../bin/remover.py $CONFIGFILE
- exit 0
-fi
diff --git a/server/scripts/stationremover.sh b/server/scripts/stationremover.sh
deleted file mode 100755
index 72be13e363e1517dbb68fc5663bdb9b7b14f1b17..0000000000000000000000000000000000000000
--- a/server/scripts/stationremover.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [config file path] [station id]"
- exit
-fi
-
-CONFIGFILE=$1
-STATIONID=$2
-
-if ps -ef | grep -v grep | grep "bin/stationremover.py $CONFIGFILE $STATIONID" ; then
- exit 0
-else
- CURRENTDIR=$(dirname $0)
-
- export PYTHONPATH=$PYTHONPATH:$CURRENTDIR/../trackdirect
- cd $CURRENTDIR/..
- python $CURRENTDIR/../bin/stationremover.py $CONFIGFILE $STATIONID
- exit 0
-fi
diff --git a/server/scripts/wsserver.sh b/server/scripts/wsserver.sh
deleted file mode 100755
index 999d3e7936b254ea8e55f9544715d55f63d20bd7..0000000000000000000000000000000000000000
--- a/server/scripts/wsserver.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-if [ $# -eq 0 ]
- then
- echo "No arguments supplied"
- echo "$0 [config file]"
- exit
-fi
-
-CONFIGFILE=$1
-
-if ps -eo pid,pgid,cmd | grep -v grep | grep "bin/wsserver.py --config $CONFIGFILE" ; then
- exit 0
-else
- CURRENTDIR=$(dirname $0)
-
- export PYTHONPATH=$PYTHONPATH:$CURRENTDIR/../trackdirect
- cd $CURRENTDIR/..
- python $CURRENTDIR/../bin/wsserver.py --config $CONFIGFILE
- exit 0
-fi
diff --git a/server/trackdirect/TrackDirectConfig.py b/server/trackdirect/TrackDirectConfig.py
deleted file mode 100644
index 422d26afcbf2400e5bf48b2b0e50b6c6bf38b574..0000000000000000000000000000000000000000
--- a/server/trackdirect/TrackDirectConfig.py
+++ /dev/null
@@ -1,190 +0,0 @@
-import os
-import os.path
-import configparser
-
-from trackdirect.common.Singleton import Singleton
-
-
-class TrackDirectConfig(Singleton):
- """Track Direct Config class
- """
-
- def __init__(self):
- """The __init__ method.
- """
- self.collector = {}
-
- def populate(self, configFile):
- """The __init__ method.
-
- Args:
- configFile (string): Config file name
- """
- configParser = configparser.SafeConfigParser()
- if (configFile.startswith('/')):
- configParser.read(os.path.expanduser(configFile))
- else:
- configParser.read(os.path.expanduser(
- '~/trackdirect/config/' + configFile))
-
- # Database
- self.dbHostname = configParser.get('database', 'host').strip('"')
- self.dbName = configParser.get('database', 'database').strip('"')
- try:
- self.dbUsername = configParser.get(
- 'database', 'username').strip('"')
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.dbUsername = os.getlogin()
- self.dbPassword = configParser.get('database', 'password').strip('"')
- self.dbPort = int(configParser.get('database', 'port').strip('"'))
- self.daysToSavePositionData = int(configParser.get(
- 'database', 'days_to_save_position_data').strip('"'))
- self.daysToSaveStationData = int(configParser.get(
- 'database', 'days_to_save_station_data').strip('"'))
- self.daysToSaveWeatherData = int(configParser.get(
- 'database', 'days_to_save_weather_data').strip('"'))
- self.daysToSaveTelemetryData = int(configParser.get(
- 'database', 'days_to_save_telemetry_data').strip('"'))
-
- self.saveOgnStationsWithMissingIdentity = False
- try:
- saveOgnStationsWithMissingIdentity = configParser.get(
- 'database', 'save_ogn_stations_with_missing_identity').strip('"')
- if (saveOgnStationsWithMissingIdentity == "1"):
- self.saveOgnStationsWithMissingIdentity = True
- except (configparser.NoSectionError, configparser.NoOptionError):
- pass
-
- # Websocket server
- self.websocketHostname = configParser.get(
- 'websocket_server', 'host').strip('"')
- self.websocketPort = int(configParser.get(
- 'websocket_server', 'port').strip('"'))
-
- self.websocketExternalPort = self.websocketPort
- try :
- self.websocketExternalPort = int(configParser.get(
- 'websocket_server', 'external_port').strip('"'))
- except (configparser.NoSectionError, configparser.NoOptionError):
- pass
-
- self.errorLog = configParser.get(
- 'websocket_server', 'error_log').strip('"')
- self.websocketFrequencyLimit = configParser.get(
- 'websocket_server', 'frequency_limit').strip('"')
-
- self.maxDefaultTime = int(configParser.get(
- 'websocket_server', 'max_default_time').strip('"'))
- self.maxFilterTime = int(configParser.get(
- 'websocket_server', 'max_filter_time').strip('"'))
- self.maxClientIdleTime = int(configParser.get(
- 'websocket_server', 'max_client_idle_time').strip('"'))
- self.maxQueuedRealtimePackets = int(configParser.get(
- 'websocket_server', 'max_queued_realtime_packets').strip('"'))
-
- allowTimeTravel = configParser.get(
- 'websocket_server', 'allow_time_travel').strip('"')
- self.allowTimeTravel = False
- if (allowTimeTravel == "1"):
- self.allowTimeTravel = True
-
- # Websocket server APRS connection (we support 2 different sources, more can be added...)
- try:
- self.websocketAprsHost1 = configParser.get(
- 'websocket_server', 'aprs_host1').strip('"')
- self.websocketAprsPort1 = configParser.get(
- 'websocket_server', 'aprs_port1').strip('"')
- self.websocketAprsSourceId1 = int(configParser.get(
- 'websocket_server', 'aprs_source_id1').strip('"'))
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.websocketAprsSourceId1 = None
- self.websocketAprsHost1 = None
- self.websocketAprsPort1 = None
-
- try:
- self.websocketAprsHost2 = configParser.get(
- 'websocket_server', 'aprs_host2').strip('"')
- self.websocketAprsPort2 = configParser.get(
- 'websocket_server', 'aprs_port2').strip('"')
- self.websocketAprsSourceId2 = int(configParser.get(
- 'websocket_server', 'aprs_source_id2').strip('"'))
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.websocketAprsSourceId2 = None
- self.websocketAprsHost2 = None
- self.websocketAprsPort2 = None
-
- if (self.websocketAprsSourceId1 == 5 or self.websocketAprsSourceId2 == 5) :
- # At least one source is of type OGN, disable display of older data
- self.allowTimeTravel = False
- if (self.maxDefaultTime > 1440) :
- self.maxDefaultTime = 1440
- if (self.maxFilterTime > 1440) :
- self.maxDefaultTime = 1440
-
- # Collectors
- for collectorNumber in range(0, 5):
- self.collector[collectorNumber] = {}
- try:
- self.collector[collectorNumber]['source_id'] = int(configParser.get(
- 'collector' + str(collectorNumber), 'source_id').strip('"'))
- self.collector[collectorNumber]['host'] = configParser.get(
- 'collector' + str(collectorNumber), 'host').strip('"')
- self.collector[collectorNumber]['port_full'] = int(configParser.get(
- 'collector' + str(collectorNumber), 'port_full').strip('"'))
- self.collector[collectorNumber]['port_filtered'] = int(configParser.get(
- 'collector' + str(collectorNumber), 'port_filtered').strip('"'))
-
- self.collector[collectorNumber]['callsign'] = configParser.get(
- 'collector' + str(collectorNumber), 'callsign').strip('"')
- self.collector[collectorNumber]['passcode'] = configParser.get(
- 'collector' + str(collectorNumber), 'passcode').strip('"')
-
- self.collector[collectorNumber]['numbers_in_batch'] = configParser.get(
- 'collector' + str(collectorNumber), 'numbers_in_batch').strip('"')
- try:
- self.collector[collectorNumber]['frequency_limit'] = int(configParser.get(
- 'collector' + str(collectorNumber), 'frequency_limit').strip('"'))
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.collector[collectorNumber]['frequency_limit'] = 0
-
- try:
- saveFastPackets = configParser.get(
- 'collector' + str(collectorNumber), 'save_fast_packets').strip('"')
- self.collector[collectorNumber]['save_fast_packets'] = bool(
- int(saveFastPackets))
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.collector[collectorNumber]['save_fast_packets'] = False
-
- try:
- detectDuplicates = configParser.get(
- 'collector' + str(collectorNumber), 'detect_duplicates').strip('"')
- self.collector[collectorNumber]['detect_duplicates'] = bool(
- int(detectDuplicates))
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.collector[collectorNumber]['detect_duplicates'] = False
-
- self.collector[collectorNumber]['error_log'] = configParser.get(
- 'collector' + str(collectorNumber), 'error_log').strip('"')
-
- if (self.websocketAprsSourceId1 == 5 or self.websocketAprsSourceId2 == 5) :
- # source is of type OGN, make sure we do not save to many packets (will cause to high load on db)
- if (self.collector[collectorNumber]['frequency_limit'] < 10) :
- self.collector[collectorNumber]['frequency_limit'] = 10
- self.collector[collectorNumber]['save_fast_packets'] = False
-
-
- except (configparser.NoSectionError, configparser.NoOptionError):
- self.collector[collectorNumber]['source_id'] = None
- self.collector[collectorNumber]['host'] = None
- self.collector[collectorNumber]['port_full'] = None
- self.collector[collectorNumber]['port_filtered'] = None
-
- self.collector[collectorNumber]['callsign'] = None
- self.collector[collectorNumber]['passcode'] = None
-
- self.collector[collectorNumber]['numbers_in_batch'] = "20"
- self.collector[collectorNumber]['frequency_limit'] = "0"
- self.collector[collectorNumber]['save_fast_packets'] = True
- self.collector[collectorNumber]['detect_duplicates'] = False
-
- self.collector[collectorNumber]['error_log'] = None
diff --git a/server/trackdirect/TrackDirectDataCollector.py b/server/trackdirect/TrackDirectDataCollector.py
deleted file mode 100644
index 63959b197bf4dfc6724add2bfb144516423d34be..0000000000000000000000000000000000000000
--- a/server/trackdirect/TrackDirectDataCollector.py
+++ /dev/null
@@ -1,524 +0,0 @@
-import logging
-import psycopg2
-import psycopg2.extras
-import re
-import aprslib
-import datetime
-import time
-from twisted.internet import reactor, threads
-
-from trackdirect.parser.AprsPacketParser import AprsPacketParser
-from trackdirect.parser.AprsISConnection import AprsISConnection
-from trackdirect.parser.policies.PacketDuplicatePolicy import PacketDuplicatePolicy
-from trackdirect.collector.PacketBatchInserter import PacketBatchInserter
-from trackdirect.exceptions.TrackDirectParseError import TrackDirectParseError
-from trackdirect.database.DatabaseConnection import DatabaseConnection
-from trackdirect.repositories.StationRepository import StationRepository
-
-#from pympler.tracker import SummaryTracker
-
-class TrackDirectDataCollector():
- """An TrackDirectDataCollector instance connects to the data source and saves all received packets to the database
-
- Note:
- The collector class is built to handle ONE connection to a data source server (may be a APRS-IS server), if two is wanted run two processes.
- This is useful if you want one connection to the regular APRS-IS network and one connection to the CWOP network.
- """
-
- def __init__(self, collectorOptions, saveOgnStationsWithMissingIdentity):
- """The __init__ method.
-
- Args:
- collectorOptions (dict): Contains data like host, port, callsign, passcode, source id
- saveOgnStationsWithMissingIdentity (boolean): True if we should not ignore stationss with a missing identity
- """
- self.saveOgnStationsWithMissingIdentity = saveOgnStationsWithMissingIdentity
- self.sourceHostname = collectorOptions['host']
- self.sourcePort = collectorOptions['port_full']
- self.numbersInBatch = collectorOptions['numbers_in_batch']
- self.saveFastPackets = collectorOptions['save_fast_packets']
- self.frequencyLimit = collectorOptions['frequency_limit']
- self.detectDuplicates = collectorOptions['detect_duplicates']
- self.hardFrequencyLimit = None
- if (not self.saveFastPackets and self.frequencyLimit is not None and int(self.frequencyLimit) > 0):
- # Only respect hard frequency limit if we are not saving "fast packets"
- self.hardFrequencyLimit = self.frequencyLimit
- self.sourceId = collectorOptions['source_id']
- self.callsign = collectorOptions['callsign']
- self.passcode = collectorOptions['passcode']
-
- dbConnection = DatabaseConnection()
- self.db = dbConnection.getConnection(True)
- self.dbNoAutoCommit = dbConnection.getConnection(False)
-
- self.stationRepository = StationRepository(self.db)
- self.logger = logging.getLogger(__name__)
-
- self.latestPacketTimestamp = None
- self.firstPacketTimestamp = None
- self.latestBatchInsertTimestamp = int(time.time())
-
- self.packets = []
- self.stationIdsWithVisiblePacket = []
- self.movingStationIdsWithVisiblePacket = []
- self.movingMarkerIdsWithVisiblePacket = []
- self.delay = 0
-
- def run(self):
- """Start the collector
- """
- threads.deferToThread(self.consume)
- # reactor.suggestThreadPoolSize(20)
- reactor.run()
-
- def consume(self):
- """Start consuming packets
- """
-
- #tracker = SummaryTracker()
-
- connection = AprsISConnection(
- self.callsign, self.passcode, self.sourceHostname, self.sourcePort)
- connection.setFrequencyLimit(self.hardFrequencyLimit)
- connection.setSourceId(self.sourceId)
-
- def onPacketRead(line):
- if (not reactor.running):
- raise StopIteration('Stopped')
-
- timestamp = int(time.time())
- deferred = threads.deferToThread(self._parse, line, timestamp)
- deferred.addCallback(onParseComplete)
- deferred.addErrback(onParseError)
-
- def onParseComplete(packet):
- reactor.callFromThread(self._addPacket, packet)
-
- def onParseError(error):
- # Parse will more or less only cast exception if db connection is lost
-
- # Force restart of collector (we assume that server will be autostarted if stopped)
- if reactor.running:
- reactor.stop()
- raise error
-
- try:
- connection.connect()
- connection.filteredConsumer(onPacketRead, True, True)
-
- #tracker.print_diff()
-
- except (aprslib.ConnectionDrop) as exp:
- # Just reconnect...
- self.logger.warning('Lost connection')
- self.logger.warning(exp)
- self.consume()
-
- except Exception as e:
- self.logger.error(e)
-
- # Force restart of collector
- if reactor.running:
- reactor.stop()
-
- def _parse(self, line, timestamp):
- """Parse raw packet
-
- Args:
- line (string): APRS raw packet string
- timestamp (int): Receive time of packet
-
- Returns:
- Returns a Packet
- """
- try:
- self.delay = int(time.time())-timestamp
- if (self.delay > 60):
- self.logger.error(
- 'Collector has a delay on %s seconds, ignoring packets until solved', self.delay)
- return None
- elif (self.delay > 15):
- self.logger.warning(
- 'Collector has a delay on %s seconds', self.delay)
-
- packetDict = aprslib.parse(line)
- parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
- parser.setSourceId(self.sourceId)
- packet = parser.getPacket(packetDict, timestamp)
-
- if (packet.mapId == 15 or packet.mapId == 16):
- return None
-
- if (self.detectDuplicates):
- self._checkIfDuplicate(packet)
-
- return self._cleanPacket(packet)
-
- except (aprslib.ParseError, aprslib.UnknownFormat, TrackDirectParseError) as exp:
- return self._parseUnsupportedPacket(line, timestamp)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except (UnicodeDecodeError) as exp:
- # just forget about this packet
- pass
- except Exception as e:
- self.logger.error(e, exc_info=1)
- return None
-
- def _parseUnsupportedPacket(self, line, timestamp):
- """Try to parse raw packet that aprs-lib could not handle
-
- Args:
- line (string): APRS raw packet string
- timestamp (int): Receive time of packet
-
- Returns:
- Returns a Packet
- """
- try:
- line = line.decode('utf-8', 'ignore')
- packetDict = self.basicParse(line)
- parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
- parser.setSourceId(self.sourceId)
- packet = parser.getPacket(packetDict, timestamp, True)
- packet.markerId = 1
-
- if (packet.packetTypeId == 6): # Telemetry packet
- packet.packetTypeId = 10 # Has no position
- else:
- packet.mapId = 11 # Unsupported packet
-
- return packet
- except Exception as e:
- self.logger.debug(e)
- self.logger.debug(line)
- return None
-
- def _addPacket(self, packet):
- """Adds packet to database
-
- Args:
- packet (Packet): The packet
- """
- if (packet is None):
- return
-
- # Soft frequency limit check
- if (self._isStationSendingToFast(packet)):
- if (not self.saveFastPackets):
- return
-
- packet.markerId = 1
- packet.mapId = 8
-
- # Reset all mapId related values
- packet.replacePacketId = None
- packet.abnormalPacketId = None
- packet.confirmPacketId = None
- packet.replacePacketTimestamp = None
- packet.abnormalPacketTimestamp = None
- packet.confirmPacketTimestamp = None
-
- if (packet.mapId == 6):
- # Packet received in wrong order
- if (not self.saveFastPackets):
- return
-
- if (not self._isPacketValidInCurrentBatch(packet)):
- self._insertBatch()
-
- if (self._shouldPacketBeAdded(packet)):
- self._addPacketToBatch(packet)
-
- if (self._isBatchFull()):
- self._insertBatch()
-
- if (self._isBatchOld()):
- self._insertBatch()
-
- def _isStationSendingToFast(self, packet):
- """Returns true if this packet has been sent to close to previous packet from the same station (we need to save previous packet first)
-
- Args:
- packet (Packet) : The packet that may have been sent to fast
-
- Returns:
- Boolean
- """
- if (packet.mapId in [1, 5, 7, 9] and packet.isMoving == 1 and self.frequencyLimit is not None):
- frequencyLimitToApply = int(self.frequencyLimit)
-
- if (frequencyLimitToApply == 0):
- return False
-
- if (packet.ogn is not None and packet.ogn.ognTurnRate is not None):
- turnRate = abs(float(packet.ogn.ognTurnRate))
- if (turnRate > 0) :
- frequencyLimitToApply = int(frequencyLimitToApply / (1+turnRate))
-
- if packet.markerPrevPacketTimestamp:
- if ((packet.timestamp - frequencyLimitToApply) < packet.markerPrevPacketTimestamp):
- # This station is sending faster than config limit
- return True
-
- if (packet.stationId in self.movingStationIdsWithVisiblePacket):
- # This station is sending way to fast (we havn't even added the previous packet to database yet)
- return True
-
- if (packet.markerId in self.movingMarkerIdsWithVisiblePacket):
- # The senders of this object is sending way to fast (we havn't even added the previous packet to database yet)
- return True
- return False
-
- def _isPacketValidInCurrentBatch(self, packet):
- """Returns true if this packet can be added to current batch
-
- Args:
- packet (Packet) : The packet that e want to add to current batch
-
- Returns:
- Boolean
- """
- if (self.latestPacketTimestamp is not None):
- # If previous packet belongs to another date we can not add packet to current batch
- currentPacketDate = datetime.datetime.utcfromtimestamp(
- int(packet.timestamp)).strftime('%Y%m%d')
- latestPacketDate = datetime.datetime.utcfromtimestamp(
- self.latestPacketTimestamp).strftime('%Y%m%d')
-
- if (currentPacketDate != latestPacketDate and len(self.packets) > 0):
- return False
-
- if (packet.stationId in self.stationIdsWithVisiblePacket):
- # We only want to handle one packet per station per batch
- return False
-
- return True
-
- def _shouldPacketBeAdded(self, packet):
- """Returns true if this packet should be added to database
-
- Args:
- packet (Packet) : The packet that we want to add to batch
-
- Returns:
- Boolean
- """
- if (packet.sourceId != 3 or packet.stationIdPath):
- # We only add pure duplicates to batch if they have a path, otherwise we are not interested
- return True
- return False
-
- def _isBatchFull(self):
- """Returns true if batch is considered full
-
- Returns:
- Boolean
- """
- # If we do insert when we have specified amount of packets (or if more than 5s has passed)
- if (int(len(self.packets)) > int(self.numbersInBatch)):
- return True
- elif (len(self.packets) > 0 and self.latestBatchInsertTimestamp < int(time.time()) - 5):
- return True
- return False
-
- def _isBatchOld(self):
- """Returns true if batch is considered old
-
- Returns:
- Boolean
- """
- if (self.latestPacketTimestamp is not None
- and self.firstPacketTimestamp is not None
- and self.latestPacketTimestamp - self.firstPacketTimestamp > 1):
- return True
- return False
-
- def _addPacketToBatch(self, packet):
- """Add instance of ParsedPacket to batch
-
- Args:
- packet (Packet): Packet that we want to add to batch
- """
- self.latestPacketTimestamp = int(packet.timestamp)
- if (self.firstPacketTimestamp is None):
- self.firstPacketTimestamp = int(packet.timestamp)
- self.packets.append(packet)
- if (packet.mapId in [1, 5, 7, 9]):
- self.stationIdsWithVisiblePacket.append(packet.stationId)
- if (packet.isMoving == 1):
- self.movingStationIdsWithVisiblePacket.append(packet.stationId)
- self.movingMarkerIdsWithVisiblePacket.append(packet.markerId)
-
- def _insertBatch(self):
- """Perform insert on the current batch
- """
- if (len(self.packets) > 0):
- self.latestBatchInsertTimestamp = int(time.time())
-
- # Make sure packets is inserted in the order that they where received
- self.packets.reverse()
-
- # Do batch insert
- packetBatchInserter = PacketBatchInserter(
- self.db, self.dbNoAutoCommit)
- packetBatchInserter.insert(self.packets[:], self.sourceId)
-
- self._reset()
-
- def _reset(self):
- """Reset all collector variables
- """
- self.packets = []
- self.stationIdsWithVisiblePacket = []
- self.movingStationIdsWithVisiblePacket = []
- self.movingMarkerIdsWithVisiblePacket = []
- self.latestPacketTimestamp = None
- self.firstPacketTimestamp = None
-
- def _cleanPacket(self, packet):
- """Method used to clean a Packet from unused columns
-
- Args:
- packet (Packet): Object of class Packet
-
- Returns:
- Returns a packet (cleaned)
- """
- if (packet.mapId not in [1, 5, 7, 9]):
- # This packet will never be shown on map, remove information that won't be used (just to save some space in database)
- packet.markerId = None
- packet.markerCounter = None
- packet.packetTailTimestamp = None
- packet.positionTimestamp = None
- packet.posambiguity = None
- packet.symbol = None
- packet.symbolTable = None
- packet.mapSector = None
- packet.relatedMapSectors = None
- packet.speed = None
- packet.course = None
- packet.altitude = None
- packet.isMoving = 1
- return packet
-
- def _checkIfDuplicate(self, packet):
- """Method used to check if this packet is a duplicate
-
- Note:
- If packet is a duplicate the object attribute mapId will be updated, and some related attributes.
-
- Args:
- packet (Packet): Object of class Packet
- """
- packetDuplicatePolicy = PacketDuplicatePolicy(self.stationRepository)
- if (packetDuplicatePolicy.isDuplicate(packet)):
- # It is a duplicate (or at least we treat it as one just to be safe)
- packet.mapId = 3
- packet.markerId = 1
- packet.replacePacketId = None # No older packet should be replaced!!!
- packet.replacePacketTimestamp = None
- packet.abnormalPacketId = None # Do not mark previous as abnormal yet
- packet.abnormalPacketTimestamp = None
- packet.confirmPacketId = None # Do not confirm previous position
- packet.confirmPacketTimestamp = None
-
- def basicParse(self, line):
- """Performes a basic packet parse and returnes result as a dict
-
- Args:
- line (string): Packet raw string
-
- Returns:
- Returns packet dict
- """
- # Divide into body and head
- try:
- (head, body) = line.split(':', 1)
- except:
- raise TrackDirectParseError("no body", {})
-
- if len(body) == 0:
- raise TrackDirectParseError("body is empty", {})
-
- packetType = body[0]
- body = body[1:]
-
- # Find sender, destination and path in header
- try:
- (fromcall, path) = head.split('>', 1)
- except:
- raise TrackDirectParseError("no header", {})
-
- if (not 1 <= len(fromcall) <= 9):
- raise TrackDirectParseError("fromcallsign has invalid length", {})
-
- path = path.split(',')
- tocall = path[0]
-
- if len(tocall) == 0:
- tocall = None
-
- path = path[1:]
-
- for station in path:
- if not re.findall(r"^[A-Z0-9\-]{1,9}\*?$", station, re.I):
- path = None
- break
-
- objectName = ''
- if packetType == ';':
- match = re.findall(r"^([ -~]{9})(\*|_)", body)
- if match:
- name, flag = match[0]
- objectName = name
- body = body[10:]
-
- if packetType == ')':
- match = re.findall(r"^([ -~!]{3,9})(\!|_)", body)
- if match:
- name, flag = match[0]
- objectName = name
- body = body[len(name)+1:]
-
- comment = None
- telemetry = None
- if packetType == 'T':
- telemetry = {}
- lst = body.split(',')
- if len(lst) >= 7 :
- seq = body.split(',')[0]
- vals = body.split(',')[1:6]
- bits = body.split(',')[6][:8]
- comment = body.split(',')[6][8:]
-
- if seq.startswith('T'):
- seq = seq[1:]
- if seq.startswith('#'):
- seq = seq[1:]
-
- for i in range(5):
- try:
- vals[i] = float(vals[i]) if vals[i] != '' else None
- except ValueError:
- vals[i] = None
-
- telemetry = {
- 'seq': seq,
- 'vals': vals,
- 'bits': bits
- }
-
- # Create result
- packet = {
- 'from': fromcall,
- 'to': tocall,
- 'path': path,
- 'raw': line,
- 'object_name': objectName,
- 'packet_type': packetType,
- 'telemetry': telemetry,
- 'comment': comment
- }
- return packet
diff --git a/server/trackdirect/TrackDirectWebsocketServer.py b/server/trackdirect/TrackDirectWebsocketServer.py
deleted file mode 100644
index fe9a0706c957f011ea84cdbd05a2e63dfc0aa1b0..0000000000000000000000000000000000000000
--- a/server/trackdirect/TrackDirectWebsocketServer.py
+++ /dev/null
@@ -1,434 +0,0 @@
-import logging
-
-from twisted.internet import threads, reactor, task
-from twisted.internet.error import AlreadyCancelled, AlreadyCalled
-
-from autobahn.twisted.websocket import WebSocketServerProtocol
-
-import json
-import time
-import psycopg2
-import psycopg2.extras
-import os
-import trackdirect
-from trackdirect.database.DatabaseConnection import DatabaseConnection
-
-from trackdirect.websocket.WebsocketResponseCreator import WebsocketResponseCreator
-from trackdirect.websocket.WebsocketConnectionState import WebsocketConnectionState
-
-from trackdirect.websocket.aprsis.AprsISReader import AprsISReader
-from trackdirect.websocket.aprsis.AprsISPayloadCreator import AprsISPayloadCreator
-
-
-class TrackDirectWebsocketServer(WebSocketServerProtocol):
- """The TrackDirectWebsocketServer class handles the incoming requests
- """
-
- def __init__(self):
- """The __init__ method.
- """
- WebSocketServerProtocol.__init__(self)
- self.logger = logging.getLogger('trackdirect')
-
- self.config = trackdirect.TrackDirectConfig()
- self.maxClientIdleTime = int(self.config.maxClientIdleTime) * 60
- self.maxQueuedRealtimePackets = int(
- self.config.maxQueuedRealtimePackets)
-
- dbConnection = DatabaseConnection()
- db = dbConnection.getConnection(True)
-
- self.connectionState = WebsocketConnectionState()
- self.responseCreator = WebsocketResponseCreator(
- self.connectionState, db)
- self.aprsISReader = AprsISReader(self.connectionState, db)
- self.aprsISPayloadCreator = AprsISPayloadCreator(
- self.connectionState, db)
-
- self.numberOfRealTimePacketThreads = 0
- self.timestampSenderCall = None
- self.realTimeListenerCall = None
- self.onInactiveCall = None
- self.isUnknownClient = False
-
- def onConnect(self, request):
- """Method that is executed on connect
-
- Args:
- request (object): The connection request
- """
- try:
- if ('x-forwarded-for' in request.headers):
- self.logger.warning("Client connecting from origin: {0}, x-forwarded-for: {1} (server pid {2})".format(
- request.origin, request.headers['x-forwarded-for'], str(os.getpid())))
- else:
- self.logger.warning(
- "Client connecting from origin: {0} (server pid {1})".format(request.origin, str(os.getpid())))
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
- raise e
-
- def onOpen(self):
- """Method that is executed on open
- """
- try:
- self.logger.info("WebSocket connection open.")
-
- self._sendResponseByType(42) # Inform client that we are active
- self._startTimestampSender()
- self._reScheduleInactiveEvent()
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- def onMessage(self, payload, isBinary):
- """Method that is executed on incoming message
-
- Args:
- request (object): The connection request
- isBinary (boolean): True if binary otherwise false
- """
- try:
- request = json.loads(payload)
- if (self.isUnknownClient):
- self.logger.warning(
- "Incoming message from unknown client: {0}".format(str(request)))
-
- if ("payload_request_type" not in request):
- self.logger.warning(
- "Incoming request has no type (%s)" % (exp))
- self.logger.warning(payload)
- return
- self._onRequest(request)
- except (ValueError) as exp:
- self.logger.warning(
- "Incoming request could not be parsed (%s)" % (exp))
- self.logger.warning(payload)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def onClose(self, wasClean, code, reason):
- """Method that is executed on close
-
- Args:
- wasClean (boolean): True if clean close otherwise false
- code (int): Close code
- reason (object): Reason for close
- """
- try:
- self.logger.info("WebSocket connection closed: {0}".format(reason))
- self.connectionState.disconnected = True
- self._stopTimestampSender()
- self._stopRealTimeListener(True)
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _onRequest(self, request, requestId=None):
- """Method that is executed on incoming request
-
- Args:
- request (object): The connection request
- requestId (int): Id of the request
- """
- if (request["payload_request_type"] != 11):
- self._reScheduleInactiveEvent()
-
- if (request["payload_request_type"] in [5, 7, 9]):
- # Request that not affects the current map status (to much)
- deferred = threads.deferToThread(
- self._processRequest, request, None)
- deferred.addErrback(self._onError)
-
- else:
- # Request that affects map and current state
- if (requestId is None):
- requestId = self.connectionState.latestRequestId + 1
- self.connectionState.latestRequestType = request["payload_request_type"]
- self.connectionState.latestRequestId = requestId
- self.connectionState.latestRequestTimestamp = int(time.time())
- self._stopRealTimeListener(False)
-
- if (self.connectionState.latestHandledRequestId < requestId - 1):
- reactor.callLater(0.1, self._onRequest, request, requestId)
- else:
- self._updateState(request)
-
- deferred = threads.deferToThread(
- self._processRequest, request, requestId)
- deferred.addErrback(self._onError)
- deferred.addCallback(self._onRequestDone)
-
- def _processRequest(self, request, requestId):
- """Method that sends a response to websocket client based on request
-
- Args:
- request (Dict): Request from websocket client
- requestId (int): Request id of processed request
- """
- try:
- for response in self.responseCreator.getResponses(request, requestId):
- if self.connectionState.disconnected:
- break
- reactor.callFromThread(self._sendDictResponse, response)
- return requestId
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _onRequestDone(self, requestId):
- """Method that is executed when request is processed
-
- Args:
- requestId (int): Request id of processed request
- """
- try:
- if (self.connectionState.latestHandledRequestId < requestId):
- self.connectionState.latestHandledRequestId = requestId
- if (self.connectionState.latestRequestId == requestId):
- # We have no newer requests
- # Tell client response is complete
- self._sendResponseByType(35)
-
- if (self.connectionState.latestTimeTravelRequest is None
- and self.connectionState.noRealTime is False
- and self.connectionState.isValidLatestPosition()):
- self._startRealTimeListener(requestId)
-
- elif ((int(time.time()) - self.connectionState.latestRequestTimestamp) <= self.maxClientIdleTime):
- self._sendResponseByType(33) # Tell client we are idle
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _onError(self, error):
- """Method that is executed when a deferToThread failed
-
- Args:
- error (Exception): The Exception
- """
- # Exception should only end up here if db connection is lost
- # Force restart of wsserver
- if reactor.running:
- reactor.stop()
- raise error
-
- def _startRealTimeListener(self, relatedRequestId):
- """Start real time APRS-IS listener, onRealTimePacketFound will be executed when a packet is received
-
- Args:
- relatedRequestId (int): Request id of related request
- """
- def readRealTimePacket():
- if (self.connectionState.latestRequestId == relatedRequestId and not self.connectionState.disconnected):
- self.aprsISReader.read(onRealTimePacketFound)
-
- def onRealTimePacketComplete():
- self.numberOfRealTimePacketThreads -= 1
- if (self.numberOfRealTimePacketThreads <= 0):
- # If we have no packets on the way we should see if we have another waiting
- readRealTimePacket()
-
- def onRealTimePacketFound(raw, sourceId):
- if (raw is None and sourceId is None):
- # Something went wrong, stop everything
- self._onInactive()
- else:
- if (self.numberOfRealTimePacketThreads > self.maxQueuedRealtimePackets):
- # To many packets, several previous LoopingCall's is not done yet.
- # We need to discard some packets, otherwise server will be overloaded and we will only send old packets.
- # Client is required to request total update now and then, so the discarded packets should be send to client later.
-
- counter = self.aprsISReader.clear(5)
- #self.logger.warning('Discarding ' + str(counter) + ' packets')
- else:
- self.numberOfRealTimePacketThreads += 1
- deferred = threads.deferToThread(
- self._processRealTimePacket, raw, sourceId)
- deferred.addCallback(lambda _: onRealTimePacketComplete())
- deferred.addErrback(self._onError)
-
- # Tell client we are connecting to real time feed
- self._sendResponseByType(34)
- self.aprsISReader.start() # Will start if needed and change filter if needed
- # Tell client we are listening on real time feed
- self._sendResponseByType(31)
-
- self.realTimeListenerCall = task.LoopingCall(readRealTimePacket)
- self.realTimeListenerCall.start(0.2)
-
- def _stopRealTimeListener(self, disconnect=False):
- """Stop real time APRS-IS listener, onRealTimePacketFound will be executed when a packet is received
-
- Args:
- disconnect (Boolean): Set to true to also disconnect from APRS-IS servers
- """
- if (self.realTimeListenerCall is not None):
- try:
- self.realTimeListenerCall.stop()
- except (AlreadyCalled, AssertionError) as e:
- pass
-
- if (disconnect):
- self.aprsISReader.stop()
- else:
- self.aprsISReader.pause()
-
- def _processRealTimePacket(self, raw, sourceId):
- """Method that is executed when we have a new real time packet to send
-
- Args:
- raw (string): Raw packet from APRS-IS
- sourceId (int): The id of the source (1 for APRS and 2 for CWOP ...)
- """
- try:
- for response in self.aprsISPayloadCreator.getPayloads(raw, sourceId):
- reactor.callFromThread(self._sendDictResponse, response)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _startTimestampSender(self):
- """Method schedules call to _sendTimestampResponse to keep connection up
- """
- self.timestampSenderCall = task.LoopingCall(
- self._sendTimestampResponse)
- self.timestampSenderCall.start(1.0)
-
- def _stopTimestampSender(self):
- """Stop looping call to _sendTimestampResponse
- """
- if (self.timestampSenderCall is not None):
- try:
- self.timestampSenderCall.stop()
- except AssertionError as e:
- pass
-
- def _reScheduleInactiveEvent(self):
- """Method schedules call to _onInactive when client has been idle too long
-
- Note:
- When _reScheduleInactiveEvent is called any previous schedules will be cancelled and countdown will be reset
- """
- if (self.onInactiveCall is not None):
- try:
- self.onInactiveCall.cancel()
- except (AlreadyCalled, AlreadyCancelled) as e:
- pass
- self.onInactiveCall = reactor.callLater(
- self.maxClientIdleTime, self._onInactive)
-
- def _onInactive(self):
- """Method that is executed when client has been inactive too long
- """
- try:
- # Client is inactive, pause (to save bandwidth, cpu and memory)
- self._sendResponseByType(36)
- self._stopTimestampSender()
- self._stopRealTimeListener(True)
- self.connectionState.totalReset()
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _sendTimestampResponse(self):
- """Send server timestamp to syncronize server and client
-
- Notes:
- This is also used to tell the client that we are still here
- Most browser will disconnect if they do not hear anything in 300sec
- """
- try:
- if (self.connectionState.latestHandledRequestId < self.connectionState.latestRequestId):
- # server is busy with request, no point in doing this now
- return
- data = {}
- data["timestamp"] = int(time.time())
- self._sendResponseByType(41, data)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.error(e, exc_info=1)
-
- def _sendResponseByType(self, payloadResponseType, data=None):
- """Send specified response to client
-
- Args:
- payloadResponseType (int): A number that specifies what type of response we are sending
- data (dict): The response data as a dict
- """
- if (data is not None):
- payload = {
- 'payload_response_type': payloadResponseType, 'data': data}
- else:
- payload = {'payload_response_type': payloadResponseType}
- self._sendDictResponse(payload)
-
- def _sendDictResponse(self, payload):
- """Send message dict payload to client
-
- Args:
- payload (Dict): Response payload
- """
- try:
- jsonPayload = json.dumps(payload, ensure_ascii=True).encode('utf8')
- if (jsonPayload is not None):
- self.sendMessage(jsonPayload)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just terminate connection to make user reconnect with new db connection
- self.logger.error(e, exc_info=1)
- raise e
- except Exception as e:
- # Log error to make us aware of unknow problem
- self.logger.warning(e, exc_info=1)
-
- def _updateState(self, request):
- """Update the connection state based on request
-
- Args:
- request (Dict): Request form client
- """
- if ("neLat" in request
- and "neLng" in request
- and "swLat" in request
- and "swLng" in request
- and "minutes" in request):
- self.connectionState.setLatestMapBounds(
- request["neLat"], request["neLng"], request["swLat"], request["swLng"])
-
- if ("onlyLatestPacket" in request):
- self.connectionState.setOnlyLatestPacketRequested(
- (request["onlyLatestPacket"] == 1))
-
- if ("minutes" in request):
- if ("time" in request):
- self.connectionState.setLatestMinutes(
- request["minutes"], request["time"])
- else:
- self.connectionState.setLatestMinutes(request["minutes"], None)
-
- if ("noRealTime" in request):
- self.connectionState.disableRealTime()
diff --git a/server/trackdirect/__init__.py b/server/trackdirect/__init__.py
deleted file mode 100644
index 27c9b557ec18ba62184bcaf63c90ac1d8b8606d3..0000000000000000000000000000000000000000
--- a/server/trackdirect/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
-
-from TrackDirectDataCollector import *
-from TrackDirectWebsocketServer import *
-from TrackDirectConfig import *
diff --git a/server/trackdirect/collector/PacketBatchInserter.py b/server/trackdirect/collector/PacketBatchInserter.py
deleted file mode 100644
index a0899d440a0d3e113ce343b5e5abb7b7d28b14c9..0000000000000000000000000000000000000000
--- a/server/trackdirect/collector/PacketBatchInserter.py
+++ /dev/null
@@ -1,425 +0,0 @@
-import logging
-import psycopg2
-import psycopg2.extras
-
-from trackdirect.collector.StationLatestPacketModifier import StationLatestPacketModifier
-from trackdirect.collector.PacketMapIdModifier import PacketMapIdModifier
-
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-from trackdirect.database.PacketPathTableCreator import PacketPathTableCreator
-from trackdirect.database.PacketWeatherTableCreator import PacketWeatherTableCreator
-from trackdirect.database.PacketTelemetryTableCreator import PacketTelemetryTableCreator
-from trackdirect.database.PacketOgnTableCreator import PacketOgnTableCreator
-
-
-class PacketBatchInserter():
- """PacketBatchInserter is used to add a list of packets to the database
- """
-
- def __init__(self, db, dbNoAutoCommit):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection (with autocommit)
- dbNoAutoCommit (psycopg2.Connection): Database connection (without autocommit)
- """
- self.db = db
- self.dbNoAutoCommit = dbNoAutoCommit
- self.logger = logging.getLogger(__name__)
-
- self.packetIdList = []
- self.weatherPacketIdList = []
- self.ognPacketIdList = []
- self.telemetryPacketIdList = []
- self.pathPacketIdList = []
- self.positionPacketIdList = []
- self.confirmedPositionPacketIdList = []
-
- def insert(self, packets, sourceId):
- """Insert this packets into database
-
- Args:
- packets (array): Packets to insert
- sourceId (int): Id that corresponds to id in source-table
- """
- cur = self.dbNoAutoCommit.cursor()
- try:
- # Make sure needed tables exists before starting the main database transaction
- self._makeSureTablesExists(packets)
-
- # insert telemetry data
- self._insertTelemetryDefinitions(packets)
-
- # Update mapId on previous packets
- packetTableCreator = PacketTableCreator(self.db)
- packetMapIdModifier = PacketMapIdModifier(cur, packetTableCreator)
- packetMapIdModifier.execute(packets)
-
- # insert into packet (and packet_path ...)
- self._insertIntoPacketTables(packets, cur)
-
- self.dbNoAutoCommit.commit()
- cur.close()
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- self.dbNoAutoCommit.rollback()
- cur.close()
- raise e
- except Exception as e:
- # Something went wrong
- self.logger.error(e, exc_info=1)
- self.dbNoAutoCommit.rollback()
- cur.close()
- return
- self._performPostInsertActions(packets)
-
- def _makeSureTablesExists(self, packets):
- """Make sures all tables needed to insert specified packets exists
-
- Args:
- packets (array): Packets to insert
- """
- timestamp = packets[0].timestamp # All packets is known to be on the same date
-
- packetTableCreator = PacketTableCreator(self.db)
- packetTable = packetTableCreator.getPacketTable(timestamp)
-
- packetPathTableCreator = PacketPathTableCreator(self.db)
- packetPathTable = packetPathTableCreator.getPacketPathTable(timestamp)
-
- packetWeatherTableCreator = PacketWeatherTableCreator(self.db)
- packetWeatherTable = packetWeatherTableCreator.getPacketWeatherTable(
- timestamp)
-
- packetTelemetryTableCreator = PacketTelemetryTableCreator(self.db)
- packetTelemetryTable = packetTelemetryTableCreator.getPacketTelemetryTable(
- timestamp)
-
- packetOgnTableCreator = PacketOgnTableCreator(self.db)
- packetOgnTable = packetOgnTableCreator.getPacketOgnTable(timestamp)
-
- def _performPostInsertActions(self, packets):
- """Perform post insert updates like updating station latest packet and related
-
- Args:
- packets (array): Packets to insert
- """
- timestamp = packets[0].timestamp
- latestPacketModifier = StationLatestPacketModifier(self.db)
- latestPacketModifier.updateStationLatestPacket(
- self.packetIdList, timestamp)
- latestPacketModifier.updateStationLatestTelemetryPacket(
- self.telemetryPacketIdList, timestamp)
- latestPacketModifier.updateStationLatestWeatherPacket(
- self.weatherPacketIdList, timestamp)
- latestPacketModifier.updateStationLatestOgnPacket(
- self.ognPacketIdList, timestamp)
- latestPacketModifier.updateStationLatestLocationPacket(
- self.positionPacketIdList, timestamp)
- latestPacketModifier.updateStationLatestConfirmedPacket(
- self.confirmedPositionPacketIdList, timestamp)
-
- def _insertIntoPacketTables(self, packets, cur):
- """Insert packets into the correct packet tables
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- self._insertIntoPacketTable(packets, cur)
- self._insertIntoPacketPathTable(packets, cur)
- self._insertIntoPacketWeatherTable(packets, cur)
- self._insertIntoPacketOgnTable(packets, cur)
- self._insertIntoPacketTelemetryTable(packets, cur)
-
- def _insertIntoPacketTable(self, packets, cur):
- """Insert packets into the correct packet table
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- timestamp = packets[0].timestamp
- packetTableCreator = PacketTableCreator(self.db)
- packetTable = packetTableCreator.getPacketTable(timestamp)
-
- datePacketTuples = []
- for packet in packets:
-
- datePacketTuples.append((packet.stationId,
- packet.senderId,
- packet.mapId,
- packet.sourceId,
- packet.packetTypeId,
- packet.latitude,
- packet.longitude,
- packet.posambiguity,
- packet.symbol,
- packet.symbolTable,
- packet.mapSector,
- packet.relatedMapSectors,
- packet.markerId,
- packet.markerCounter,
- packet.speed,
- packet.course,
- packet.altitude,
- packet.rng,
- packet.phg,
- packet.latestPhgTimestamp,
- packet.latestRngTimestamp,
- packet.timestamp,
- packet.packetTailTimestamp,
- packet.isMoving,
- packet.reportedTimestamp,
- packet.positionTimestamp,
- packet.comment,
- packet.rawPath,
- packet.raw))
-
- try:
- # insert into packetYYYYMMDD
- argString = b','.join(cur.mogrify(
- "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in datePacketTuples)
- sql = "insert into " + packetTable + "(station_id, sender_id, map_id, source_id, packet_type_id, latitude, longitude, posambiguity, symbol, symbol_table, map_sector, related_map_sectors, marker_id, marker_counter, speed, course, altitude, rng, phg, latest_phg_timestamp, latest_rng_timestamp, timestamp, packet_tail_timestamp, is_moving, reported_timestamp, position_timestamp, comment, raw_path, raw) values " + argString.decode() + " RETURNING id"
- cur.execute(sql)
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
- self.logger.error(sql)
- return
-
- i = 0
- for record in cur:
- if packets[i]:
- packets[i].id = record["id"]
-
- if packets[i].mapId in [1]:
- self.confirmedPositionPacketIdList.append(record["id"])
- elif packets[i].mapId in [1, 5, 7, 9]:
- self.positionPacketIdList.append(record["id"])
- else:
- # We only need to add the packet to the packetIdList if not in the positionPacketIdList or confirmedPositionPacketIdList array's
- self.packetIdList.append(record["id"])
- i += 1
-
- def _insertIntoPacketPathTable(self, packets, cur):
- """Insert packets into the correct packet path table
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- timestamp = packets[0].timestamp
- packetPathTableCreator = PacketPathTableCreator(self.db)
- packetPathTable = packetPathTableCreator.getPacketPathTable(timestamp)
-
- i = 0
- pathTuples = []
- for packet in packets:
- if (packet.stationIdPath):
- self.pathPacketIdList.append(packet.id)
- number = 0
- for stationId in packet.stationIdPath:
- if (packet.stationLocationPath
- and packet.stationLocationPath[number]):
- latitude = packet.stationLocationPath[number][0]
- longitude = packet.stationLocationPath[number][1]
- distance = packet.getTransmitDistance()
-
- pathTuples.append(
- (packet.id, stationId, latitude, longitude, packet.timestamp, distance, number, packet.stationId, packet.latitude, packet.longitude))
- number += 1
- i += 1
-
- # insert into packetYYYYMMDD_path
- if pathTuples:
- try:
- argString = b','.join(cur.mogrify(
- "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in pathTuples)
- cur.execute("insert into " + packetPathTable +
- "(packet_id, station_id, latitude, longitude, timestamp, distance, number, sending_station_id, sending_latitude, sending_longitude) values " + argString.decode())
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
- self.logger.error(argString)
-
- def _insertIntoPacketWeatherTable(self, packets, cur):
- """Insert packets into the correct packet weather table
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- timestamp = packets[0].timestamp
- packetWeatherTableCreator = PacketWeatherTableCreator(self.db)
- packetWeatherTable = packetWeatherTableCreator.getPacketWeatherTable(
- timestamp)
-
- i = 0
- weatherTuples = []
- for packet in packets:
- if (packet.weather):
- self.weatherPacketIdList.append(packet.id)
- weatherTuples.append((packet.id,
- packet.stationId,
- packet.timestamp,
- packet.weather.humidity,
- packet.weather.pressure,
- packet.weather.rain1h,
- packet.weather.rain24h,
- packet.weather.rainSinceMidnight,
- packet.weather.temperature,
- packet.weather.windDirection,
- packet.weather.windGust,
- packet.weather.windSpeed,
- packet.weather.luminosity,
- packet.weather.snow,
- packet.weather.wxRawTimestamp))
- i += 1
-
- # insert into packetYYYYMMDD_weather
- if weatherTuples:
- try:
- argString = b','.join(cur.mogrify(
- "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in weatherTuples)
- cur.execute("insert into " + packetWeatherTable +
- "(packet_id, station_id, timestamp, humidity, pressure, rain_1h, rain_24h, rain_since_midnight, temperature, wind_direction, wind_gust, wind_speed, luminosity, snow, wx_raw_timestamp) values " + argString.decode())
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
- self.logger.error(argString)
-
- def _insertIntoPacketOgnTable(self, packets, cur):
- """Insert packets into the correct packet OGN table
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- timestamp = packets[0].timestamp
- packetOgnTableCreator = PacketOgnTableCreator(self.db)
- packetOgnTable = packetOgnTableCreator.getPacketOgnTable(timestamp)
-
- i = 0
- ognTuples = []
- for packet in packets:
- if (packet.ogn):
- self.ognPacketIdList.append(packet.id)
- ognTuples.append((packet.id,
- packet.stationId,
- packet.timestamp,
- packet.ogn.ognSenderAddress,
- packet.ogn.ognAddressTypeId,
- packet.ogn.ognAircraftTypeId,
- packet.ogn.ognClimbRate,
- packet.ogn.ognTurnRate,
- packet.ogn.ognSignalToNoiseRatio,
- packet.ogn.ognBitErrorsCorrected,
- packet.ogn.ognFrequencyOffset))
-
- i += 1
- # insert into packetYYYYMMDD_ogn
- if ognTuples:
- try:
- argString = b','.join(cur.mogrify(
- "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in ognTuples)
- cur.execute("insert into " + packetOgnTable + "(packet_id, station_id, timestamp, ogn_sender_address, ogn_address_type_id, ogn_aircraft_type_id, ogn_climb_rate, ogn_turn_rate, ogn_signal_to_noise_ratio, ogn_bit_errors_corrected, ogn_frequency_offset) values " + argString.decode())
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
- self.logger.error(argString)
-
- def _insertIntoPacketTelemetryTable(self, packets, cur):
- """Insert packets into the correct packet telemetry table
-
- Args:
- packets (array): Packets to insert
- cur (cursor): Database curser to use
- """
- timestamp = packets[0].timestamp
- packetTelemetryTableCreator = PacketTelemetryTableCreator(self.db)
- packetTelemetryTable = packetTelemetryTableCreator.getPacketTelemetryTable(
- timestamp)
-
- i = 0
- telemetryTuples = []
- for packet in packets:
- if (packet.telemetry):
- self.telemetryPacketIdList.append(packet.id)
- if (not packet.telemetry.isDuplicate()):
- telemetryTuples.append((packet.id,
- packet.stationId,
- packet.timestamp,
- packet.telemetry.val1,
- packet.telemetry.val2,
- packet.telemetry.val3,
- packet.telemetry.val4,
- packet.telemetry.val5,
- packet.telemetry.bits,
- packet.telemetry.seq))
- i += 1
-
- # insert into packetYYYYMMDD_telemetry
- if telemetryTuples:
- try:
- argString = b','.join(cur.mogrify(
- "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", x) for x in telemetryTuples)
- cur.execute("insert into " + packetTelemetryTable +
- "(packet_id, station_id, timestamp, val1, val2, val3, val4, val5, bits, seq) values " + argString.decode() + " returning id")
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
-
- packetTelemetryIds = []
- record = cur.fetchone()
- while record:
- packetTelemetryIds.append(record['id'])
- record = cur.fetchone()
-
- try:
- cur.execute("""update """ + packetTelemetryTable + """ packet_telemetry set
- station_telemetry_param_id = (select id from station_telemetry_param where station_id = packet_telemetry.station_id and valid_to_ts is null),
- station_telemetry_unit_id = (select id from station_telemetry_unit where station_id = packet_telemetry.station_id and valid_to_ts is null),
- station_telemetry_eqns_id = (select id from station_telemetry_eqns where station_id = packet_telemetry.station_id and valid_to_ts is null),
- station_telemetry_bits_id = (select id from station_telemetry_bits where station_id = packet_telemetry.station_id and valid_to_ts is null)
- where id in %s""", (tuple(packetTelemetryIds), ))
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- # Something went wrong, log error so we can fix problem
- self.logger.error(e, exc_info=1)
-
- def _insertTelemetryDefinitions(self, packets):
- """Insert telemetry definitions (PARAM, UNIT, EQNS, BITS) if any exists in current packets
-
- Args:
- packets (array): Packets to insert
- """
- for packet in packets:
- if (packet.stationTelemetryBits):
- packet.stationTelemetryBits.save()
-
- if (packet.stationTelemetryEqns):
- packet.stationTelemetryEqns.save()
-
- if (packet.stationTelemetryParam):
- packet.stationTelemetryParam.save()
-
- if (packet.stationTelemetryUnit):
- packet.stationTelemetryUnit.save()
diff --git a/server/trackdirect/collector/PacketMapIdModifier.py b/server/trackdirect/collector/PacketMapIdModifier.py
deleted file mode 100644
index 2893c45f605dda00b101287368c3ab80859a2df4..0000000000000000000000000000000000000000
--- a/server/trackdirect/collector/PacketMapIdModifier.py
+++ /dev/null
@@ -1,164 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketMapIdModifier():
- """PacketMapIdModifier is used to modify mapId on existing packets in database based on new packets
- """
-
- def __init__(self, cur, packetTableCreator):
- """The __init__ method.
-
- Args:
- cur (psycopg2.Cursor): Database cursor
- packetTableCreator (PacketTableCreator): PacketTableCreator instance
- """
- self.cur = cur
- self.packetTableCreator = packetTableCreator
-
- def execute(self, packets):
- """Perform mapId mofifications based on information in specified packets
-
- Args:
- packets (array): Packets that may affect exisintg packets mapId
- cur (cursor): Database curser to use
- """
- self._markPreviousPacketsAsReplaced(packets)
- self._markPreviousPacketsAsAbnormal(packets)
- self._markPreviousPacketsAsConfirmed(packets)
-
- def _markPreviousPacketsAsReplaced(self, packets):
- """Find packets that has been replaced by packets in this batch and mark them as replaced (mapId 2, 12 or 13)
-
- Args:
- packets (array): Packets that may affect exisintg packets mapId
- """
- packetsToUpdateToMapId2 = {}
- packetsToUpdateToMapId12 = {}
- packetsToUpdateToMapId13 = {}
- for packet in packets:
- if (packet.replacePacketId is not None):
- try:
- self.packetTableCreator.enableCreateIfMissing()
- newPacketTable = self.packetTableCreator.getPacketTable(
- packet.timestamp)
- self.packetTableCreator.disableCreateIfMissing()
- oldPacketTable = self.packetTableCreator.getPacketTable(
- packet.replacePacketTimestamp)
-
- if (packet.mapId == 5):
- if (oldPacketTable not in packetsToUpdateToMapId13):
- packetsToUpdateToMapId13[oldPacketTable] = []
-
- packetsToUpdateToMapId13[oldPacketTable].append(
- packet.replacePacketId)
-
- elif (newPacketTable == oldPacketTable):
- if (oldPacketTable not in packetsToUpdateToMapId2):
- packetsToUpdateToMapId2[oldPacketTable] = []
-
- packetsToUpdateToMapId2[oldPacketTable].append(
- packet.replacePacketId)
-
- else:
- if (oldPacketTable not in packetsToUpdateToMapId12):
- packetsToUpdateToMapId12[oldPacketTable] = []
-
- packetsToUpdateToMapId12[oldPacketTable].append(
- packet.replacePacketId)
- except TrackDirectMissingTableError as e:
- pass
-
- if (packetsToUpdateToMapId2):
- for packetTable in packetsToUpdateToMapId2:
- # Set map_id = 2
- self._updatePacketMapId(
- packetTable, packetsToUpdateToMapId2[packetTable], 2)
-
- if (packetsToUpdateToMapId12):
- for packetTable in packetsToUpdateToMapId12:
- # Set map_id = 12
- self._updatePacketMapId(
- packetTable, packetsToUpdateToMapId12[packetTable], 12)
-
- if (packetsToUpdateToMapId13):
- for packetTable in packetsToUpdateToMapId13:
- # Set map_id = 13
- self._updatePacketMapId(
- packetTable, packetsToUpdateToMapId13[packetTable], 13)
-
- def _markPreviousPacketsAsAbnormal(self, packets):
- """Find packets that has been confirmed to by abnormal becuse of packets in this batch and mark them as abnormal (mapId 9)
-
- Args:
- packets (array): Packets that may affect exisintg packets mapId
- """
- packetsToUpdate = {}
- for packet in packets:
- if (packet.abnormalPacketId is not None):
- try:
- self.packetTableCreator.disableCreateIfMissing()
- packetTable = self.packetTableCreator.getPacketTable(
- packet.abnormalPacketTimestamp)
-
- if (packetTable not in packetsToUpdate):
- packetsToUpdate[packetTable] = []
-
- packetsToUpdate[packetTable].append(
- packet.abnormalPacketId)
- except TrackDirectMissingTableError as e:
- pass
-
- if (packetsToUpdate):
- for packetTable in packetsToUpdate:
- # Set map_id = 9
- self._updatePacketMapId(
- packetTable, packetsToUpdate[packetTable], 9)
-
- def _markPreviousPacketsAsConfirmed(self, packets):
- """Find packets that has been found to be correct becuase of packets in this batch and mark them as confirmed (mapId 1)
-
- Args:
- packets (array): Packets that may affect exisintg packets mapId
- cur (cursor): Database curser to use
- """
- packetsToUpdate = {}
- for packet in packets:
- if (packet.confirmPacketId is not None):
- try:
- self.packetTableCreator.disableCreateIfMissing()
- packetTable = self.packetTableCreator.getPacketTable(
- packet.confirmPacketTimestamp)
-
- if (packetTable not in packetsToUpdate):
- packetsToUpdate[packetTable] = []
-
- packetsToUpdate[packetTable].append(packet.confirmPacketId)
- except TrackDirectMissingTableError as e:
- pass
-
- if (packetsToUpdate):
- for packetTable in packetsToUpdate:
- # Set map_id = 1
- self._updatePacketMapId(
- packetTable, packetsToUpdate[packetTable], 1)
-
- def _updatePacketMapId(self, packetTable, packetIdList, mapId):
- """Update map id on all specified packets
-
- Args:
- cur (cursor): Database cursor to use
- packetTable (str): Packet database table to perform update on
- packetIdList (array): Array of all packet id's to update
- mapId (int): The requested new map id
- """
- if (packetIdList):
- sql = self.cur.mogrify("""update """ + packetTable + """
- set map_id = %s
- where id in %s""", (mapId, tuple(packetIdList),))
- self.cur.execute(sql)
diff --git a/server/trackdirect/collector/StationLatestPacketModifier.py b/server/trackdirect/collector/StationLatestPacketModifier.py
deleted file mode 100644
index ecc06231ec38bd306884c60c93d4e3b6e7298ec5..0000000000000000000000000000000000000000
--- a/server/trackdirect/collector/StationLatestPacketModifier.py
+++ /dev/null
@@ -1,187 +0,0 @@
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-
-
-class StationLatestPacketModifier():
- """The StationLatestPacketModifier class contains functionality to modify the station latest packet
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.packetTableCreator = PacketTableCreator(db)
-
- def updateStationLatestConfirmedPacket(self, packetIdList, timestamp):
- """Updates several stations latest confirmed packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest confirmed packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_sender_id = packet.sender_id,
- latest_confirmed_packet_id = packet.id,
- latest_confirmed_marker_id = packet.marker_id,
- latest_confirmed_packet_timestamp = packet.timestamp,
- latest_confirmed_symbol = packet.symbol,
- latest_confirmed_symbol_table = packet.symbol_table,
- latest_confirmed_latitude = packet.latitude,
- latest_confirmed_longitude = packet.longitude,
- latest_location_packet_id = packet.id,
- latest_location_packet_timestamp = packet.timestamp,
- latest_packet_id = packet.id,
- latest_packet_timestamp = packet.timestamp
- from """ + packetTable + """ packet
- where packet.station_id = station.id
- and packet.id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
-
- cur.close()
- return rowCount
- return 0
-
- def updateStationLatestLocationPacket(self, packetIdList, timestamp):
- """Updates several stations latest location packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest location packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_location_packet_id = packet.id,
- latest_location_packet_timestamp = packet.timestamp,
- latest_packet_id = packet.id,
- latest_packet_timestamp = packet.timestamp
- from """ + packetTable + """ packet
- where packet.station_id = station.id
- and packet.id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
-
- cur.close()
- return rowCount
- return 0
-
- def updateStationLatestPacket(self, packetIdList, timestamp):
- """Updates several stations latest packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_packet_id = packet.id,
- latest_packet_timestamp = packet.timestamp
- from """ + packetTable + """ packet
- where packet.station_id = station.id
- and packet.id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
-
- cur.close()
- return rowCount
- return 0
-
-
- def updateStationLatestTelemetryPacket(self, packetIdList, timestamp):
- """Updates several stations latest telemetry packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_telemetry_packet_id = packet.id,
- latest_telemetry_packet_timestamp = packet.timestamp
- from """ + packetTable + """ packet
- where packet.station_id = station.id
- and packet.id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
-
- cur.close()
- return rowCount
- return 0
-
- def updateStationLatestOgnPacket(self, packetIdList, timestamp):
- """Updates several stations latest OGN packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_ogn_packet_id = packet_ogn.packet_id,
- latest_ogn_packet_timestamp = packet_ogn.timestamp,
- latest_ogn_sender_address = packet_ogn.ogn_sender_address,
- latest_ogn_aircraft_type_id = packet_ogn.ogn_aircraft_type_id,
- latest_ogn_address_type_id = packet_ogn.ogn_address_type_id
- from """ + packetTable + """_ogn packet_ogn
- where packet_ogn.station_id = station.id
- and packet_ogn.packet_id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
- cur.close()
- return rowCount
- return 0
-
- def updateStationLatestWeatherPacket(self, packetIdList, timestamp):
- """Updates several stations latest weather packet based on the specified list of packet id's
-
- Args:
- packetIdList (array): Array of packet id's that should be used to set the latest packets on related stations
- timestamp (int): Unix timestamp which is in the same date as the receive date of all packets (UTC)
-
- Returns:
- number of updated stations
- """
- if (packetIdList):
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- cur = self.db.cursor()
- sql = cur.mogrify("""
- update station set latest_weather_packet_id = packet.id,
- latest_weather_packet_timestamp = packet.timestamp,
- latest_weather_packet_comment = packet.comment
- from """ + packetTable + """ packet
- where packet.station_id = station.id
- and packet.id in %s""", (tuple(packetIdList),))
- cur.execute(sql)
- rowCount = cur.rowcount
-
- cur.close()
- return rowCount
- return 0
\ No newline at end of file
diff --git a/server/trackdirect/collector/__init__.py b/server/trackdirect/collector/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/collector/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/common/Model.py b/server/trackdirect/common/Model.py
deleted file mode 100644
index 5661308d479137c40ee20ded7a55c0dd9605c936..0000000000000000000000000000000000000000
--- a/server/trackdirect/common/Model.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import abc
-
-
-class Model():
- """The Model class is the parent of all my models
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- id (int): Database row id
- """
- self.id = None
- self.db = db
-
- def isExistingObject(self):
- """Returns true if the object exists in database
-
- Returns:
- true if the object exists in database otherwise false
- """
- if ((type(self.id) == int) and self.id is not None and self.id > 0):
- return True
- else:
- return False
-
- @abc.abstractmethod
- def insert(self):
- """Insert this object into database
-
- Returns:
- true on success otherwise false
- """
- return False
-
- @abc.abstractmethod
- def update(self):
- """Update columns in database based on this object
-
- Returns:
- true on success otherwise false
- """
- return False
-
- @abc.abstractmethod
- def validate(self):
- """Return true if object attribute values are valid
-
- Returns:
- true if object attribute values are valid otherwise false
- """
- return
-
- def save(self):
- """Save object data to database if attribute data is valid
-
- Returns:
- true on success otherwise false
- """
- if (self.validate()):
- if (self.isExistingObject()):
- return self.update()
- else:
- return self.insert()
- return False
diff --git a/server/trackdirect/common/Repository.py b/server/trackdirect/common/Repository.py
deleted file mode 100644
index 7888c399483d89dbb66504631dada22bdef12c2e..0000000000000000000000000000000000000000
--- a/server/trackdirect/common/Repository.py
+++ /dev/null
@@ -1,27 +0,0 @@
-
-import abc
-
-
-class Repository():
- """The Repository class is the parent of all my repository classes
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (object): Database connection (with autocommit)
- """
- self.db = db
-
- @abc.abstractmethod
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- object
- """
- return
diff --git a/server/trackdirect/common/Singleton.py b/server/trackdirect/common/Singleton.py
deleted file mode 100644
index b767e94323824d87992769e9399afb315861e3e4..0000000000000000000000000000000000000000
--- a/server/trackdirect/common/Singleton.py
+++ /dev/null
@@ -1,7 +0,0 @@
-class Singleton(object):
- _instance = None
-
- def __new__(class_, *args, **kwargs):
- if not isinstance(class_._instance, class_):
- class_._instance = object.__new__(class_, *args, **kwargs)
- return class_._instance
diff --git a/server/trackdirect/common/__init__.py b/server/trackdirect/common/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/common/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/database/DatabaseConnection.py b/server/trackdirect/database/DatabaseConnection.py
deleted file mode 100644
index 42c2ec95b760b626454fc520d58951f53790328b..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/DatabaseConnection.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import psycopg2
-import psycopg2.extras
-
-import trackdirect
-
-
-class DatabaseConnection():
- """The DatabaseConnection class handles the most basic communication with the database
- """
-
- db = None
- dbNoAutoCommit = None
-
- def __init__(self):
- """The __init__ method.
- """
- config = trackdirect.TrackDirectConfig()
- self.host = config.dbHostname
- self.database = config.dbName
- self.username = config.dbUsername
- self.password = config.dbPassword
- self.port = config.dbPort
-
- def getConnection(self, autocommit=True, createNewConnection=False):
- """Returns a connection to the database
-
- Args:
- autocommit (boolean): set to true if you want the connection to autocommit otherwise false
- createNewConnection (boolean): set to true to force a new connection
- Returns:
- psycopg2.Connection
- """
- if (createNewConnection):
- db = self._createNewConnection()
- if (autocommit):
- # Active autocommit to avoid open transactions laying around
- DatabaseConnection.db.autocommit = True
- return db
-
- elif (autocommit):
- if (DatabaseConnection.db is None):
- DatabaseConnection.db = self._createNewConnection()
- # Active autocommit to avoid open transactions laying around
- DatabaseConnection.db.autocommit = True
- return DatabaseConnection.db
-
- else:
- if (DatabaseConnection.dbNoAutoCommit is None):
- DatabaseConnection.dbNoAutoCommit = self._createNewConnection()
- return DatabaseConnection.dbNoAutoCommit
-
- def _createNewConnection(self):
- """Returns a connection to the database
-
- Returns:
- psycopg2.Connection
- """
- return psycopg2.connect(host=self.host,
- database=self.database,
- user=self.username,
- password=self.password,
- port=self.port,
- sslmode='disable',
- cursor_factory=psycopg2.extras.DictCursor)
diff --git a/server/trackdirect/database/DatabaseObjectFinder.py b/server/trackdirect/database/DatabaseObjectFinder.py
deleted file mode 100644
index 680f99254d15d452bb4d6238336033d1fdb468b6..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/DatabaseObjectFinder.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import logging
-from twisted.python import log
-import datetime
-import time
-
-
-class DatabaseObjectFinder():
- """The DatabaseObjectFinder class can be used to check if a database table exists or not
- """
-
- existingTables = {}
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def setTableExists(self, tablename):
- """Mark a table as existing
-
- Args:
- tablename (str): table to be marked as existing
- """
- DatabaseObjectFinder.existingTables[tablename] = True
-
- def checkTableExists(self, tablename):
- """Returns true if specified table exists in database
-
- Args:
- tablename (str): Table that we want's to know if it exists or not
-
- Returns:
- Returns true if specified table exists in database otherwise false
- """
- todayDateStr = datetime.datetime.utcfromtimestamp(
- int(time.time())).strftime('%Y%m%d')
- yesterdayDateStr = datetime.datetime.utcfromtimestamp(
- int(time.time()) - 86400).strftime('%Y%m%d')
-
- if (todayDateStr in tablename or yesterdayDateStr in tablename):
- # We only trust cache for the latest two days
- if (tablename in DatabaseObjectFinder.existingTables):
- # we know table exists
- return True
-
- cur = self.db.cursor()
- cur.execute("""
- SELECT COUNT(*)
- FROM information_schema.tables
- WHERE table_name = '{0}'
- """.format(tablename.replace('\'', '\'\'')))
- if cur.fetchone()[0] == 1:
- DatabaseObjectFinder.existingTables[tablename] = True
- cur.close()
- return True
- else:
- cur.close()
- return False
-
- def checkIndexExists(self, index):
- """Returns true if specified index exists in database
-
- Args:
- index (str): index that we want's to know if it exists or not
-
- Returns:
- Returns true if specified index exists in database otherwise false
- """
- cur = self.db.cursor()
- cur.execute("""select to_regclass('{0}') \"name\"""".format(
- index.replace('\'', '\'\'')))
- record = cur.fetchone()
- if record and record['name'] == index.replace('\'', '\'\''):
- cur.close()
- return True
- else:
- cur.close()
- return False
diff --git a/server/trackdirect/database/PacketOgnTableCreator.py b/server/trackdirect/database/PacketOgnTableCreator.py
deleted file mode 100644
index 46364051025bb18f255ab423b41ad8205d735a15..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/PacketOgnTableCreator.py
+++ /dev/null
@@ -1,108 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-import datetime
-import time
-import calendar
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketOgnTableCreator():
- """The PacketOgnTableCreator class handles packet OGN table name logic
-
- Note:
- Packets are stored in different tables depending on what day they are received,
- new packet tables are created by this class.
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.logger = logging.getLogger('trackdirect')
- self.createIfMissing = True
-
- def disableCreateIfMissing(self):
- """Disable feature that creates new tables if missing
- """
- self.createIfMissing = False
-
- def getPacketOgnTable(self, packetTimestamp):
- """Returns the name of the OGN packet table
-
- Args:
- packetTimestamp (int): Unix timestamp that we need the table for
-
- Returns:
- the name of the OGN packet table as a string
- """
- date = datetime.datetime.utcfromtimestamp(
- packetTimestamp).strftime('%Y%m%d')
- packetOgnTable = 'packet' + date + '_ogn'
- if (not self.dbObjectFinder.checkTableExists(packetOgnTable)):
- if(self.createIfMissing):
- minTimestamp = packetTimestamp // (24*60*60) * (24*60*60)
- maxTimestamp = minTimestamp + (24*60*60)
- self._createPacketOgnTable(
- packetOgnTable, minTimestamp, maxTimestamp)
- self.dbObjectFinder.setTableExists(packetOgnTable)
- else:
- raise TrackDirectMissingTableError(
- 'Database table does not exists')
- return packetOgnTable
-
- def _createPacketOgnTable(self, tablename, minTimestamp, maxTimestamp):
- """Create a packet OGN table with the specified name
-
- Args:
- tablename (str): Name of the packet OGN table to create
- packetTablename (str): Name of the related packet table
- minTimestamp (int): Min Unix timestamp for this table
- maxTimestamp (int): Max Unix timestamp for this table
- """
- try:
- # Note that we have no reference constraint to the packet table (we will keep rows in this table longer than rows in packet table)
- cur = self.db.cursor()
- sql = """
- create table %s () inherits (packet_ogn)""" % (tablename)
- cur.execute(sql)
-
- sql = """alter table %s add constraint timestamp_range_check check(timestamp >= %d and timestamp < %d)""" % (tablename, minTimestamp, maxTimestamp)
- cur.execute(sql)
-
- sql = """create index %s_pkey on %s using btree (id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_packet_id_idx on %s(packet_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_station_id_idx on %s(station_id, timestamp)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- cur.close()
-
- except (psycopg2.IntegrityError, psycopg2.ProgrammingError) as e:
- # Probably the other collector created the table at the same time (might happen when you run multiple collectors), just go on...
- if ('already exists' not in str(e)):
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
diff --git a/server/trackdirect/database/PacketPathTableCreator.py b/server/trackdirect/database/PacketPathTableCreator.py
deleted file mode 100644
index 8eda761db01a205fc9df18dc1a4aeee3683eb19a..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/PacketPathTableCreator.py
+++ /dev/null
@@ -1,111 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-import datetime
-import time
-import calendar
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketPathTableCreator():
- """The PacketPathTableCreator class handles packet table name logic
-
- Note:
- Packets are stored in different tables depending on what day they are received,
- new packet tables are created by this class.
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.logger = logging.getLogger('trackdirect')
- self.createIfMissing = True
-
- def disableCreateIfMissing(self):
- """Disable feature that creates new tables if missing
- """
- self.createIfMissing = False
-
- def getPacketPathTable(self, packetTimestamp):
- """Returns the name of the path packet table
-
- Args:
- packetTimestamp (int): Unix timestamp that we need the table for
-
- Returns:
- Returns the name of the path packet table as a string
- """
- date = datetime.datetime.utcfromtimestamp(
- packetTimestamp).strftime('%Y%m%d')
- packetTable = 'packet' + date
- packetPathTable = 'packet' + date + '_path'
- if (not self.dbObjectFinder.checkTableExists(packetPathTable)):
- if(self.createIfMissing):
- minTimestamp = packetTimestamp // (24*60*60) * (24*60*60)
- maxTimestamp = minTimestamp + (24*60*60)
- self._createPacketPathTable(
- packetPathTable, minTimestamp, maxTimestamp)
- self.dbObjectFinder.setTableExists(packetPathTable)
- else:
- raise TrackDirectMissingTableError(
- 'Database table does not exists')
- return packetPathTable
-
- def _createPacketPathTable(self, tablename, minTimestamp, maxTimestamp):
- """Create a packet path table with the specified name
-
- Args:
- tablename (str): Name of the packet path table to create
- minTimestamp (int): Min Unix timestamp for this table
- maxTimestamp (int): Max Unix timestamp for this table
- """
- try:
- cur = self.db.cursor()
- sql = """
- create table %s () inherits (packet_path)""" % (tablename)
- cur.execute(sql)
-
- sql = """alter table %s add constraint timestamp_range_check check(timestamp >= %d and timestamp < %d)""" % (tablename, minTimestamp, maxTimestamp)
- cur.execute(sql)
-
- sql = """create index %s_pkey on %s using btree (id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_packet_id_idx on %s(packet_id, number)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_station_id_idx on %s(station_id, timestamp)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_sending_station_id_idx on %s(sending_station_id, timestamp)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- cur.close()
-
- except (psycopg2.IntegrityError, psycopg2.ProgrammingError) as e:
- # Probably the other collector created the table at the same time (might happen when you run multiple collectors), just go on...
- if ('already exists' not in str(e)):
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
diff --git a/server/trackdirect/database/PacketTableCreator.py b/server/trackdirect/database/PacketTableCreator.py
deleted file mode 100644
index 26077c370e092afd981f8b86bf14643b2e114e77..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/PacketTableCreator.py
+++ /dev/null
@@ -1,157 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-import datetime
-import time
-import calendar
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketTableCreator():
- """The PacketTableCreator class handles packet table name logic
-
- Note:
- Packets are stored in different tables depending on what day they are received,
- new packet tables are created by this class.
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.logger = logging.getLogger('trackdirect')
- self.createIfMissing = True
-
- def disableCreateIfMissing(self):
- """Disable feature that creates new tables if missing
- """
- self.createIfMissing = False
-
- def enableCreateIfMissing(self):
- """Enable feature that creates new tables if missing
- """
- self.createIfMissing = True
-
- def getPacketTable(self, packetTimestamp):
- """Returns the name of the packet table
-
- Args:
- packetTimestamp (int): Unix timestamp that we need the table for
-
- Returns:
- Returns the name of the packet table as a string
- """
- date = datetime.datetime.utcfromtimestamp(
- packetTimestamp).strftime('%Y%m%d')
- packetTable = 'packet' + date
- if (not self.dbObjectFinder.checkTableExists(packetTable)):
- if(self.createIfMissing):
- minTimestamp = packetTimestamp // (24*60*60) * (24*60*60)
- maxTimestamp = minTimestamp + (24*60*60)
- self._createPacketTable(
- packetTable, minTimestamp, maxTimestamp)
- self.dbObjectFinder.setTableExists(packetTable)
- else:
- raise TrackDirectMissingTableError(
- 'Database table ' + packetTable + ' does not exists')
- return packetTable
-
- def getPacketTables(self, startTimestamp, endTimestamp=None):
- """Returns an array of packet table names based on the specified timestamp range
-
- Note:
- If table does not exist we will not include the packet table name in array
-
- Args:
- startTimestamp (int): Start unix timestamp for requested packet tables
- endTimestamp (int): End unix timestamp for requested packet tables
-
- Returns:
- Array of packet table names
- """
- if (endTimestamp is None):
- endTimestamp = int(time.time())
-
- # We allways want to include
- endDateTime = datetime.datetime.utcfromtimestamp(int(endTimestamp))
- endDateTime = endDateTime.replace(
- hour=0, minute=0, second=0, microsecond=0) + datetime.timedelta(days=1)
- endTimestamp = calendar.timegm(endDateTime.timetuple())
-
- result = []
- if (startTimestamp == 0):
- # Go back 1 year
- ts = int(time.time()) - (60*60*24*366)
- else:
- ts = startTimestamp
- while (ts < endTimestamp):
- date = datetime.datetime.utcfromtimestamp(
- int(ts)).strftime('%Y%m%d')
- datePacketTable = 'packet' + date
- if (self.dbObjectFinder.checkTableExists(datePacketTable)):
- result.append(datePacketTable)
-
- ts = ts + 86400 # 1 day in seconds
- return result
-
- def _createPacketTable(self, tablename, minTimestamp, maxTimestamp):
- """Create a packet table with the specified name
-
- Args:
- tablename (str): Name of the packet table to create
- minTimestamp (int): Min Unix timestamp for this table
- maxTimestamp (int): Max Unix timestamp for this table
- """
- try:
- cur = self.db.cursor()
- sql = """
- create table %s () inherits (packet)""" % (tablename)
- cur.execute(sql)
-
- sql = """alter table %s add constraint timestamp_range_check check(timestamp >= %d and timestamp < %d)""" % (tablename, minTimestamp, maxTimestamp)
- cur.execute(sql)
-
- # The regular primary key index
- sql = """create index %s_pkey on %s using btree (id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- # This index is magic for multiple methods in PacketRepository
- sql = """create index %s_station_id_idx on %s(station_id, map_id, marker_id, timestamp)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- # This should be good when using the time-travel functionality
- sql = """create index %s_map_sector_idx on %s(map_sector, timestamp, map_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- # Used by remover
- sql = """create index %s_sender_id_idx on %s(sender_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- cur.close()
-
- except (psycopg2.IntegrityError, psycopg2.ProgrammingError) as e:
- # Probably the other collector created the table at the same time (might happen when you run multiple collectors), just go on...
- if ('already exists' not in str(e)):
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
diff --git a/server/trackdirect/database/PacketTelemetryTableCreator.py b/server/trackdirect/database/PacketTelemetryTableCreator.py
deleted file mode 100644
index 54967a016e4859b5f93116eb3e7b8d1233ff9be8..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/PacketTelemetryTableCreator.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-import datetime
-import time
-import calendar
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketTelemetryTableCreator():
- """The PacketTelemetryTableCreator class handles packet telemetry table name logic
-
- Note:
- Packets are stored in different tables depending on what day they are received,
- new packet tables are created by this class.
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.logger = logging.getLogger('trackdirect')
- self.createIfMissing = True
-
- def disableCreateIfMissing(self):
- """Disable feature that creates new tables if missing
- """
- self.createIfMissing = False
-
- def getPacketTelemetryTable(self, packetTimestamp):
- """Returns the name of the telemetry packet table
-
- Args:
- packetTimestamp (int): Unix timestamp that we need the table for
-
- Returns:
- Returns the name of the telemetry packet table as a string
- """
- date = datetime.datetime.utcfromtimestamp(
- packetTimestamp).strftime('%Y%m%d')
- packetTelemetryTable = 'packet' + date + '_telemetry'
- if (not self.dbObjectFinder.checkTableExists(packetTelemetryTable)):
- if(self.createIfMissing):
- minTimestamp = packetTimestamp // (24*60*60) * (24*60*60)
- maxTimestamp = minTimestamp + (24*60*60)
- self._createPacketTelemetryTable(
- packetTelemetryTable, minTimestamp, maxTimestamp)
- self.dbObjectFinder.setTableExists(packetTelemetryTable)
- else:
- raise TrackDirectMissingTableError(
- 'Database table does not exists')
- return packetTelemetryTable
-
- def _createPacketTelemetryTable(self, tablename, minTimestamp, maxTimestamp):
- """Create a packet telemetry table with the specified name
-
- Args:
- tablename (str): Name of the packet telemetry table to create
- packetTablename (str): Name of the related packet table
- minTimestamp (int): Min Unix timestamp for this table
- maxTimestamp (int): Max Unix timestamp for this table
- """
- try:
- # Note that we have no reference constraint to the packet table (we might keep rows in this table longer than rows in packet table)
- cur = self.db.cursor()
- sql = """
- create table %s () inherits (packet_telemetry)""" % (tablename)
- cur.execute(sql)
-
- sql = """alter table %s add constraint timestamp_range_check check(timestamp >= %d and timestamp < %d)""" % (tablename, minTimestamp, maxTimestamp)
- cur.execute(sql)
-
- sql = """create index %s_pkey on %s using btree (id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_packet_id_idx on %s(packet_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_station_id_idx on %s(station_id, timestamp, seq)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_telemetry_param_id on %s(station_telemetry_param_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_telemetry_unit_id on %s(station_telemetry_unit_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_telemetry_eqns_id on %s(station_telemetry_eqns_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_telemetry_bits_id on %s(station_telemetry_bits_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- cur.close()
-
- except (psycopg2.IntegrityError, psycopg2.ProgrammingError) as e:
- # Probably the other collector created the table at the same time (might happen when you run multiple collectors), just go on...
- if ('already exists' not in str(e)):
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
diff --git a/server/trackdirect/database/PacketWeatherTableCreator.py b/server/trackdirect/database/PacketWeatherTableCreator.py
deleted file mode 100644
index f2ced64e7c5ac3d5993831d73718c205cbff0f76..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/PacketWeatherTableCreator.py
+++ /dev/null
@@ -1,107 +0,0 @@
-import logging
-from twisted.python import log
-import psycopg2
-import psycopg2.extras
-import datetime
-import time
-import calendar
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketWeatherTableCreator():
- """The PacketWeatherTableCreator class handles packet weather table name logic
-
- Note:
- Packets are stored in different tables depending on what day they are received,
- new packet tables are created by this class.
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.logger = logging.getLogger('trackdirect')
- self.createIfMissing = True
-
- def disableCreateIfMissing(self):
- """Disable feature that creates new tables if missing
- """
- self.createIfMissing = False
-
- def getPacketWeatherTable(self, packetTimestamp):
- """Returns the name of the weather packet table
-
- Args:
- packetTimestamp (int): Unix timestamp that we need the table for
-
- Returns:
- the name of the weather packet table as a string
- """
- date = datetime.datetime.utcfromtimestamp(
- packetTimestamp).strftime('%Y%m%d')
- packetWeatherTable = 'packet' + date + '_weather'
- if (not self.dbObjectFinder.checkTableExists(packetWeatherTable)):
- if(self.createIfMissing):
- minTimestamp = packetTimestamp // (24*60*60) * (24*60*60)
- maxTimestamp = minTimestamp + (24*60*60)
- self._createPacketWeatherTable(
- packetWeatherTable, minTimestamp, maxTimestamp)
- self.dbObjectFinder.setTableExists(packetWeatherTable)
- else:
- raise TrackDirectMissingTableError(
- 'Database table does not exists')
- return packetWeatherTable
-
- def _createPacketWeatherTable(self, tablename, minTimestamp, maxTimestamp):
- """Create a packet weather table with the specified name
-
- Args:
- tablename (str): Name of the packet weather table to create
- minTimestamp (int): Min Unix timestamp for this table
- maxTimestamp (int): Max Unix timestamp for this table
- """
- try:
- # Note that we have no reference constraint to the packet table (we might keep rows in this table longer than rows in packet table)
- cur = self.db.cursor()
- sql = """
- create table %s () inherits (packet_weather)""" % (tablename)
- cur.execute(sql)
-
- sql = """alter table %s add constraint timestamp_range_check check(timestamp >= %d and timestamp < %d)""" % (tablename, minTimestamp, maxTimestamp)
- cur.execute(sql)
-
- sql = """create index %s_pkey on %s using btree (id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_packet_id_idx on %s(packet_id)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- sql = """create index %s_station_id_idx on %s(station_id, timestamp)""" % (
- tablename, tablename)
- cur.execute(sql)
-
- cur.close()
-
- except (psycopg2.IntegrityError, psycopg2.ProgrammingError) as e:
- # Probably the other collector created the table at the same time (might happen when you run multiple collectors), just go on...
- if ('already exists' not in str(e)):
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
-
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- # Do some sleep and let the other process create all related tables (if other table failes we will do it after sleep)
- time.sleep(10)
- return
diff --git a/server/trackdirect/database/__init__.py b/server/trackdirect/database/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/database/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/exceptions/TrackDirectGenericError.py b/server/trackdirect/exceptions/TrackDirectGenericError.py
deleted file mode 100644
index 1ea03e41d393a484fb4657504548703632bb2b62..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/TrackDirectGenericError.py
+++ /dev/null
@@ -1,12 +0,0 @@
-class TrackDirectGenericError(Exception):
- """ Base exception class for the library. Logs information via logging module
- """
-
- def __init__(self, message):
- """The __init__ method.
-
- Args:
- message (str): Exception message
- """
- super(TrackDirectGenericError, self).__init__(message)
- self.message = message
diff --git a/server/trackdirect/exceptions/TrackDirectMissingSenderError.py b/server/trackdirect/exceptions/TrackDirectMissingSenderError.py
deleted file mode 100644
index 1f70550ebe8ec7dfdb303e8701e6360e8143ae6e..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/TrackDirectMissingSenderError.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from trackdirect.exceptions.TrackDirectGenericError import TrackDirectGenericError
-
-
-class TrackDirectMissingSenderError(TrackDirectGenericError):
- """Raised when unexpected format of a supported packet format is encountered
- """
-
- def __init__(self, message, data={}):
- """The __init__ method.
-
- Args:
- message (str): Exception message
- data (dict): Packet data that caused parse error
- """
- super(TrackDirectMissingSenderError, self).__init__(message)
- self.packet = data
diff --git a/server/trackdirect/exceptions/TrackDirectMissingStationError.py b/server/trackdirect/exceptions/TrackDirectMissingStationError.py
deleted file mode 100644
index 425593176149f095f3352da128930027684f3e08..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/TrackDirectMissingStationError.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from trackdirect.exceptions.TrackDirectGenericError import TrackDirectGenericError
-
-
-class TrackDirectMissingStationError(TrackDirectGenericError):
- """Raised when unexpected format of a supported packet format is encountered
- """
-
- def __init__(self, message, data={}):
- """The __init__ method.
-
- Args:
- message (str): Exception message
- data (dict): Packet data that caused parse error
- """
- super(TrackDirectMissingStationError, self).__init__(message)
- self.packet = data
diff --git a/server/trackdirect/exceptions/TrackDirectMissingTableError.py b/server/trackdirect/exceptions/TrackDirectMissingTableError.py
deleted file mode 100644
index 454d90ad36a87a05423ab3e2de036f2cb27ea155..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/TrackDirectMissingTableError.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from trackdirect.exceptions.TrackDirectGenericError import TrackDirectGenericError
-
-
-class TrackDirectMissingTableError(TrackDirectGenericError):
- """Raised when unexpected format of a supported packet format is encountered
- """
-
- def __init__(self, message, data={}):
- """The __init__ method.
-
- Args:
- message (str): Exception message
- data (dict): Packet data that caused parse error
- """
- super(TrackDirectMissingTableError, self).__init__(message)
- self.packet = data
diff --git a/server/trackdirect/exceptions/TrackDirectParseError.py b/server/trackdirect/exceptions/TrackDirectParseError.py
deleted file mode 100644
index 74587d7228952fc4c1f6b4b83801ebded7911580..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/TrackDirectParseError.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from trackdirect.exceptions.TrackDirectGenericError import TrackDirectGenericError
-
-
-class TrackDirectParseError(TrackDirectGenericError):
- """Raised when unexpected format of a supported packet format is encountered
- """
-
- def __init__(self, message, data={}):
- """The __init__ method.
-
- Args:
- message (str): Exception message
- data (dict): Packet data that caused parse error
- """
- super(TrackDirectParseError, self).__init__(message)
- self.packet = data
diff --git a/server/trackdirect/exceptions/__init__.py b/server/trackdirect/exceptions/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/exceptions/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/objects/Marker.py b/server/trackdirect/objects/Marker.py
deleted file mode 100644
index 2db8363e610ef9df0d111c7bbf14652218212913..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/Marker.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class Marker(Model):
- """Marker represents the marker that each visible packet has, two packet with the same marker id will be connected on map
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- cursor = self.db.cursor()
- cursor.execute("""select nextval('marker_seq')""")
- self.id = cursor.fetchone()[0]
- cursor.close()
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/OgnDevice.py b/server/trackdirect/objects/OgnDevice.py
deleted file mode 100644
index 9b813e20c5589fa8f5170d0e2ce1b43fcc73d9ab..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/OgnDevice.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class OgnDevice(Model):
- """OgnDevice represents a pre registered device in the ogn ddb
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
-
- self.deviceType = None
- self.deviceId = None
- self.aircraftModel = None
- self.registration = None
- self.cn = None
- self.tracked = None
- self.identified = None
- self.ddbAircraftType = None # Do not confuse with the aircraft type in aprs message
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def getDict(self):
- """Returns a dict representation of the object
-
- Returns:
- Dict representation of the object
- """
- data = {}
-
- data['device_type'] = self.deviceType
- data['device_id'] = self.deviceId
- data['aircraft_model'] = self.aircraftModel
- data['registration'] = self.registration
- data['cn'] = self.cn
- data['tracked'] = self.tracked
- data['identified'] = self.identified
- data['ddb_aircraft_type'] = self.ddbAircraftType
-
- return data
diff --git a/server/trackdirect/objects/OgnHiddenStation.py b/server/trackdirect/objects/OgnHiddenStation.py
deleted file mode 100644
index aedaf18960d6a4aaff7944d4472a5df2211a0eed..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/OgnHiddenStation.py
+++ /dev/null
@@ -1,65 +0,0 @@
-
-from trackdirect.common.Model import Model
-
-
-class OgnHiddenStation(Model):
- """OgnDevice represents a pre registered device in the ogn ddb
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
-
- self.id = None
- self.hashedName = None
-
- def getStationName(self):
- """Returns the unidentifiable station name used for the current hashed name
-
- Returns:
- string
- """
- if (self.isExistingObject()):
- return 'UNKNOWN' + str(self.id)
- else:
- return None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute(
- """insert into ogn_hidden_station(hashed_name) values(%s) RETURNING id""", (str(
- self.hashedName).strip(),)
- )
- self.id = insertCursor.fetchone()[0]
- insertCursor.close()
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/Packet.py b/server/trackdirect/objects/Packet.py
deleted file mode 100644
index ccacf5b5a97b2c5b2d4b41be52032f006091a05a..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/Packet.py
+++ /dev/null
@@ -1,359 +0,0 @@
-import logging
-import re
-from twisted.python import log
-import json
-import datetime
-import time
-from math import sin, cos, sqrt, atan2, radians, floor, ceil
-
-from trackdirect.common.Model import Model
-from trackdirect.repositories.StationRepository import StationRepository
-from trackdirect.repositories.SenderRepository import SenderRepository
-from trackdirect.objects.Station import Station
-
-from trackdirect.exceptions.TrackDirectMissingSenderError import TrackDirectMissingSenderError
-from trackdirect.exceptions.TrackDirectMissingStationError import TrackDirectMissingStationError
-
-
-class Packet(Model):
- """Packet represents a APRS packet, AIS packet or any other supported packet
-
- Note:
- Packet corresponds to a row in the packetYYYYMMDD table
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.logger = logging.getLogger('trackdirect')
-
- self.id = None
- self.stationId = None
- self.senderId = None
- self.packetTypeId = None
- self.timestamp = None
- self.reportedTimestamp = None
- self.positionTimestamp = None # Inherited from prev packet if position was equal
- self.latitude = None
- self.longitude = None
- self.symbol = None
- self.symbolTable = None
- self.markerId = None
- self.markerCounter = None
- self.markerPrevPacketTimestamp = None
- self.mapId = None
- self.sourceId = None
- self.mapSector = None
- self.relatedMapSectors = []
- self.speed = None
- self.course = None
- self.altitude = None
- self.rng = None
- self.phg = None
- self.latestRngTimestamp = None
- self.latestPhgTimestamp = None
- self.comment = None
- self.rawPath = None
- self.raw = None
-
- # packet tail timestamp indicates how long time ago we had a tail
- self.packetTailTimestamp = None
-
- # If packet reports a new position for a moving symbol is_moving will be 1 otherwise 0
- # Some times is_moving will be 0 for a moving symbol, but as fast we realize it is moving related packets will have is_moving set to 1
- self.isMoving = 1
-
- self.posambiguity = None
-
- # Following attributes will not allways be loaded from database (comes from related tables)
- self.stationIdPath = []
- self.stationNamePath = []
- self.stationLocationPath = []
-
- # Will only be used when packet is not inserted to database yet
- self.replacePacketId = None
- self.replacePacketTimestamp = None
- self.abnormalPacketId = None
- self.abnormalPacketTimestamp = None
- self.confirmPacketId = None
- self.confirmPacketTimestamp = None
-
- # Will only be used when packet is not inserted to database yet
- self.ogn = None
- self.weather = None
- self.telemetry = None
- self.stationTelemetryBits = None
- self.stationTelemetryEqns = None
- self.stationTelemetryParam = None
- self.stationTelemetryUnit = None
- self.senderName = None
- self.stationName = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def getDistance(self, p2Lat, p2Lng):
- """Get distance in meters between current position and specified position
-
- Args:
- p2Lat (float): Position 2 latitude
- p2Lng (float): Position 2 longitude
-
- Returns:
- Distance in meters between the two specified positions (as float)
- """
- if (self.latitude is not None
- and self.longitude is not None):
- p1Lat = self.latitude
- p1Lng = self.longitude
- R = 6378137 # Earths mean radius in meter
- dLat = radians(p2Lat - p1Lat)
- dLong = radians(p2Lng - p1Lng)
- a = sin(dLat / 2) * sin(dLat / 2) + cos(radians(p1Lat)) * \
- cos(radians(p2Lat)) * sin(dLong / 2) * sin(dLong / 2)
- c = 2 * atan2(sqrt(a), sqrt(1 - a))
- d = R * c
- return d # returns the distance in meter
- else:
- return None
-
- def getCalculatedSpeed(self, prevPacket):
- """Get speed compared to previous packet position and timestamp
-
- Args:
- prevPacket (Packet): Previous related packet for the same station
-
- Returns:
- Speed in kmh compared to previous packet position and timestamp (as float)
- """
- if (self.latitude is not None
- and self.longitude is not None):
- distance = self.getDistance(
- prevPacket.latitude, prevPacket.longitude)
- time = abs(prevPacket.timestamp - self.timestamp)
- if (self.reportedTimestamp is not None
- and prevPacket.reportedTimestamp is not None
- and self.reportedTimestamp != 0
- and prevPacket.reportedTimestamp != 0
- and (self.reportedTimestamp % 60 != 0 or prevPacket.reportedTimestamp % 60 != 0)
- and prevPacket.reportedTimestamp != self.reportedTimestamp):
- time = abs(prevPacket.reportedTimestamp -
- self.reportedTimestamp)
-
- if (time == 0):
- return 0
- return distance / time # meters per second
- else:
- return None
-
- def isSymbolEqual(self, comparePacket):
- """Returns true if current symbol is equal to symbol in specified packet
-
- Args:
- comparePacket (Packet): Packet to compare current symbol with
-
- Returns:
- True if current symbol is equal to symbol in specified packet
- """
- if (self.symbol is not None
- and self.symbolTable is not None
- and comparePacket.symbol is not None
- and comparePacket.symbolTable is not None
- and self.symbol == comparePacket.symbol
- and self.symbolTable == comparePacket.symbolTable):
- return True
- else:
- return False
-
- def isPostitionEqual(self, comparePacket):
- """Returns true if current position is equal to position in specified packet
-
- Args:
- comparePacket (Packet): Packet to compare current position with
-
- Returns:
- True if current position is equal to position in specified packet
- """
- if (comparePacket.latitude is not None
- and comparePacket.longitude is not None
- and self.longitude is not None
- and self.latitude is not None
- and round(self.latitude, 5) == round(comparePacket.latitude, 5)
- and round(self.longitude, 5) == round(comparePacket.longitude, 5)):
- return True
- else:
- return False
-
- def getTransmitDistance(self):
- """Calculate the transmit distance
-
- Notes:
- require that stationLocationPath is set
-
- Args:
- None
-
- Returns:
- Distance in meters for this transmission
- """
- if (self.stationLocationPath is None
- or len(self.stationLocationPath) < 1):
- return None
-
- location = self.stationLocationPath[0]
- if (location[0] is None
- or location[1] is None):
- return None
-
- if (self.latitude is not None
- and self.longitude is not None):
-
- # Current packet contains position, use that
- return self.getDistance(location[0], location[1])
- else:
-
- # Current packet is missing position, use latest station position
- stationRepository = StationRepository(self.db)
- station = stationRepository.getObjectById(self.stationId)
- if (not station.isExistingObject()):
- return None
-
- if (station.latestConfirmedLatitude is not None and station.latestConfirmedLongitude is not None):
- curStationLatestLocationPacket = Packet(self.db)
- curStationLatestLocationPacket.latitude = station.latestConfirmedLatitude
- curStationLatestLocationPacket.longitude = station.latestConfirmedLongitude
- return curStationLatestLocationPacket.getDistance(location[0], location[1])
- else:
- return None
-
- def getDict(self, includeStationName=False):
- """Returns a dict representation of the object
-
- Args:
- includeStationName (Boolean): Include station name and sender name in dict
-
- Returns:
- Dict representation of the object
- """
- data = {}
- data['id'] = self.id
-
- if (self.stationId is not None):
- data['station_id'] = int(self.stationId)
- else:
- data['station_id'] = None
-
- if (self.senderId is not None):
- data['sender_id'] = int(self.senderId)
- else:
- data['sender_id'] = None
-
- data['packet_type_id'] = self.packetTypeId
- data['timestamp'] = self.timestamp
- data['reported_timestamp'] = self.reportedTimestamp
- data['position_timestamp'] = self.positionTimestamp
-
- if (self.latitude is not None and self.longitude is not None):
- data['latitude'] = float(self.latitude)
- data['longitude'] = float(self.longitude)
- else:
- data['latitude'] = None
- data['longitude'] = None
-
- data['symbol'] = self.symbol
- data['symbol_table'] = self.symbolTable
- data['marker_id'] = self.markerId
- data['marker_counter'] = self.markerCounter
- data['map_id'] = self.mapId
- data['source_id'] = self.sourceId
- data['map_sector'] = self.mapSector
- data['related_map_sectors'] = self.relatedMapSectors
- data['speed'] = self.speed
- data['course'] = self.course
- data['altitude'] = self.altitude
- data['rng'] = self.rng
- data['phg'] = self.phg
- data['latest_phg_timestamp'] = self.latestPhgTimestamp
- data['latest_rng_timestamp'] = self.latestRngTimestamp
- data['comment'] = self.comment
- data['raw_path'] = self.rawPath
- data['raw'] = self.raw
- data['packet_tail_timestamp'] = self.packetTailTimestamp
- data['is_moving'] = self.isMoving
- data['posambiguity'] = self.posambiguity
- data['db'] = 1
-
- if (includeStationName):
- try:
- stationRepository = StationRepository(self.db)
- station = stationRepository.getCachedObjectById(
- data['station_id'])
- data['station_name'] = station.name
- except TrackDirectMissingStationError as e:
- data['station_name'] = ''
-
- try:
- senderRepository = SenderRepository(self.db)
- sender = senderRepository.getCachedObjectById(
- data['sender_id'])
- data['sender_name'] = sender.name
- except TrackDirectMissingSenderError as e:
- data['sender_name'] = ''
-
- data['station_id_path'] = self.stationIdPath
- data['station_name_path'] = self.stationNamePath
- data['station_location_path'] = self.stationLocationPath
- data['telemetry'] = None
- if (self.telemetry is not None):
- data['telemetry'] = self.telemetry.getDict()
- data['weather'] = None
- if (self.weather is not None):
- data['weather'] = self.weather.getDict()
- data['ogn'] = None
- if (self.ogn is not None):
- data['ogn'] = self.ogn.getDict()
- return data
-
- def getJson(self):
- """Returns a json representation of the object
-
- Returns:
- Json representation of the object (returnes None on failure)
- """
- data = self.getDict()
-
- try:
- return json.dumps(data, ensure_ascii=False).encode('utf8')
- except (ValueError) as exp:
- self.logger.error(e, exc_info=1)
-
- return None
diff --git a/server/trackdirect/objects/PacketOgn.py b/server/trackdirect/objects/PacketOgn.py
deleted file mode 100644
index 74adb4aa932fbe243de8b0276f4ee72182ac6902..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/PacketOgn.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class PacketOgn(Model):
- """PacketOgn represents the OGN data in a APRS packet
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.packetId = None
- self.stationId = None
- self.timestamp = None
- self.ognSenderAddress = None
- self.ognAddressTypeId = None
- self.ognAircraftTypeId = None
- self.ognClimbRate = None
- self.ognTurnRate = None
- self.ognSignalToNoiseRatio = None
- self.ognBitErrorsCorrected = None
- self.ognFrequencyOffset = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (self.stationId <= 0):
- return False
-
- if (self.packetId <= 0):
- return False
-
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def getDict(self):
- """Returns the packet OGN as a dict
-
- Args:
- None
-
- Returns:
- A packet OGN dict
- """
- data = {}
- data['id'] = self.id
- data['packet_id'] = self.packetId
- data['station_id'] = self.stationId
- data['timestamp'] = self.timestamp
- data['ogn_sender_address'] = self.ognSenderAddress
- data['ogn_address_type_id'] = self.ognAddressTypeId
- data['ogn_aircraft_type_id'] = self.ognAircraftTypeId
- data['ogn_climb_rate'] = self.ognClimbRate
- data['ogn_turn_rate'] = self.ognTurnRate
- data['ogn_signal_to_noise_ratio'] = self.ognSignalToNoiseRatio
- data['ogn_bit_errors_corrected'] = self.ognBitErrorsCorrected
- data['ogn_frequency_offset'] = self.ognFrequencyOffset
- return data
diff --git a/server/trackdirect/objects/PacketTelemetry.py b/server/trackdirect/objects/PacketTelemetry.py
deleted file mode 100644
index ad2d20439e39546d7af3d76e19a00022142607cb..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/PacketTelemetry.py
+++ /dev/null
@@ -1,105 +0,0 @@
-from trackdirect.common.Model import Model
-from trackdirect.database.PacketTelemetryTableCreator import PacketTelemetryTableCreator
-
-
-class PacketTelemetry(Model):
- """PacketTelemetry represents the telemetry data in a APRS packet
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.packetId = None
- self.stationId = None
- self.timestamp = None
- self.val1 = None
- self.val2 = None
- self.val3 = None
- self.val4 = None
- self.val5 = None
- self.bits = None
- self.seq = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (self.stationId <= 0):
- return False
-
- if (self.packetId <= 0):
- return False
-
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def isDuplicate(self):
- """Method returnes true if a duplicate exists in database
-
- Returns:
- True if a duplicate exists in database otherwise False
- """
- packetTelemetryTableCreator = PacketTelemetryTableCreator(self.db)
- packetTelemetryTableCreator.disableCreateIfMissing()
- packetTelemetryTable = packetTelemetryTableCreator.getPacketTelemetryTable(
- self.timestamp)
- if (packetTelemetryTable is not None):
-
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from """ + packetTelemetryTable +
- """ where station_id = %s order by timestamp desc limit 1""", (self.stationId,))
-
- record = selectCursor.fetchone()
- selectCursor.close()
- if record is not None and record['seq'] == self.seq:
- return True
- return False
-
- def getDict(self):
- """Returns a packet telemetry dict
-
- Args:
- None
-
- Returns:
- A packet telemetry dict
- """
- data = {}
- data['id'] = self.id
- data['packet_id'] = self.packetId
- data['station_id'] = self.stationId
- data['timestamp'] = self.timestamp
- data['val1'] = self.val1
- data['val2'] = self.val2
- data['val3'] = self.val3
- data['val4'] = self.val4
- data['val5'] = self.val5
- data['bits'] = self.bits
- data['seq'] = self.seq
- return data
diff --git a/server/trackdirect/objects/PacketWeather.py b/server/trackdirect/objects/PacketWeather.py
deleted file mode 100644
index aaef5eb5f0a1ec9287de96719f796ae297db3ad5..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/PacketWeather.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class PacketWeather(Model):
- """PacketWeather represents the weather data in a APRS packet
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.packetId = None
- self.stationId = None
- self.timestamp = None
- self.humidity = None
- self.pressure = None
- self.rain1h = None
- self.rain24h = None
- self.rainSinceMidnight = None
- self.temperature = None
- self.windDirection = None
- self.windGust = None
- self.windSpeed = None
- self.luminosity = None
- self.snow = None
- self.wxRawTimestamp = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (self.stationId <= 0):
- return False
-
- if (self.packetId <= 0):
- return False
-
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
-
- def getDict(self):
- """Returns the packet weather as a dict
-
- Args:
- None
-
- Returns:
- A packet weather dict
- """
- data = {}
- data['id'] = self.id
- data['packet_id'] = self.packetId
- data['station_id'] = self.stationId
- data['timestamp'] = self.timestamp
- data['humidity'] = self.humidity
- data['pressure'] = self.pressure
- data['rain_1h'] = self.rain1h
- data['rain_24h'] = self.rain24h
- data['rain_since_midnight'] = self.rainSinceMidnight
- data['temperature'] = self.temperature
- data['wind_direction'] = self.windDirection
- data['wind_gust'] = self.windGust
- data['wind_speed'] = self.windSpeed
- data['luminosity'] = self.luminosity
- data['snow'] = self.snow
- data['wx_raw_timestamp'] = self.wxRawTimestamp
- return data
diff --git a/server/trackdirect/objects/Sender.py b/server/trackdirect/objects/Sender.py
deleted file mode 100644
index 6c926be3a9ced33efa19455778b511bf03eb7add..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/Sender.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class Sender(Model):
- """Sender represents the sender of a packet (often same name as station name)
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
-
- self.id = None
- self.name = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (self.name == ''):
- return False
-
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute(
- """insert into sender(name) values(%s) RETURNING id""", (self.name.strip(
- ),)
- )
- self.id = insertCursor.fetchone()[0]
- insertCursor.close()
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Since packet will be updated in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/Station.py b/server/trackdirect/objects/Station.py
deleted file mode 100644
index da4e9d8426e544e4d5461163958a9c97727d1b97..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/Station.py
+++ /dev/null
@@ -1,149 +0,0 @@
-import logging
-from trackdirect.common.Model import Model
-
-
-class Station(Model):
- """Station represents the object/station that the packet is about
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.logger = logging.getLogger('trackdirect')
-
- self.id = None
- self.name = None
- self.latestSenderId = None
- self.stationTypeId = 1 # default to 1
- self.sourceId = None
-
- self.latestPacketId = None
- self.latestPacketTimestamp = None
-
- self.latestLocationPacketId = None
- self.latestLocationPacketTimestamp = None
-
- self.latestWeatherPacketId = None
- self.latestWeatherPacketTimestamp = None
-
- self.latestTelemetryPacketId = None
- self.latestTelemetryPacketTimestamp = None
-
- # Latest packet with a location that is confirmed to be correct
- self.latestConfirmedPacketId = None
- self.latestConfirmedPacketTimestamp = None
- self.latestConfirmedSymbol = None
- self.latestConfirmedSymbolTable = None
- self.latestConfirmedLatitude = None
- self.latestConfirmedLongitude = None
- self.latestConfirmedMarkerId = None
-
- self.latestOgnPacketId = None
- self.latestOgnPacketTimestamp = None
- self.latestOgnSenderAddress = None
- self.latestOgnAircraftTypeId = None
- self.latestOgnAddressTypeId = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (self.name == ''):
- return False
-
- return True
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Since packet will be inserted in batch we never use this method.
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute(
- """insert into station(name, station_type_id, source_id) values(%s, %s, %s) RETURNING id""", (
- self.name.strip(), self.stationTypeId, self.sourceId)
- )
- self.id = insertCursor.fetchone()[0]
- insertCursor.close()
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- if (self.isExistingObject()):
- cursor = self.db.cursor()
- cursor.execute(
- """update station set source_id = %s, name = %s, station_type_id = %s where id = %s and source_id is null""", (
- self.sourceId, self.name, self.stationTypeId, self.id)
- )
- cursor.close()
- return True
- else:
- return False
-
- def getShortDict(self):
- """Returns a dict representation of the object
-
- Returns:
- Dict representation of the object
- """
- data = {}
- data['id'] = self.id
-
- data['name'] = self.name
- data['latest_sender_id'] = self.latestSenderId
- data['station_type_id'] = self.stationTypeId
- data['source_id'] = self.sourceId
-
- if (self.latestConfirmedPacketId is not None):
- data['latest_confirmed_packet_id'] = int(
- self.latestConfirmedPacketId)
- else:
- data['latest_confirmed_packet_id'] = None
-
- data['latest_confirmed_packet_timestamp'] = self.latestConfirmedPacketTimestamp
- data['latest_confirmed_symbol'] = self.latestConfirmedSymbol
- data['latest_confirmed_symbol_table'] = self.latestConfirmedSymbolTable
-
- if (self.latestConfirmedLatitude is not None):
- data['latest_confirmed_latitude'] = float(
- self.latestConfirmedLatitude)
- else:
- data['latest_confirmed_latitude'] = None
-
- if (self.latestConfirmedLongitude is not None):
- data['latest_confirmed_longitude'] = float(
- self.latestConfirmedLongitude)
- else:
- data['latest_confirmed_longitude'] = None
-
- if (self.latestLocationPacketId is not None):
- data['latest_location_packet_id'] = self.latestLocationPacketId
- else:
- data['latest_location_packet_id'] = None
-
- data['latest_location_packet_timestamp'] = self.latestLocationPacketTimestamp
-
- if (self.latestPacketId is not None):
- data['latest_packet_id'] = int(self.latestPacketId)
- else:
- data['latest_packet_id'] = None
-
- data['latest_packet_timestamp'] = self.latestPacketTimestamp
-
- return data
diff --git a/server/trackdirect/objects/StationTelemetryBits.py b/server/trackdirect/objects/StationTelemetryBits.py
deleted file mode 100644
index e8e90b0332e3fe5f28c86db261e2644a571d9c1a..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/StationTelemetryBits.py
+++ /dev/null
@@ -1,100 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class StationTelemetryBits(Model):
- """StationTelemetryBits represents the telemetry bits sent by the related station
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.stationId = None
- self.createdTs = None
- self.latestTs = None
- self.validToTs = None
- self.bits = None
- self.title = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (type(self.stationId) != int or self.stationId <= 0):
- return False
-
- return True
-
- def save(self):
- """Save object data to database if attribute data is valid
-
- Returns:
- Returns true on success otherwise false
- """
- if (self.validate()):
- if (self.isExistingObject()):
- return self.update()
- else:
- cursor = self.db.cursor()
- cursor.execute("""update station_telemetry_bits
- set latest_ts = %s
- where station_id = %s
- and valid_to_ts is null
- and bits = %s
- and title = %s""",
- (self.createdTs,
- self.stationId,
- self.bits,
- self.title))
-
- if (cursor.rowcount == 0):
- return self.insert()
- else:
- # We do not insert it since it was equal to the existsing row
- return True
- return False
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute("""update station_telemetry_bits
- set valid_to_ts = %s
- where station_id = %s
- and valid_to_ts is null""",
- (self.createdTs,
- self.stationId))
-
- insertCursor.execute("""insert into station_telemetry_bits(
- station_id,
- created_ts,
- latest_ts,
- bits,
- title)
- values (%s, %s, %s, %s, %s)""",
- (self.stationId,
- self.createdTs,
- self.createdTs,
- self.bits,
- self.title))
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/StationTelemetryEqns.py b/server/trackdirect/objects/StationTelemetryEqns.py
deleted file mode 100644
index 85b07b8b10c1449cea7e89d830375c69c9decfa9..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/StationTelemetryEqns.py
+++ /dev/null
@@ -1,161 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class StationTelemetryEqns(Model):
- """StationTelemetryEqns represents the telemetry equations sent by the related station
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.stationId = None
- self.createdTs = None
- self.latestTs = None
- self.validToTs = None
- self.a1 = None
- self.b1 = None
- self.c1 = None
- self.a2 = None
- self.b2 = None
- self.c2 = None
- self.a3 = None
- self.b3 = None
- self.c3 = None
- self.a4 = None
- self.b4 = None
- self.c4 = None
- self.a5 = None
- self.b5 = None
- self.c5 = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (type(self.stationId) != int or self.stationId <= 0):
- return False
-
- return True
-
- def save(self):
- """Save object data to database if attribute data is valid
-
- Returns:
- Returns true on success otherwise false
- """
- if (self.validate()):
- if (self.isExistingObject()):
- return self.update()
- else:
- cursor = self.db.cursor()
- cursor.execute("""update station_telemetry_eqns
- set latest_ts = %s
- where station_id = %s
- and valid_to_ts is null
- and a1::numeric = %s
- and b1::numeric = %s
- and c1::numeric = %s
-
- and a2::numeric = %s
- and b2::numeric = %s
- and c2::numeric = %s
-
- and a3::numeric = %s
- and b3::numeric = %s
- and c3::numeric = %s
-
- and a4::numeric = %s
- and b4::numeric = %s
- and c4::numeric = %s
-
- and a5::numeric = %s
- and b5::numeric = %s
- and c5::numeric = %s""",
-
- (self.createdTs,
- self.stationId,
- self.a1,
- self.b1,
- self.c1,
-
- self.a2,
- self.b2,
- self.c2,
-
- self.a3,
- self.b3,
- self.c3,
-
- self.a4,
- self.b4,
- self.c4,
-
- self.a5,
- self.b5,
- self.c5))
-
- if (cursor.rowcount == 0):
- return self.insert()
- else:
- # We do not insert it since it was equal to the existsing row
- return True
- return False
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute("""update station_telemetry_eqns
- set valid_to_ts = %s
- where station_id = %s
- and valid_to_ts is null""", (
- self.createdTs,
- self.stationId))
-
- insertCursor.execute("""insert into station_telemetry_eqns(station_id, created_ts, latest_ts, a1, b1, c1, a2, b2, c2, a3, b3, c3, a4, b4, c4, a5, b5, c5)
- values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
- (self.stationId,
- self.createdTs,
- self.timestamp,
-
- self.a1,
- self.b1,
- self.c1,
-
- self.a2,
- self.b2,
- self.c2,
-
- self.a3,
- self.b3,
- self.c3,
-
- self.a4,
- self.b4,
- self.c4,
-
- self.a5,
- self.b5,
- self.c5))
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/StationTelemetryParam.py b/server/trackdirect/objects/StationTelemetryParam.py
deleted file mode 100644
index 11657f0cc346986de9764949b32b2527b950cc80..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/StationTelemetryParam.py
+++ /dev/null
@@ -1,139 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class StationTelemetryParam(Model):
- """StationTelemetryParam represents the telemetry parameters sent by the related station
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.stationId = None
- self.createdTs = None
- self.latestTs = None
- self.validToTs = None
- self.p1 = None
- self.p2 = None
- self.p3 = None
- self.p4 = None
- self.p5 = None
- self.b1 = None
- self.b2 = None
- self.b3 = None
- self.b4 = None
- self.b5 = None
- self.b6 = None
- self.b7 = None
- self.b8 = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (type(self.stationId) != int or self.stationId <= 0):
- return False
-
- return True
-
- def save(self):
- """Save object data to database if attribute data is valid
-
- Returns:
- Returns true on success otherwise false
- """
- if (self.validate()):
- if (self.isExistingObject()):
- return self.update()
- else:
- cursor = self.db.cursor()
- cursor.execute("""update station_telemetry_param
- set latest_ts = %s
- where station_id = %s
- and valid_to_ts is null
- and p1 = %s
- and p2 = %s
- and p3 = %s
- and p4 = %s
- and p5 = %s
- and b1 = %s
- and b2 = %s
- and b3 = %s
- and b4 = %s
- and b5 = %s
- and b6 = %s
- and b7 = %s
- and b8 = %s""",
- (self.createdTs,
- self.stationId,
- self.p1,
- self.p2,
- self.p3,
- self.p4,
- self.p5,
- self.b1,
- self.b2,
- self.b3,
- self.b4,
- self.b5,
- self.b6,
- self.b7,
- self.b8))
-
- if (cursor.rowcount == 0):
- return self.insert()
- else:
- # We do not insert it since it was equal to the existsing row
- return True
- return False
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute("""update station_telemetry_param
- set valid_to_ts = %s
- where station_id = %s
- and valid_to_ts is null""",
- (self.createdTs,
- self.stationId))
-
- insertCursor.execute("""insert into station_telemetry_param(station_id, created_ts, latest_ts, p1, p2, p3, p4, p5, b1, b2, b3, b4, b5, b6, b7, b8)
- values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
- (self.stationId,
- self.createdTs,
- self.createdTs,
- self.p1,
- self.p2,
- self.p3,
- self.p4,
- self.p5,
- self.b1,
- self.b2,
- self.b3,
- self.b4,
- self.b5,
- self.b6,
- self.b7,
- self.b8))
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/StationTelemetryUnit.py b/server/trackdirect/objects/StationTelemetryUnit.py
deleted file mode 100644
index 1e9b244b0fcb0301663eddfe53c0050c6f09fd90..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/StationTelemetryUnit.py
+++ /dev/null
@@ -1,140 +0,0 @@
-from trackdirect.common.Model import Model
-
-
-class StationTelemetryUnit(Model):
- """StationTelemetryUnit represents the telemetry UNIT sent by the related station
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- Model.__init__(self, db)
- self.id = None
- self.stationId = None
- self.createdTs = None
- self.latestTs = None
- self.validToTs = None
- self.u1 = None
- self.u2 = None
- self.u3 = None
- self.u4 = None
- self.u5 = None
- self.l1 = None
- self.l2 = None
- self.l3 = None
- self.l4 = None
- self.l5 = None
- self.l6 = None
- self.l7 = None
- self.l8 = None
-
- def validate(self):
- """Returns true on success (when object content is valid), otherwise false
-
- Returns:
- True on success otherwise False
- """
- if (type(self.stationId) != int or self.stationId <= 0):
- return False
-
- return True
-
- def save(self):
- """Save object data to database if attribute data is valid
-
- Returns:
- Returns true on success otherwise false
- """
- if (self.validate()):
- if (self.isExistingObject()):
- return self.update()
- else:
- cursor = self.db.cursor()
- cursor.execute("""update station_telemetry_unit
- set latest_ts = %s
- where station_id = %s
- and valid_to_ts is null
- and u1 = %s
- and u2 = %s
- and u3 = %s
- and u4 = %s
- and u5 = %s
- and l1 = %s
- and l2 = %s
- and l3 = %s
- and l4 = %s
- and l5 = %s
- and l6 = %s
- and l7 = %s
- and l8 = %s""",
- (self.createdTs,
- self.stationId,
- self.u1,
- self.u2,
- self.u3,
- self.u4,
- self.u5,
- self.l1,
- self.l2,
- self.l3,
- self.l4,
- self.l5,
- self.l6,
- self.l7,
- self.l8))
-
- if (cursor.rowcount == 0):
- return self.insert()
- else:
- # We do not insert it since it was equal to the existsing row
- return True
- return False
-
- def insert(self):
- """Method to call when we want to save a new object to database
-
- Returns:
- True on success otherwise False
- """
- if (not self.isExistingObject()):
- insertCursor = self.db.cursor()
- insertCursor.execute("""update station_telemetry_unit
- set valid_to_ts = %s
- where station_id = %s
- and valid_to_ts is null""",
- (self.createdTs,
- self.stationId))
-
- insertCursor.execute("""insert into station_telemetry_unit(station_id, created_ts, latest_ts, u1, u2, u3, u4, u5, l1, l2, l3, l4, l5, l6, l7, l8)
- values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
- (self.stationId,
- self.createdTs,
- self.createdTs,
- self.u1,
- self.u2,
- self.u3,
- self.u4,
- self.u5,
- self.l1,
- self.l2,
- self.l3,
- self.l4,
- self.l5,
- self.l6,
- self.l7,
- self.l8))
-
- return True
- else:
- return False
-
- def update(self):
- """Method to call when we want to save changes to database
-
- Returns:
- True on success otherwise False
- """
- return False
diff --git a/server/trackdirect/objects/__init__.py b/server/trackdirect/objects/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/objects/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/parser/AprsISConnection.py b/server/trackdirect/parser/AprsISConnection.py
deleted file mode 100644
index 3cfad1cd076a1e3380b68c839801422390c02e77..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/AprsISConnection.py
+++ /dev/null
@@ -1,140 +0,0 @@
-import logging
-import aprslib
-import collections
-import time
-import re
-
-
-class AprsISConnection(aprslib.IS):
- """Handles communication with the APRS-IS server
- """
-
- def __init__(self, callsign, passwd="-1", host="rotate.aprs.net", port=10152):
- """The __init__ method.
-
- Args:
- callsign (string): APRS-IS callsign
- passwd (string): APRS-IS password
- host (string): APRS-IS Server hostname
- port (int): APRS-IS Server port
- """
- aprslib.IS.__init__(self, callsign, passwd, host, port)
-
- self.logger = logging.getLogger("aprslib.IS")
- self.frequencyLimit = None
- self.stationHashTimestamps = collections.OrderedDict()
- self.sourceId = 1
-
- def setFrequencyLimit(self, frequencyLimit):
- """Set frequency limit
-
- Args:
- frequencyLimit (int): Hard frequency limit (in seconds)
- """
- self.frequencyLimit = frequencyLimit
-
- def getFrequencyLimit(self):
- """Get frequency limit
-
- Return:
- int
- """
- return self.frequencyLimit
-
- def setSourceId(self, sourceId):
- """Set what source packet is from (APRS, CWOP ...)
-
- Args:
- sourceId (int): Id that corresponds to id in source-table
- """
- self.sourceId = sourceId
-
- def filteredConsumer(self, callback, blocking=True, raw=False):
- """The filtered consume method
-
- Args:
- callback (boolean): Method to call with result
- blocking (boolean): Set to true if consume should be blocking
- raw (boolean): Set to true if result should be raw
- """
- def filterCallback(line):
- try:
- # decode first then replace
- line = line.decode()
- line = line.replace('\x00', '')
- except UnicodeError as e:
- # string is not UTF-8
- return
-
- if line.startswith('dup'):
- line = line[4:].strip()
-
- if (self._isSendingToFast(line)):
- return
-
- if raw:
- callback(line)
- else:
- callback(self._parse(line))
-
- self.consumer(filterCallback, blocking, False, True)
-
- def _isSendingToFast(self, line):
- """Simple check that returns True if sending frequency limit is to fast
-
- Args:
- line (string): Packet string
-
- Returns:
- True if sending frequency limit is to fast
- """
- if (self.frequencyLimit is not None):
- try:
- (name, other) = line.split('>', 1)
- except:
- return False
-
- # Divide into body and head
- try:
- (head, body) = other.split(':', 1)
- except:
- return False
-
- if len(body) == 0:
- return False
-
- packetType = body[0]
- body = body[1:]
-
- # Try to find turn rate and reduce frequency limit if high turn rate
- frequencyLimitToApply = int(self.frequencyLimit)
- if (self.sourceId == 5) :
- match = re.search("(\+|\-)(\d\.\d)rot ", line)
- try:
- turnRate = abs(float(match.group(2)))
- if (turnRate > 0) :
- frequencyLimitToApply = int(frequencyLimitToApply / (1+turnRate))
- except:
- pass
-
- latestTimestampOnMap = 0
- if (name + packetType in self.stationHashTimestamps):
- latestTimestampOnMap = self.stationHashTimestamps[name + packetType]
-
- if (((int(time.time()) - 1) - frequencyLimitToApply) < latestTimestampOnMap):
- # This sender is sending faster than config limit
- return True
- self.stationHashTimestamps[name + packetType] = int(time.time()) - 1
- self._cacheMaintenance()
- return False
-
- def _cacheMaintenance(self):
- """Make sure cache does not contain to many packets
- """
- frequencyLimitToApply = int(self.frequencyLimit)
- maxNumberOfPackets = frequencyLimitToApply * 1000 # We assume that we never have more than 1000 packets per second
- if (len(self.stationHashTimestamps) > maxNumberOfPackets):
- try:
- self.stationHashTimestamps.popitem(last=False)
- except (KeyError, StopIteration) as e:
- pass
diff --git a/server/trackdirect/parser/AprsPacketParser.py b/server/trackdirect/parser/AprsPacketParser.py
deleted file mode 100644
index d8eabb82082cbfbca6f30f84f1d15417d476d5ed..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/AprsPacketParser.py
+++ /dev/null
@@ -1,629 +0,0 @@
-import logging
-from twisted.python import log
-import json
-import datetime
-import time
-import calendar
-import hashlib
-
-from trackdirect.exceptions.TrackDirectParseError import TrackDirectParseError
-from trackdirect.exceptions.TrackDirectMissingSenderError import TrackDirectMissingSenderError
-from trackdirect.exceptions.TrackDirectMissingStationError import TrackDirectMissingStationError
-
-from trackdirect.repositories.OgnHiddenStationRepository import OgnHiddenStationRepository
-from trackdirect.repositories.OgnDeviceRepository import OgnDeviceRepository
-from trackdirect.repositories.StationRepository import StationRepository
-from trackdirect.repositories.SenderRepository import SenderRepository
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.repositories.PacketTelemetryRepository import PacketTelemetryRepository
-from trackdirect.repositories.PacketWeatherRepository import PacketWeatherRepository
-from trackdirect.repositories.PacketOgnRepository import PacketOgnRepository
-from trackdirect.repositories.MarkerRepository import MarkerRepository
-from trackdirect.repositories.StationTelemetryBitsRepository import StationTelemetryBitsRepository
-from trackdirect.repositories.StationTelemetryEqnsRepository import StationTelemetryEqnsRepository
-from trackdirect.repositories.StationTelemetryParamRepository import StationTelemetryParamRepository
-from trackdirect.repositories.StationTelemetryUnitRepository import StationTelemetryUnitRepository
-
-from trackdirect.objects.Packet import Packet
-from trackdirect.objects.Station import Station
-from trackdirect.objects.PacketWeather import PacketWeather
-from trackdirect.objects.PacketTelemetry import PacketTelemetry
-from trackdirect.objects.Marker import Marker
-from trackdirect.objects.OgnHiddenStation import OgnHiddenStation
-from trackdirect.objects.OgnDevice import OgnDevice
-
-from trackdirect.parser.policies.AprsPacketTypePolicy import AprsPacketTypePolicy
-from trackdirect.parser.policies.PacketAssumedMoveTypePolicy import PacketAssumedMoveTypePolicy
-from trackdirect.parser.policies.PacketSpeedComputablePolicy import PacketSpeedComputablePolicy
-from trackdirect.parser.policies.PreviousPacketPolicy import PreviousPacketPolicy
-from trackdirect.parser.policies.PacketTailPolicy import PacketTailPolicy
-from trackdirect.parser.policies.PacketRelatedMapSectorsPolicy import PacketRelatedMapSectorsPolicy
-from trackdirect.parser.policies.PacketMapIdPolicy import PacketMapIdPolicy
-from trackdirect.parser.policies.PacketPathPolicy import PacketPathPolicy
-from trackdirect.parser.policies.MapSectorPolicy import MapSectorPolicy
-from trackdirect.parser.policies.PacketCommentPolicy import PacketCommentPolicy
-from trackdirect.parser.policies.PacketKillCharPolicy import PacketKillCharPolicy
-from trackdirect.parser.policies.StationNameFormatPolicy import StationNameFormatPolicy
-from trackdirect.parser.policies.PacketOgnDataPolicy import PacketOgnDataPolicy
-
-
-class AprsPacketParser():
- """AprsPacketParser tackes a aprslib output and converts it to a Trackdirect Packet
- """
-
- def __init__(self, db, saveOgnStationsWithMissingIdentity):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- saveOgnStationsWithMissingIdentity (boolean): True if we should not ignore stationss with a missing identity
- """
- self.db = db
- self.saveOgnStationsWithMissingIdentity = saveOgnStationsWithMissingIdentity
- self.logger = logging.getLogger('trackdirect')
-
- self.databaseWriteAccess = True
- self.sourceId = 1
-
- self.ognDeviceRepository = OgnDeviceRepository(db)
- self.ognHiddenStationRepository = OgnHiddenStationRepository(db)
- self.stationRepository = StationRepository(db)
- self.senderRepository = SenderRepository(db)
- self.packetRepository = PacketRepository(db)
- self.packetTelemetryRepository = PacketTelemetryRepository(db)
- self.packetWeatherRepository = PacketWeatherRepository(db)
- self.packetOgnRepository = PacketOgnRepository(db)
- self.markerRepository = MarkerRepository(db)
- self.stationTelemetryBitsRepository = StationTelemetryBitsRepository(db)
- self.stationTelemetryEqnsRepository = StationTelemetryEqnsRepository(db)
- self.stationTelemetryParamRepository = StationTelemetryParamRepository(db)
- self.stationTelemetryUnitRepository = StationTelemetryUnitRepository(db)
-
- def setDatabaseWriteAccess(self, databaseWriteAccess):
- """Enable or disable database updates
-
- Args:
- databaseWriteAccess (boolean): True if we have database access otherwise false
- """
- self.databaseWriteAccess = databaseWriteAccess
-
- def setSourceId(self, sourceId):
- """Set what source packet is from (APRS, CWOP ...)
-
- Args:
- sourceId (int): Id that corresponds to id in source-table
- """
- self.sourceId = sourceId
-
- def getPacket(self, data, timestamp=None, minimal=False):
- """Returns the resulting packet
-
- Args:
- data (dict): Raw packet data
- timestamp (int): Packet timestamp
- minimal (boolean): Set to true to only perform minimal parsing
-
- Returns:
- Packet
- """
- self.isHiddenStation = False
- self.data = data
- self.packet = Packet(self.db)
- self.packet.sourceId = self.sourceId
- self._parsePacketInitialValues(timestamp)
- self._parsePacketReportedTimestamp()
-
- # Parse OGN stuff before station-id, may result in no station to create
- self._parsePacketOgn()
- if (self.packet.mapId != 15):
- self._parsePacketType()
- self._parsePacketSender()
- self._parsePacketStationName()
- self._parsePacketStationId()
-
- self._parsePacketRng()
- self._parsePacketPhg()
-
- if (self.packet.stationId is None):
- self.packet.mapId = 4
- else:
- self._parsePacketComment()
- self._parsePacketWeather()
- self._parsePacketTelemetryDefinition()
- self._parsePacketTelemetry()
- self._parsePacketPosition()
- self._parsePacketPath()
-
- if (not minimal):
- previousPacketPolicy = PreviousPacketPolicy(
- self.packet, self.db)
- previousPacket = previousPacketPolicy.getPreviousPacket()
- self._parseAssumedMoveTypeId(previousPacket)
- self._parsePacketTail(previousPacket)
- self._parsePacketMapId(previousPacket)
- self._parsePacketPreviousTimestamps(previousPacket)
- self._parsePacketPhgRngTimestamps(previousPacket)
- self._parsePacketRelatedMapSectors(previousPacket)
-
- if (self.isHiddenStation):
- if (self.packet.ogn is not None):
- self.packet.ogn.ognAddressTypeId = None
- self.packet.ogn.ognSenderAddress = None
- self.packet.comment = None
- self.packet.raw = None
- return self.packet
-
- def _parsePacketInitialValues(self, timestamp):
- """Set packet initial values
-
- Args:
- timestamp (int): Packet timestamp
- """
- self.packet.raw = self.data['raw'].replace('\x00', '')
- self.packet.symbol = self.data['symbol'] if (
- 'symbol' in self.data) else None
- self.packet.symbolTable = self.data['symbol_table'] if (
- 'symbol_table' in self.data) else None
- self.packet.reportedTimestamp = self.data['timestamp'] if (
- 'timestamp' in self.data) else None
- self.packet.rawPath = self.data['to'] + ',' + ','.join(self.data['path']) if (
- 'path' in self.data and 'to' in self.data) else None
- if (timestamp is not None):
- self.packet.timestamp = timestamp
- else:
- self.packet.timestamp = int(time.time())
- self.packet.positionTimestamp = self.packet.timestamp
- self.packet.packetTailTimestamp = 0
- self.packet.posambiguity = self.data['posambiguity'] if (
- 'posambiguity' in self.data) else None
- self.packet.speed = self.data['speed'] if (
- 'speed' in self.data) else None
- self.packet.course = self.data['course'] if (
- 'course' in self.data) else None
- self.packet.altitude = self.data['altitude'] if (
- 'altitude' in self.data) else None
- self.packet.mapId = 10 # Default map for a packet without a position
- self.packet.markerId = 1
- self.packet.markerCounter = 1 # We allways start at 1
-
- def _parsePacketReportedTimestamp(self):
- """Set packet reported timestamp
- """
- if ('timestamp' in self.data):
- reportedTimestampDay = int(datetime.datetime.utcfromtimestamp(
- int(self.data['timestamp'])).strftime('%d'))
- currentTimestampDay = int(datetime.datetime.utcfromtimestamp(
- self.packet.timestamp).strftime('%d'))
- if (reportedTimestampDay > currentTimestampDay and self.data['timestamp'] > self.packet.timestamp):
- # Day is in the future, the reported timestamp was probably in previous month
-
- prevMonth = int(datetime.datetime.utcfromtimestamp(
- int(self.data['timestamp']) - (reportedTimestampDay+1)*24*60*60).strftime('%m'))
- prevMonthYear = int(datetime.datetime.utcfromtimestamp(
- int(self.data['timestamp']) - (reportedTimestampDay+1)*24*60*60).strftime('%Y'))
- numberOfDaysInMonth = int(
- calendar.monthrange(prevMonthYear, prevMonth)[1])
-
- self.packet.reportedTimestamp = int(
- self.data['timestamp']) - (numberOfDaysInMonth*24*60*60)
- else:
- self.packet.reportedTimestamp = None
-
- def _parsePacketRng(self):
- """Set packet RNG data
- """
- if ('rng' in self.data):
- try:
- self.packet.rng = float(self.data['rng'])
- self.packet.latestRngTimestamp = self.packet.timestamp
- if (self.packet.rng <= 0):
- self.packet.rng = None
- except ValueError:
- # Not a float
- self.packet.rng = None
-
- def _parsePacketPhg(self):
- """Set packet PHG data
- """
- if ('phg' in self.data):
- phg = str(self.data['phg'])[0:4]
- if (len(phg) == 4 and phg.isdigit()):
- self.packet.phg = phg
- self.packet.latestPhgTimestamp = self.packet.timestamp
-
- def _parsePacketSender(self):
- """Set sender id and name
- """
- stationNameFormatPolicy = StationNameFormatPolicy()
- self.packet.senderName = stationNameFormatPolicy.getCorrectFormat(
- self.data["from"])
- try:
- sender = self.senderRepository.getCachedObjectByName(
- self.packet.senderName)
- self.packet.senderId = sender.id
- except (TrackDirectMissingSenderError) as exp:
- if (self.databaseWriteAccess):
- sender = self.senderRepository.getObjectByName(
- self.packet.senderName, True, self.packet.sourceId)
- self.packet.senderId = sender.id
-
- def _parsePacketStationName(self):
- """Set station name
- """
- if ("object_name" in self.data
- and self.data["object_name"] is not None
- and self.data["object_name"] != ''):
- self.packet.stationTypeId = 2
- stationNameFormatPolicy = StationNameFormatPolicy()
- self.packet.stationName = stationNameFormatPolicy.getCorrectFormat(
- self.data["object_name"])
- if (self.packet.stationName is None or self.packet.stationName == ''):
- self.packet.stationName = self.packet.senderName
- if (self.packet.stationName == self.packet.senderName):
- self.packet.stationTypeId = 1
- else:
- self.packet.stationTypeId = 1
- self.packet.stationName = self.packet.senderName
-
- def _parsePacketStationId(self):
- """Set station id
- """
- if (self.packet.stationName is None):
- return
- try:
- station = self.stationRepository.getCachedObjectByName(
- self.packet.stationName,
- self.packet.sourceId
- )
- self.packet.stationId = station.id
-
- if (self.packet.stationName != station.name):
- # Station lower/upper case is modified
- station.name = self.packet.stationName
- station.save()
-
- if (station.stationTypeId != self.packet.stationTypeId and int(self.packet.stationTypeId) == 1):
- # Switch to station type 1
- station.stationTypeId = self.packet.stationTypeId
- station.save()
-
- except (TrackDirectMissingStationError) as exp:
- if (self.databaseWriteAccess):
- station = self.stationRepository.getObjectByName(
- self.packet.stationName,
- self.packet.sourceId,
- self.packet.stationTypeId,
- True
- )
- self.packet.stationId = station.id
-
- def _parsePacketComment(self):
- """Set packet comment
- """
- commentPolicy = PacketCommentPolicy()
- self.packet.comment = commentPolicy.getComment(
- self.data, self.packet.packetTypeId)
-
- def _parsePacketOgn(self):
- """Set th OGN sender address
- """
- ognDataPolicy = PacketOgnDataPolicy(
- self.data, self.ognDeviceRepository, self.packet.sourceId)
- if (ognDataPolicy.isOgnPositionPacket):
- originalRaw = self.packet.raw
-
- if (not ognDataPolicy.isAllowedToTrack):
- self.packet.mapId = 15
- return
-
- elif (not ognDataPolicy.isAllowedToIdentify):
- if (not self.saveOgnStationsWithMissingIdentity) :
- self.packet.mapId = 15
- return
- self.isHiddenStation = True
- self.data["from"] = self._getHiddenStationName()
- self.data["object_name"] = None
-
- self.data['ogn'] = ognDataPolicy.getOgnData()
- if (self.data['ogn'] is not None):
- self.packet.ogn = self.packetOgnRepository.getObjectFromPacketData(
- self.data)
- self.packet.ogn.stationId = self.packet.stationId
- self.packet.ogn.timestamp = self.packet.timestamp
- self.data["comment"] = None
- self._modifyOgnSymbol(originalRaw)
-
- def _modifyOgnSymbol(self, originalRaw):
- """Sets a better symbol for an OGN station
-
- Args:
- originalRaw (string): Non modified raw
- """
- if ((self.packet.symbol == '\'' and self.packet.symbolTable == '/') or (self.packet.symbol == '^' and self.packet.symbolTable in ['/', '\\']) or (self.packet.symbol == 'g' and self.packet.symbolTable in ['/'])):
- ognDevice = None
- if (self.packet.ogn is not None and self.packet.ogn.ognSenderAddress is not None):
- ognDevice = self.ognDeviceRepository.getObjectByDeviceId(
- self.packet.ogn.ognSenderAddress)
-
- if (ognDevice is not None and ognDevice.isExistingObject() and ognDevice.ddbAircraftType > 0 and ognDevice.ddbAircraftType < 6):
- # If another aircraft type exist in device db, use that instead
- if (ognDevice.ddbAircraftType == 1): # Gliders/motoGliders
- # Glider -> Glider
- self.packet.symbol = '^'
- self.packet.symbolTable = 'G'
-
- elif (ognDevice.ddbAircraftType == 2): # Planes
- # Powered aircraft -> Propeller aircraft
- self.packet.symbol = '^'
- self.packet.symbolTable = 'P'
-
- elif (ognDevice.ddbAircraftType == 3): # Ultralights
- # Small plane
- self.packet.symbol = '\''
- self.packet.symbolTable = '/'
-
- elif (ognDevice.ddbAircraftType == 4): # Helicopters
- # Helicopter
- self.packet.symbol = 'X'
- self.packet.symbolTable = '/'
-
- elif (ognDevice.ddbAircraftType == 5): # Drones/UAV
- # UAV -> Drone
- self.packet.symbol = '^'
- self.packet.symbolTable = 'D'
-
- elif (self.packet.ogn is not None and self.packet.ogn.ognAircraftTypeId is not None):
- if (self.packet.ogn.ognAircraftTypeId == 1):
- # Glider -> Glider
- self.packet.symbol = '^'
- self.packet.symbolTable = 'G'
- elif (self.packet.ogn.ognAircraftTypeId == 9):
- # Jet aircraft -> Jet
- self.packet.symbol = '^'
- self.packet.symbolTable = 'J'
- elif (self.packet.ogn.ognAircraftTypeId == 8):
- # Powered aircraft -> Propeller aircraft
- self.packet.symbol = '^'
- self.packet.symbolTable = 'P'
- elif (self.packet.ogn.ognAircraftTypeId == 13):
- # UAV -> Drone
- self.packet.symbol = '^'
- self.packet.symbolTable = 'D'
- elif (self.packet.ogn.ognAircraftTypeId == 7): #paraglider
- # map to own symbol 94-76.svg (do not show hangglider symbol 103-1.svg, 'g' = 103)
- self.packet.symbol = '^' #94
- self.packet.symbolTable = 'L' #76
-
- if ((self.packet.symbol == '\'' and self.packet.symbolTable == '/') or (self.packet.symbol == '^' and self.packet.symbolTable in ['/', '\\'])):
- # Current symbol is still "small aircraft" or "large aircraft"
- if (originalRaw.startswith('FMT')):
- # FMT, Remotely Piloted
- self.packet.symbol = '^'
- self.packet.symbolTable = 'R'
-
- def _getHiddenStationName(self):
- """Returnes a unidentifiable station name
-
- Returns:
- string
- """
- date = datetime.datetime.utcfromtimestamp(
- self.packet.timestamp).strftime('%Y%m%d')
- dailyStationNameHash = hashlib.sha256(
- self.data["from"] + date).hexdigest()
-
- ognHiddenStation = self.ognHiddenStationRepository.getObjectByHashedName(
- dailyStationNameHash, True)
- return ognHiddenStation.getStationName()
-
- def _parsePacketWeather(self):
- """Parse weather data
- """
- if ("weather" in self.data):
- self.packet.weather = self.packetWeatherRepository.getObjectFromPacketData(
- self.data)
- self.packet.weather.stationId = self.packet.stationId
- self.packet.weather.timestamp = self.packet.timestamp
-
- def _parsePacketTelemetry(self):
- """Parse telemetry data
- """
- if ("telemetry" in self.data):
- self.packet.telemetry = self.packetTelemetryRepository.getObjectFromPacketData(
- self.data)
- self.packet.telemetry.stationId = self.packet.stationId
- self.packet.telemetry.timestamp = self.packet.timestamp
-
- def _parsePacketTelemetryDefinition(self):
- """Parse telemetry definition
- """
- if ("tBITS" in self.data):
- self.packet.stationTelemetryBits = self.stationTelemetryBitsRepository.getObjectFromPacketData(
- self.data)
- self.packet.stationTelemetryBits.stationId = self.packet.stationId
- self.packet.stationTelemetryBits.timestamp = self.packet.timestamp
-
- if ("tEQNS" in self.data):
- self.packet.stationTelemetryEqns = self.stationTelemetryEqnsRepository.getObjectFromPacketData(
- self.data)
- self.packet.stationTelemetryEqns.stationId = self.packet.stationId
- self.packet.stationTelemetryEqns.timestamp = self.packet.timestamp
-
- if ("tPARM" in self.data):
- self.packet.stationTelemetryParam = self.stationTelemetryParamRepository.getObjectFromPacketData(
- self.data)
- self.packet.stationTelemetryParam.stationId = self.packet.stationId
- self.packet.stationTelemetryParam.timestamp = self.packet.timestamp
-
- if ("tUNIT" in self.data):
- self.packet.stationTelemetryUnit = self.stationTelemetryUnitRepository.getObjectFromPacketData(
- self.data)
- self.packet.stationTelemetryUnit.stationId = self.packet.stationId
- self.packet.stationTelemetryUnit.timestamp = self.packet.timestamp
-
- def _parsePacketType(self):
- """Set packet type
- """
- aprsPacketTypePolicy = AprsPacketTypePolicy()
- self.packet.packetTypeId = aprsPacketTypePolicy.getPacketType(
- self.packet)
-
- def _parsePacketPosition(self):
- """Parse the packet position and related attributes
- """
- if ("latitude" in self.data
- and "longitude" in self.data
- and self.data["latitude"] is not None
- and self.data["longitude"] is not None):
-
- self.packet.latitude = self.data['latitude']
- self.packet.longitude = self.data['longitude']
-
- mapSectorPolicy = MapSectorPolicy()
- self.packet.mapSector = mapSectorPolicy.getMapSector(
- self.data["latitude"], self.data["longitude"])
- self.packet.mapId = 1 # Default map for a packet with a position
- self.packet.isMoving = 1 # Moving/Stationary, default value is moving
-
- def _parsePacketPath(self):
- """Parse packet path
- """
- if ("path" in self.data and isinstance(self.data["path"], list)):
- packetPathPolicy = PacketPathPolicy(
- self.data['path'], self.packet.sourceId, self.stationRepository, self.senderRepository)
- self.packet.stationIdPath = packetPathPolicy.getStationIdPath()
- self.packet.stationNamePath = packetPathPolicy.getStationNamePath()
- self.packet.stationLocationPath = packetPathPolicy.getStationLocationPath()
-
- def _getPacketRawBody(self):
- """Returns packet raw body as string
-
- Returns:
- Packet raw body as string
- """
- try:
- (rawHeader, rawBody) = self.data["raw"].split(':', 1)
- except:
- raise TrackDirectParseError(
- 'Could not split packet into header and body', self.data)
-
- if len(rawBody) == 0:
- raise TrackDirectParseError('Packet body is empty', self.data)
- return rawBody
-
- def _parsePacketPhgRngTimestamps(self, previousPacket):
- """Set current packet timestamp when latest rng / phg was received
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- if (previousPacket.isExistingObject()
- and self.packet.isPostitionEqual(previousPacket)):
- if (self.packet.phg is None
- and previousPacket.latestPhgTimestamp is not None
- and previousPacket.latestPhgTimestamp > (self.packet.timestamp - (60*60*24))):
- self.latestPhgTimestamp = previousPacket.latestPhgTimestamp
-
- if (self.packet.rng is None
- and previousPacket.latestRngTimestamp is not None
- and previousPacket.latestRngTimestamp > (self.packet.timestamp - (60*60*24))):
- self.latestRngTimestamp = previousPacket.latestRngTimestamp
-
- def _parsePacketMapId(self, previousPacket):
- """Set current packet map id and related
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- mapIdPolicy = PacketMapIdPolicy(self.packet, previousPacket)
- killCharPolicy = PacketKillCharPolicy()
- if (killCharPolicy.hasKillCharacter(self.data)):
- mapIdPolicy.enableHavingKillCharacter()
-
- if (mapIdPolicy.isReplacingPreviousPacket()):
- self.packet.replacePacketId = previousPacket.id
- self.packet.replacePacketTimestamp = previousPacket.timestamp
-
- if (mapIdPolicy.isConfirmingPreviousPacket()):
- self.packet.confirmPacketId = previousPacket.id
- self.packet.confirmPacketTimestamp = previousPacket.timestamp
-
- if (mapIdPolicy.isKillingPreviousPacket()):
- self.packet.abnormalPacketId = previousPacket.id
- self.packet.abnormalPacketTimestamp = previousPacket.timestamp
-
- self.packet.mapId = mapIdPolicy.getMapId()
- self.packet.markerId = mapIdPolicy.getMarkerId()
- if (self.packet.markerId is None):
- # Policy could not find a marker id to use, create a new
- self.packet.markerId = self._getNewMarkerId()
- if (self.packet.markerId == 1):
- self.packet.mapId = 4
-
- def _parsePacketPreviousTimestamps(self, previousPacket):
- """Set packet previous timestamps and related
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- if (previousPacket.isExistingObject()
- and self.packet.markerId == previousPacket.markerId):
- isPostitionEqual = self.packet.isPostitionEqual(previousPacket)
- if (not self.databaseWriteAccess
- and isPostitionEqual
- and self.packet.isMoving == 1
- and previousPacket.positionTimestamp == previousPacket.timestamp):
- # This is probably the exact same packet
- self.packet.markerPrevPacketTimestamp = previousPacket.markerPrevPacketTimestamp
- self.packet.markerCounter = previousPacket.markerCounter
- self.packet.positionTimestamp = self.packet.timestamp
- else:
- self.packet.markerPrevPacketTimestamp = previousPacket.timestamp
- self.packet.markerCounter = previousPacket.markerCounter + 1
- if (isPostitionEqual):
- self.packet.positionTimestamp = previousPacket.positionTimestamp
- else:
- self.packet.positionTimestamp = self.packet.timestamp
-
- def _parseAssumedMoveTypeId(self, previousPacket):
- """Set current packet move type id
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- packetAssumedMoveTypePolicy = PacketAssumedMoveTypePolicy(self.db)
- self.packet.isMoving = packetAssumedMoveTypePolicy.getAssumedMoveType(self.packet, previousPacket)
-
- def _parsePacketTail(self, previousPacket):
- """Set current packet tail timestamp
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- packetTailPolicy = PacketTailPolicy(self.packet, previousPacket)
- self.packet.packetTailTimestamp = packetTailPolicy.getPacketTailTimestamp()
-
- def _parsePacketRelatedMapSectors(self, previousPacket):
- """Set current packet related map sectors
-
- Args:
- previousPacket (Packet): Packet object that represents the packet before the current packet
- """
- packetRelatedMapSectorsPolicy = PacketRelatedMapSectorsPolicy(
- self.packetRepository)
- self.packet.relatedMapSectors = packetRelatedMapSectorsPolicy.getAllRelatedMapSectors(
- self.packet, previousPacket)
-
- def _getNewMarkerId(self):
- """Creates a new marker id
-
- Returns:
- int
- """
- if (not self.databaseWriteAccess):
- return 1
- else:
- # No suitable marker id found, let's create a new!
- marker = self.markerRepository.create()
- marker.save()
- return marker.id
diff --git a/server/trackdirect/parser/__init__.py b/server/trackdirect/parser/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/parser/policies/AprsPacketSymbolPolicy.py b/server/trackdirect/parser/policies/AprsPacketSymbolPolicy.py
deleted file mode 100644
index 20e39008c884c0980276040c4787e152fe8968ce..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/AprsPacketSymbolPolicy.py
+++ /dev/null
@@ -1,410 +0,0 @@
-class AprsPacketSymbolPolicy():
- """The AprsPacketSymbolPolicy class can answer APRS symbol related questions for a specified packet symbol characters.
- """
-
- def __init__(self):
- """The __init__ method.
- """
- self.primarySymbolMoving = []
- self.primarySymbolStationary = []
- self.primarySymbolMaybeMoving = []
-
- self.alternativeSymbolMoving = []
- self.alternativeSymbolStationary = []
- self.alternativeSymbolMaybeMoving = []
-
- self.primarySymbolWeather = []
- self.alternativeSymbolWeather = []
-
- self._initSymbolArrays()
-
- def isMovingSymbol(self, symbol, symbolTable):
- """Returns true is symbol indicates that station is of moving type
-
- Args:
- symbol (string): The symbol character
- symbolTable (string): The symbol table character
-
- Returns:
- Boolean
- """
- if (symbolTable == "/"):
- # Primary symbol
- if (symbol in self.primarySymbolMoving):
- return True
- else:
- # Alternative Symbol
- if (symbol in self.alternativeSymbolMoving):
- return True
- return False
-
- def isMaybeMovingSymbol(self, symbol, symbolTable):
- """Returns true is symbol indicates that station maybe is moving
-
- Note:
- "maybe moving" means that station should be treated as it's stationary, but you should allways be ready to change your mind and treat it as moving.
-
- Args:
- symbol (string): The symbol character
- symbolTable (string): The symbol table character
-
- Returns:
- Boolean
- """
- if (symbolTable == "/"):
- # Primary symbol
- if (symbol in self.primarySymbolMaybeMoving):
- return True
- else:
- # Alternative Symbol
- if (symbol in self.alternativeSymbolMaybeMoving):
- return True
- return False
-
- def isStationarySymbol(self, symbol, symbolTable):
- """Returns true is symbol indicates that station seems to be stationary
-
- Args:
- symbol (string): The symbol character
- symbolTable (string): The symbol table character
-
- Returns:
- Boolean
- """
- if (symbolTable == "/"):
- # Primary symbol
- if (symbol in self.primarySymbolStationary):
- return True
- else:
- # Alternative Symbol
- if (symbol in self.alternativeSymbolStationary):
- return True
- return False
-
- def isWeatherSymbol(self, symbol, symbolTable):
- """Returns true is symbol seems to be a weather station symbol
-
- Args:
- symbol (string): The symbol character
- symbolTable (string): The symbol table character
-
- Returns:
- Boolean
- """
- if (symbolTable == "/"):
- # Primary symbol
- if (symbol in self.primarySymbolWeather):
- return True
- else:
- # Alternative Symbol
- if (symbol in self.alternativeSymbolWeather):
- return True
- return False
-
- def _initSymbolArrays(self):
- """Init the symbol arrays
- """
- # If we are not sure if it is moving or not we should set it to maybe moving
- # A station marked as stationary will not get a tail on map (it will get a new marker Id for each new position), until a certain limit
- self.primarySymbolStationary.append('!') # BB Police, Sheriff
- self.primarySymbolStationary.append('"') # BC reserved (was rain)
- self.primarySymbolStationary.append('#') # BD DIGI (white center)
- self.primarySymbolMaybeMoving.append('$') # BE PHONE
- self.primarySymbolStationary.append('%') # BF DX CLUSTER
- self.primarySymbolStationary.append('&') # BG HF GATEway
- self.primarySymbolMaybeMoving.append(
- '\'') # BH Small AIRCRAFT (SSID-11)
- self.primarySymbolMoving.append('(') # BI Mobile Satellite Station
- self.primarySymbolMaybeMoving.append(
- ')') # BJ Wheelchair (handicapped)
- self.primarySymbolMoving.append('*') # BK SnowMobile
- self.primarySymbolStationary.append('+') # BL Red Cross
- self.primarySymbolStationary.append(',') # BM Boy Scouts
- self.primarySymbolStationary.append('-') # BN House QTH (VHF)
- self.primarySymbolStationary.append('.') # BO X
- self.primarySymbolMaybeMoving.append('/') # BP Red Dot
- self.primarySymbolMaybeMoving.append('0') # P0 # circle (obsolete)
- self.primarySymbolMaybeMoving.append(
- '1') # P1 TBD (these were numbered)
- self.primarySymbolMaybeMoving.append(
- '2') # P2 TBD (circles like pool)
- self.primarySymbolMaybeMoving.append('3') # P3 TBD (balls. But with)
- self.primarySymbolMaybeMoving.append('4') # P4 TBD (overlays, we can)
- self.primarySymbolMaybeMoving.append(
- '5') # P5 TBD (put all #'s on one)
- self.primarySymbolMaybeMoving.append(
- '6') # P6 TBD (So 1-9 are available)
- self.primarySymbolMaybeMoving.append('7') # P7 TBD (for new uses?)
- self.primarySymbolMaybeMoving.append(
- '8') # P8 TBD (They are often used)
- self.primarySymbolMaybeMoving.append(
- '9') # P9 TBD (as mobiles at events)
- self.primarySymbolStationary.append(':') # MR FIRE
- self.primarySymbolMaybeMoving.append(
- ';') # MS Campground (Portable ops)
- self.primarySymbolMoving.append('<') # MT Motorcycle (SSID-10)
- self.primarySymbolMaybeMoving.append('=') # MU RAILROAD ENGINE
- self.primarySymbolMoving.append('>') # MV CAR (SSID-9)
- self.primarySymbolStationary.append('?') # MW SERVER for Files
- self.primarySymbolStationary.append('@') # MX HC FUTURE predict (dot)
- self.primarySymbolStationary.append('A') # PA Aid Station
- self.primarySymbolStationary.append('B') # PB BBS or PBBS
- self.primarySymbolMoving.append('C') # PC Canoe
- self.primarySymbolStationary.append('D') # PD
- self.primarySymbolStationary.append('E') # PE EYEBALL (Events, etc!)
- self.primarySymbolMoving.append('F') # PF Farm Vehicle (tractor)
- self.primarySymbolStationary.append('G') # PG Grid Square (6 digit)
- self.primarySymbolStationary.append('H') # PH HOTEL (blue bed symbol)
- self.primarySymbolStationary.append(
- 'I') # PI TcpIp on air network stn
- self.primarySymbolStationary.append('J') # PJ
- self.primarySymbolStationary.append('K') # PK School
- self.primarySymbolMaybeMoving.append('L') # PL PC user (Jan 03)
- self.primarySymbolMaybeMoving.append('M') # PM MacAPRS
- self.primarySymbolStationary.append('N') # PN NTS Station
- self.primarySymbolMoving.append('O') # PO BALLOON (SSID-11)
- self.primarySymbolMaybeMoving.append('P') # PP Police
- self.primarySymbolStationary.append('Q') # PQ TBD
- self.primarySymbolMaybeMoving.append(
- 'R') # PR REC. VEHICLE (SSID-13)
- self.primarySymbolMaybeMoving.append('S') # PS SHUTTLE
- self.primarySymbolStationary.append('T') # PT SSTV
- self.primarySymbolMoving.append('U') # PU BUS (SSID-2)
- self.primarySymbolStationary.append('V') # PV ATV
- self.primarySymbolStationary.append(
- 'W') # PW National WX Service Site
- self.primarySymbolMaybeMoving.append(
- 'X') # PX HELO (SSID-6)
- self.primarySymbolMoving.append('Y') # PY YACHT (sail) (SSID-5)
- self.primarySymbolMaybeMoving.append('Z') # PZ WinAPRS
- self.primarySymbolMoving.append('[') # HS Human/Person (SSID-7)
- self.primarySymbolStationary.append('\\') # HT TRIANGLE(DF station)
- self.primarySymbolStationary.append(
- ']') # HU MAIL/PostOffice(was PBBS)
- self.primarySymbolMaybeMoving.append('^') # HV LARGE AIRCRAFT
- self.primarySymbolStationary.append('_') # HW WEATHER Station (blue)
- self.primarySymbolStationary.append('`') # HX Dish Antenna
- self.primarySymbolMaybeMoving.append('a') # LA AMBULANCE (SSID-1)
- self.primarySymbolMoving.append('b') # LB BIKE (SSID-4)
- self.primarySymbolStationary.append('c') # LC Incident Command Post
- self.primarySymbolStationary.append('d') # LD Fire dept
- self.primarySymbolMoving.append('e') # LE HORSE (equestrian)
- self.primarySymbolMaybeMoving.append('f') # LF FIRE TRUCK (SSID-3)
- self.primarySymbolMoving.append('g') # LG Glider
- self.primarySymbolStationary.append('h') # LH HOSPITAL
- self.primarySymbolStationary.append(
- 'i') # LI IOTA (islands on the air)
- self.primarySymbolMoving.append('j') # LJ JEEP (SSID-12)
- self.primarySymbolMoving.append('k') # LK TRUCK (SSID-14)
- self.primarySymbolMaybeMoving.append(
- 'l') # LL Laptop (Jan 03) (Feb 07)
- self.primarySymbolStationary.append('m') # LM Mic-E Repeater
- self.primarySymbolStationary.append('n') # LN Node (black bulls-eye)
- self.primarySymbolStationary.append('o') # LO EOC
- self.primarySymbolMoving.append('p') # LP ROVER (puppy, or dog)
- self.primarySymbolStationary.append(
- 'q') # LQ GRID SQ shown above 128 m
- self.primarySymbolStationary.append(
- 'r') # LR Repeater (Feb 07)
- self.primarySymbolMoving.append('s') # LS SHIP (pwr boat) (SSID-8)
- self.primarySymbolStationary.append('t') # LT TRUCK STOP
- self.primarySymbolMoving.append('u') # LU TRUCK (18 wheeler)
- self.primarySymbolMoving.append('v') # LV VAN (SSID-15)
- self.primarySymbolStationary.append('w') # LW WATER station
- self.primarySymbolStationary.append('x') # LX xAPRS (Unix)
- self.primarySymbolStationary.append('y') # LY YAGI @ QTH
- self.primarySymbolStationary.append('z') # LZ TBD
- self.primarySymbolStationary.append('{') # J1
- self.primarySymbolStationary.append('|') # J2 TNC Stream Switch
- self.primarySymbolStationary.append('}') # J3
- self.primarySymbolStationary.append('~') # J4 TNC Stream Switch
-
- self.alternativeSymbolStationary.append(
- '!') # OBO EMERGENCY (and overlays)
- self.alternativeSymbolStationary.append('"') # OC reserved
- self.alternativeSymbolStationary.append(
- '#') # OD# OVERLAY DIGI (green star)
- self.alternativeSymbolStationary.append(
- '$') # OEO Bank or ATM (green box)
- self.alternativeSymbolStationary.append(
- '%') # OFO Power Plant with overlay
- self.alternativeSymbolStationary.append(
- '&') # OG# I=Igte R=RX T=1hopTX 2=2hopTX
- self.alternativeSymbolStationary.append(
- '\'') # OHO Crash (& now Incident sites)
- self.alternativeSymbolStationary.append(
- '(') # OIO CLOUDY (other clouds w ovrly)
- # OJO Firenet MEO, MODIS Earth Obs.
- self.alternativeSymbolStationary.append(')')
- self.alternativeSymbolStationary.append(
- '*') # OK AVAIL (SNOW moved to ` ovly S)
- self.alternativeSymbolStationary.append('+') # OL Church
- self.alternativeSymbolStationary.append(',') # OM Girl Scouts
- self.alternativeSymbolStationary.append(
- '-') # ONO House (H=HF) (O = Op Present)
- self.alternativeSymbolStationary.append(
- '.') # OO Ambiguous (Big Question mark)
- self.alternativeSymbolStationary.append(
- '/') # OP Waypoint Destination
- self.alternativeSymbolStationary.append(
- '0') # A0# CIRCLE (IRLP/Echolink/WIRES)
- self.alternativeSymbolStationary.append('1') # A1 AVAIL
- self.alternativeSymbolStationary.append('2') # A2 AVAIL
- self.alternativeSymbolStationary.append('3') # A3 AVAIL
- self.alternativeSymbolStationary.append('4') # A4 AVAIL
- self.alternativeSymbolStationary.append('5') # A5 AVAIL
- self.alternativeSymbolStationary.append('6') # A6 AVAIL
- self.alternativeSymbolStationary.append('7') # A7 AVAIL
- self.alternativeSymbolMaybeMoving.append(
- '8') # A8O 802.11 or other network node
- self.alternativeSymbolStationary.append(
- '9') # A9 Gas Station (blue pump)
- self.alternativeSymbolStationary.append(
- ':') # NR AVAIL (Hail ==> ` ovly H)
- self.alternativeSymbolStationary.append(
- ';') # NSO Park/Picnic + overlay events
- self.alternativeSymbolStationary.append(
- '<') # NTO ADVISORY (one WX flag)
- self.alternativeSymbolMaybeMoving.append(
- '=') # NUO APRStt Touchtone (DTMF users)
- self.alternativeSymbolMoving.append(
- '>') # NV# OVERLAYED CARs & Vehicles
- self.alternativeSymbolStationary.append(
- '?') # NW INFO Kiosk (Blue box with ?)
- self.alternativeSymbolStationary.append('@') # NX HURICANE/Trop-Storm
- self.alternativeSymbolStationary.append(
- 'A') # AA# overlayBOX DTMF & RFID & XO
- self.alternativeSymbolStationary.append(
- 'B') # AB AVAIL (BlwngSnow ==> E ovly B
- self.alternativeSymbolStationary.append('C') # AC Coast Guard
- self.alternativeSymbolStationary.append(
- 'D') # ADO DEPOTS (Drizzle ==> ' ovly D)
- self.alternativeSymbolStationary.append(
- 'E') # AE Smoke (& other vis codes)
- self.alternativeSymbolStationary.append(
- 'F') # AF AVAIL (FrzngRain ==> `F)
- self.alternativeSymbolStationary.append(
- 'G') # AG AVAIL (Snow Shwr ==> I ovly S)
- self.alternativeSymbolStationary.append(
- 'H') # AHO \Haze (& Overlay Hazards)
- self.alternativeSymbolStationary.append('I') # AI Rain Shower
- # AJ AVAIL (Lightening ==> I ovly L)
- self.alternativeSymbolStationary.append('J')
- self.alternativeSymbolMaybeMoving.append('K') # AK Kenwood HT (W)
- self.alternativeSymbolStationary.append('L') # AL Lighthouse
- self.alternativeSymbolStationary.append(
- 'M') # AMO MARS (A=Army,N=Navy,F=AF)
- self.alternativeSymbolStationary.append('N') # AN Navigation Buoy
- self.alternativeSymbolMaybeMoving.append(
- 'O') # AO Overlay Balloon (Rocket = \O)
- # AP Parking [Some cars use this when they stop]
- self.alternativeSymbolMaybeMoving.append('P')
- self.alternativeSymbolStationary.append('Q') # AQ QUAKE
- self.alternativeSymbolStationary.append('R') # ARO Restaurant
- self.alternativeSymbolMoving.append('S') # AS Satellite/Pacsat
- self.alternativeSymbolStationary.append('T') # AT Thunderstorm
- self.alternativeSymbolStationary.append('U') # AU SUNNY
- self.alternativeSymbolStationary.append('V') # AV VORTAC Nav Aid
- self.alternativeSymbolStationary.append(
- 'W') # AW# # NWS site (NWS options)
- self.alternativeSymbolStationary.append(
- 'X') # AX Pharmacy Rx (Apothicary)
- self.alternativeSymbolMaybeMoving.append('Y') # AYO Radios and devices
- self.alternativeSymbolStationary.append('Z') # AZ AVAIL
- self.alternativeSymbolMaybeMoving.append(
- '[') # DSO W.Cloud (& humans w Ovrly)
- self.alternativeSymbolMaybeMoving.append(
- '\\') # DTO New overlayable GPS symbol
- self.alternativeSymbolStationary.append(']') # DU AVAIL
- self.alternativeSymbolMaybeMoving.append(
- '^') # DV# other Aircraft ovrlys (2014)
- self.alternativeSymbolStationary.append(
- '_') # DW# # WX site (green digi)
- self.alternativeSymbolStationary.append(
- '`') # DX Rain (all types w ovrly)
- self.alternativeSymbolStationary.append(
- 'a') # SA#O ARRL,ARES,WinLINK,Dstar, etc
- self.alternativeSymbolStationary.append(
- 'b') # SB AVAIL(Blwng Dst/Snd => E ovly)
- self.alternativeSymbolStationary.append(
- 'c') # SC#O CD triangle RACES/SATERN/etc
- self.alternativeSymbolStationary.append('d') # SD DX spot by callsign
- self.alternativeSymbolStationary.append(
- 'e') # SE Sleet (& future ovrly codes)
- self.alternativeSymbolStationary.append('f') # SF Funnel Cloud
- self.alternativeSymbolStationary.append('g') # SG Gale Flags
- self.alternativeSymbolStationary.append(
- 'h') # SHO Store. or HAMFST Hh=HAM store
- self.alternativeSymbolStationary.append(
- 'i') # SI# BOX or points of Interest
- self.alternativeSymbolMaybeMoving.append(
- 'j') # SJ WorkZone (Steam Shovel)
- # SKO Special Vehicle SUV,ATV,4x4
- self.alternativeSymbolMoving.append('k')
- self.alternativeSymbolStationary.append(
- 'l') # SL Areas(box,circles,etc)
- self.alternativeSymbolStationary.append(
- 'm') # SM Value Sign (3 digit display)
- self.alternativeSymbolStationary.append('n') # SN# OVERLAY TRIANGLE
- self.alternativeSymbolStationary.append('o') # SO small circle
- self.alternativeSymbolStationary.append(
- 'p') # SP AVAIL (PrtlyCldy => ( ovly P
- self.alternativeSymbolStationary.append('q') # SQ AVAIL
- self.alternativeSymbolStationary.append('r') # SR Restrooms
- self.alternativeSymbolMoving.append('s') # SS# OVERLAY SHIP/boats
- self.alternativeSymbolStationary.append('t') # ST Tornado
- self.alternativeSymbolMoving.append('u') # SU# OVERLAYED TRUCK
- self.alternativeSymbolMoving.append('v') # SV# OVERLAYED Van
- self.alternativeSymbolStationary.append(
- 'w') # SWO Flooding (Avalanches/Slides)
- self.alternativeSymbolStationary.append(
- 'x') # SX Wreck or Obstruction ->X<-
- self.alternativeSymbolStationary.append('y') # SY Skywarn
- self.alternativeSymbolStationary.append('z') # SZ# OVERLAYED Shelter
- self.alternativeSymbolStationary.append(
- '{') # Q1 AVAIL? (Fog ==> E ovly F)
- self.alternativeSymbolStationary.append('|') # Q2 TNC Stream Switch
- self.alternativeSymbolStationary.append('}') # Q3 AVAIL? (maybe)
- self.alternativeSymbolStationary.append('~') # Q4 TNC Stream Switch
-
- self.primarySymbolWeather.append('W') # PW National WX Service Site
- self.primarySymbolWeather.append('_') # HW WEATHER Station (blue)
-
- self.alternativeSymbolWeather.append(
- '(') # OIO CLOUDY (other clouds w ovrly)
- # OK AVAIL (SNOW moved to ` ovly S)
- self.alternativeSymbolWeather.append('*')
- self.alternativeSymbolWeather.append(
- ':') # NR AVAIL (Hail ==> ` ovly H)
- self.alternativeSymbolWeather.append('@') # NX HURICANE/Trop-Storm
- self.alternativeSymbolWeather.append(
- 'B') # AB AVAIL (BlwngSnow ==> E ovly B
- # ADO DEPOTS (Drizzle ==> ' ovly D)
- self.alternativeSymbolWeather.append('D')
- self.alternativeSymbolWeather.append(
- 'F') # AF AVAIL (FrzngRain ==> `F)
- # AG AVAIL (Snow Shwr ==> I ovly S)
- self.alternativeSymbolWeather.append('G')
- self.alternativeSymbolWeather.append(
- 'H') # AHO \Haze (& Overlay Hazards)
- self.alternativeSymbolWeather.append('I') # AI Rain Shower
- # AJ AVAIL (Lightening ==> I ovly L)
- self.alternativeSymbolWeather.append('J')
- self.alternativeSymbolWeather.append('T') # AT Thunderstorm
- self.alternativeSymbolWeather.append('U') # AU SUNNY
- self.alternativeSymbolWeather.append(
- '[') # DSO W.Cloud (& humans w Ovrly)
- self.alternativeSymbolWeather.append('_') # DW# # WX site (green digi)
- self.alternativeSymbolWeather.append(
- '`') # DX Rain (all types w ovrly)
- # SB AVAIL(Blwng Dst/Snd => E ovly)
- self.alternativeSymbolWeather.append('b')
- # SE Sleet (& future ovrly codes)
- self.alternativeSymbolWeather.append('e')
- self.alternativeSymbolWeather.append('f') # SF Funnel Cloud
- # SP AVAIL (PrtlyCldy => ( ovly P
- self.alternativeSymbolWeather.append('p')
- self.alternativeSymbolWeather.append('t') # ST Tornado
- self.alternativeSymbolWeather.append('y') # SY Skywarn
- self.alternativeSymbolWeather.append(
- '{') # Q1 AVAIL? (Fog ==> E ovly F)
diff --git a/server/trackdirect/parser/policies/AprsPacketTypePolicy.py b/server/trackdirect/parser/policies/AprsPacketTypePolicy.py
deleted file mode 100644
index 651cae2e5a4397a823df33d76f7da07b278a8695..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/AprsPacketTypePolicy.py
+++ /dev/null
@@ -1,275 +0,0 @@
-from trackdirect.exceptions.TrackDirectParseError import TrackDirectParseError
-
-
-class AprsPacketTypePolicy():
- """The AprsPacketTypePolicy class can answer questions related to what packet type
- """
-
- def __init__(self):
- """The __init__ method.
- """
- self.onlyPositionCharList = []
- self.generalPositionCharList = []
- self.objectCharList = []
- self.itemCharList = []
- self.weatherCharList = []
- self.telemetryCharList = []
- self.messageCharList = []
- self.queryCharList = []
- self.statusCharList = []
- self.otherCharList = []
- self._initPacketTypeArrays()
-
- def getPacketType(self, packet):
- """Returns the packet type id
-
- Args:
- packet (Packet): Packet that we want analyze
-
- Returns:
- Packet type id as integer
- """
- if (packet is None):
- return 11
- elif (packet.sourceId == 4):
- return 12
- else:
- packetTypeChar = self._getPacketTypeChar(packet)
-
- if (self._isPositionPacketType(packetTypeChar)):
- return 1
- elif (self._isGeneralPositionPacketType(packetTypeChar)):
- if (packet.symbol == "\\" and packet.symbolTable == "/"):
- return 2
- elif (packet.symbol == "_"):
- return 3
- else:
- return 1
- elif (self._isObjectPacketType(packetTypeChar)):
- return 4
- elif (self._isItemPacketType(packetTypeChar)):
- return 5
- elif (self._isWeatherPacketType(packetTypeChar)):
- return 3
- elif (self._isTelemetryPacketType(packetTypeChar)):
- return 6
- elif (self._isMessagePacketType(packetTypeChar)):
- return 7
- elif (self._isQueryPacketType(packetTypeChar)):
- return 8
- elif (self._isStatusPacketType(packetTypeChar)):
- return 10
- elif (self._isOtherPacketType(packetTypeChar)):
- return 11
- else:
- return 11
-
- def _isPositionPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type position
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type position
- """
- if (packetTypeChar in self.onlyPositionCharList):
- return True
- else:
- return False
-
- def _isGeneralPositionPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type general position
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type general position
- """
- if (packetTypeChar in self.generalPositionCharList):
- return True
- else:
- return False
-
- def _isObjectPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type object
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type object
- """
- if (packetTypeChar in self.objectCharList):
- return True
- else:
- return False
-
- def _isItemPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type item
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type item
- """
- if (packetTypeChar in self.itemCharList):
- return True
- else:
- return False
-
- def _isWeatherPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type weather
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type weather
- """
- if (packetTypeChar in self.weatherCharList):
- return True
- else:
- return False
-
- def _isTelemetryPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type telemetry
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type telemetry
- """
- if (packetTypeChar in self.telemetryCharList):
- return True
- else:
- return False
-
- def _isMessagePacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type message
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type message
- """
- if (packetTypeChar in self.messageCharList):
- return True
- else:
- return False
-
- def _isQueryPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type query
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type query
- """
- if (packetTypeChar in self.queryCharList):
- return True
- else:
- return False
-
- def _isStatusPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type status
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type status
- """
- if (packetTypeChar in self.statusCharList):
- return True
- else:
- return False
-
- def _isOtherPacketType(self, packetTypeChar):
- """Returns true if the specified packet type character is of type other
-
- Args:
- None
-
- Returns:
- True if the specified packet type character is of type other
- """
- if (packetTypeChar in self.otherCharList):
- return True
- else:
- return False
-
- def _initPacketTypeArrays(self):
- """Init the packet type arrays
-
- Args:
- None
- """
- self.onlyPositionCharList.append("`") # New Mic-E data
- self.onlyPositionCharList.append("'") # Old Mic-E data
- self.onlyPositionCharList.append("[") # maidenhead locator beacon
- self.onlyPositionCharList.append("$") # raw gps
-
- # Position without timestamp (no APRS messaging), or Ultimeter 2000 WX Station
- self.generalPositionCharList.append("!")
- # Position without timestamp (with APRS messaging)
- self.generalPositionCharList.append("=")
- # Position with timestamp (no APRS messaging)
- self.generalPositionCharList.append("/")
- # Position with timestamp (with APRS messaging)
- self.generalPositionCharList.append("@")
-
- self.objectCharList.append(";") # Object
-
- self.itemCharList.append(")") # item report
-
- self.weatherCharList.append("#") # raw weather report
- self.weatherCharList.append("*") # complete weather report
- self.weatherCharList.append("_") # positionless weather report
-
- self.telemetryCharList.append("T") # telemetry report"
-
- self.messageCharList.append(":") # Message
-
- self.queryCharList.append("?") # general query format
-
- self.statusCharList.append(">") # Status
-
- self.otherCharList.append("%") # agrelo
- self.otherCharList.append("&") # reserved
- self.otherCharList.append("(") # unused
- self.otherCharList.append("+") # reserved
- self.otherCharList.append(",") # invalid/test format
- self.otherCharList.append("-") # unused
- self.otherCharList.append(".") # reserved
- self.otherCharList.append("<") # station capabilities
- self.otherCharList.append("\\") # unused
- self.otherCharList.append("]") # unused
- self.otherCharList.append("^") # unused
- self.otherCharList.append("{") # user defined
- self.otherCharList.append("}") # 3rd party traffic
-
- def _getPacketTypeChar(self, packet):
- """Returns the packet type char
-
- Args:
- packet (Packet): Packet object to find type char for
-
- Returns:
- Packet type char
- """
- try:
- (rawHeader, rawBody) = packet.raw.split(':', 1)
- except:
- raise TrackDirectParseError(
- 'Could not split packet into header and body', packet)
-
- if len(rawBody) == 0:
- raise TrackDirectParseError('Packet body is empty', packet)
-
- return rawBody[0]
diff --git a/server/trackdirect/parser/policies/MapSectorPolicy.py b/server/trackdirect/parser/policies/MapSectorPolicy.py
deleted file mode 100644
index 07ef365a7ebcdee9cb4861fdc87dac40489f46b6..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/MapSectorPolicy.py
+++ /dev/null
@@ -1,78 +0,0 @@
-from math import floor, ceil
-
-
-class MapSectorPolicy():
- """The MapSectorPolicy class hanles logic related to map sectors
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def getMapSector(self, latitude, longitude):
- """Returns a map sector integer specified by latitude and longitude
-
- Args:
- latitude (float): Numeric latitude
- longitude (float): Numeric longitude
-
- Returns:
- A map sector integer
- """
- if (type(latitude) is float and type(longitude) is float):
- lat = self.getMapSectorLatRepresentation(latitude)
- lng = self.getMapSectorLngRepresentation(longitude)
-
- # lat interval: 0 - 18000000
- # lng interval: 0 - 00003600
- return lat+lng
- else:
- return None
-
- def getMapSectorLatRepresentation(self, latitude):
- """Returns the latitude part of a map sector integer
-
- Args:
- latitude (float): Numeric latitude
-
- Returns:
- The latitude part of a map sector integer
- """
- lat = int(floor(latitude)) + 90 # Positive representation of lat
- latDecimalPart = latitude - floor(latitude)
-
- if (latDecimalPart < 0.2):
- lat = lat * 10 + 0
- elif (latDecimalPart < 0.4):
- lat = lat * 10 + 2
- elif (latDecimalPart < 0.6):
- lat = lat * 10 + 4
- elif (latDecimalPart < 0.8):
- lat = lat * 10 + 6
- else:
- lat = lat * 10 + 8
-
- lat = lat * 10000
-
- # lat interval: 0 - 18000000
- return lat
-
- def getMapSectorLngRepresentation(self, longitude):
- """Returns the longitude part of a map sector integer
-
- Args:
- longitude (float): Numeric latitude
-
- Returns:
- The longitude part of a map sector integer
- """
- lng = int(floor(longitude)) + 180 # Positive representation of lng
- lngDecimalPart = longitude - floor(longitude)
-
- if (lngDecimalPart < 0.5):
- lng = lng * 10 + 0
- else:
- lng = lng * 10 + 5
-
- # lng interval: 0 - 00003600
- return lng
diff --git a/server/trackdirect/parser/policies/PacketAssumedMoveTypePolicy.py b/server/trackdirect/parser/policies/PacketAssumedMoveTypePolicy.py
deleted file mode 100644
index 4ea33a5877772def5f300d6070b9db3556390a53..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketAssumedMoveTypePolicy.py
+++ /dev/null
@@ -1,174 +0,0 @@
-from trackdirect.parser.policies.AprsPacketSymbolPolicy import AprsPacketSymbolPolicy
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-
-
-class PacketAssumedMoveTypePolicy():
- """PacketAssumedMoveTypeIdPolicy calculates a packets default move type
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getAssumedMoveType(self, packet, prevPacket):
- """Returns the current packet move type based on if it seems to be moving or not
-
- Args:
- packet (Packet): Packet that we want to know move typ for
- prevPacket (Packet): Previous related packet for the same station
-
- Returns:
- Returns the current packet move type id as integer
- """
- isMoving = self._getDefaultAssumedMoveType(packet)
- if (prevPacket.isExistingObject()
- and isMoving == 0
- and not self._isBalloonPredictedTouchdown(packet)):
- aprsPacketSymbolPolicy = AprsPacketSymbolPolicy()
-
- # If assumed stationary we validate this by comparing to previous packet
- if (packet.isSymbolEqual(prevPacket)
- and (prevPacket.timestamp - prevPacket.positionTimestamp) < 36000
- and prevPacket.isMoving == 1):
- # Previous packet has same symbol and is moving
- # (If previous was moving so should this)
- isMoving = 1
-
- elif (aprsPacketSymbolPolicy.isMaybeMovingSymbol(packet.symbol, packet.symbolTable)
- and prevPacket.isMoving == 1):
- # symbol that maybe is moving is considered moving if prev packet is moving
- isMoving = 1
-
- elif (packet.isSymbolEqual(prevPacket)
- and not packet.isPostitionEqual(prevPacket)):
- # Previous packet has same symbol and another position
- isMoving = 1
-
- elif (not packet.isPostitionEqual(prevPacket)):
- # Previous packet has another symbol and another position
- # In this case we do a deper investigation... (this is to heavy to do for all packets)
- numberOfPackets = self._getNumberOfPacketWithSameSymbolAndOtherPos(
- packet, packet.timestamp - 86400
- )
-
- if (numberOfPackets > 0):
- # We have more then 1 positions for this symbol from this station, assume it is moving
- isMoving = 1
- return isMoving
-
- def _isBalloonPredictedTouchdown(self, packet):
- """Returns true if packet probably is a balloon touchdown
-
- Args:
- packet (Packet): Packet that we want to know move typ for
-
- Returns:
- true if packet probably is a balloon touchdown otherwise false
- """
- if (packet.symbolTable != "/" and packet.symbol == "o"):
- # Symbol is a small circle often used as predicted touchdown
- if (packet.comment is not None and "touchdown" in packet.comment):
- return True
- return False
-
- def _getDefaultAssumedMoveType(self, packet):
- """Returns the default packet move type id
-
- Args:
- packet (Packet): Packet that we want to know move typ for
-
- Returns:
- Returns the default packet move type id as integer
- """
- # Default is moving and if we are not sure we should choose moving
- isMoving = 1
- if (packet is not None
- and packet.symbol is not None
- and packet.symbolTable is not None):
- # First we set a initial value based on symbol
- aprsPacketSymbolPolicy = AprsPacketSymbolPolicy()
- if (aprsPacketSymbolPolicy.isStationarySymbol(packet.symbol, packet.symbolTable)
- or aprsPacketSymbolPolicy.isMaybeMovingSymbol(packet.symbol, packet.symbolTable)):
- isMoving = 0
- if (isMoving == 0 and self._isSsidIndicateMoving(packet.stationName)
- and aprsPacketSymbolPolicy.isMaybeMovingSymbol(packet.symbol, packet.symbolTable)):
- isMoving = 1
- if (isMoving == 0
- and (packet.course is not None or packet.speed is not None)
- and packet.packetTypeId != 3):
- # Packet has a speed and a course and is not a weather packet!
- # If it looks like a weather station we validate that speed is higher than 0
- if (aprsPacketSymbolPolicy.isMaybeMovingSymbol(packet.symbol, packet.symbolTable)):
- isMoving = 1
- elif (self._isSsidIndicateMoving(packet.stationName)):
- isMoving = 1
- elif (packet.speed is not None and packet.speed > 0):
- # A moving stationary station?!
- isMoving = 1
- elif (packet.course is not None and packet.course > 0):
- # A moving stationary station?!
- isMoving = 1
- return isMoving
-
- def _isSsidIndicateMoving(self, stationName):
- """Returns true if station SSID indicates moving
-
- Args:
- stationName (string): Packet station name
-
- Returns:
- Returns true if station SSID indicates moving otherwise false
- """
- if (stationName.endswith('-7')):
- # walkie talkies, HT's or other human portable
- return True
- elif (stationName.endswith('-8')):
- # boats, sailboats, RV's or second main mobile
- return True
- elif (stationName.endswith('-9')):
- # Primary Mobile (usually message capable)
- return True
- elif (stationName.endswith('-11')):
- # balloons, aircraft, spacecraft, etc
- return True
- elif (stationName.endswith('-14')):
- # Truckers or generally full time drivers
- return True
- else:
- return False
-
- def _getNumberOfPacketWithSameSymbolAndOtherPos(self, packet, minTimestamp):
- """Returns the number of packets that has the same symbol but another position (for the same station)
-
- Args:
- stationId (int): Id of the station
- packet (Packet): Packet instance that we base the search on
-
- Returns:
- The number of packets that has the same symbol but another position
- """
- selectCursor = self.db.cursor()
- packetTableCreator = PacketTableCreator(self.db)
- packetTables = packetTableCreator.getPacketTables(minTimestamp)
- result = 0
- for packetTable in packetTables:
- sql = selectCursor.mogrify("""select count(*) number_of_packets from """ + packetTable + """ where station_id = %s and map_id = 1 and symbol = %s and symbol_table = %s and latitude != %s and longitude != %s""", (
- packet.stationId,
- packet.symbol,
- packet.symbolTable,
- packet.latitude,
- packet.longitude,))
-
- selectCursor = self.db.cursor()
- selectCursor.execute(sql)
- record = selectCursor.fetchone()
-
- if (record is not None):
- result = result + record["number_of_packets"]
-
- selectCursor.close()
- return result
diff --git a/server/trackdirect/parser/policies/PacketCommentPolicy.py b/server/trackdirect/parser/policies/PacketCommentPolicy.py
deleted file mode 100644
index e2fde323f9ecdcfd9a69a0de5f004582ff6bf543..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketCommentPolicy.py
+++ /dev/null
@@ -1,135 +0,0 @@
-import re
-
-
-class PacketCommentPolicy():
- """The PacketCommentPolicy class handles logic to format comments
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def getComment(self, data, packetTypeId):
- """Returns the packet comment
-
- Args:
- data (dict): Raw packet data
- packetTypeId (int): Packet type id
-
- Returns:
- String
- """
- comment = None
- if (packetTypeId == 7 and "message_text" in data):
- # We save messages as a comment (a message packet does not have a comment so this column is free)
- comment = data["message_text"]
- elif (packetTypeId == 10 and "status" in data):
- # We save status as comment (a status message does not have a comment so this column is free)
- comment = data["status"]
- elif ("comment" in data):
- comment = data["comment"]
-
- if isinstance(comment, bytes):
- comment = comment.encode('ascii', 'ignore')
- comment = comment.replace('\x00', '')
-
- return self._formatComment(comment)
-
- def _formatComment(self, comment):
- """Remove junk from comment
-
- Args:
- comment (string): Comment from packet
-
- Returns:
- String
- """
- comment = self._lchop(comment, "!=")
- comment = self._rchop(comment, "!=")
- comment = self._lchop(comment, "]=")
- comment = self._rchop(comment, "]=")
- comment = self._lchop(comment, ">=")
- comment = self._rchop(comment, ">=")
- comment = self._lchop(comment, "_%")
- comment = self._rchop(comment, "_%")
- comment = self._lchop(comment, "_#")
- comment = self._rchop(comment, "_#")
- comment = self._lchop(comment, "_\"")
- comment = self._rchop(comment, "_\"")
- comment = self._lchop(comment, "_$")
- comment = self._rchop(comment, "_$")
- comment = self._lchop(comment, "_)")
- comment = self._rchop(comment, "_)")
- comment = self._lchop(comment, "_(")
- comment = self._rchop(comment, "_(")
- comment = self._lchop(comment, "()")
- comment = self._rchop(comment, "()")
- comment = self._lchop(comment, "^")
- comment = self._rchop(comment, "^")
- comment = self._lchop(comment, "\\x")
- comment = self._rchop(comment, "\\x")
- comment = self._lchop(comment, "/")
- comment = self._rchop(comment, "/")
- comment = self._lchop(comment, "\\!")
- comment = self._rchop(comment, "\\!")
- comment = self._lchop(comment, "1}")
- comment = self._rchop(comment, "1}")
- comment = self._lchop(comment, "_1")
- comment = self._rchop(comment, "_1")
- comment = self._lchop(comment, "\"(}")
- comment = self._rchop(comment, "\"(}")
- comment = self._rchop(comment, "=")
- comment = self._lchop(comment, "]")
- comment = self._lchopRegex(comment, "\.\.\.\/\d\d\d")
- comment = self._lchopRegex(comment, "\d\d\d\/\d\d\d")
- comment = self._lchop(comment, ".../...")
-
- if (comment is not None and len(comment) <= 1):
- # Comments with one letter is probably wrong
- comment = None
- return comment
-
- def _rchop(self, string, substr):
- """Chops substr from right of string
-
- Args:
- string (str): String to do modification on
- substr (str): Substr to look for in string
-
- Returns:
- Updated version of string
- """
- if (string is not None and string.endswith(substr)):
- return string[:-len(substr)]
- return string
-
- def _lchop(self, string, substr):
- """Chops substr from left of string
-
- Args:
- string (str): String to do modification on
- substr (str): Substr to look for in string
-
- Returns:
- Updated version of string
- """
- if (string is not None and string.startswith(substr)):
- return string[len(substr):]
- return string
-
- def _lchopRegex(self, string, substrRegex):
- """Chops substr from left of string
-
- Args:
- string (str): String to do modification on
- substrRegex (str): Substr to look for in string
-
- Returns:
- Updated version of string
- """
- regex = re.compile(substrRegex)
- if (string is not None):
- m = re.match(regex, string)
- if (m):
- return string[len(m.group(0)):]
- return string
diff --git a/server/trackdirect/parser/policies/PacketDuplicatePolicy.py b/server/trackdirect/parser/policies/PacketDuplicatePolicy.py
deleted file mode 100644
index 4e3c084e845840423a68130d8712a46f96f3ccdd..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketDuplicatePolicy.py
+++ /dev/null
@@ -1,139 +0,0 @@
-import logging
-from twisted.python import log
-
-import collections
-from trackdirect.exceptions.TrackDirectParseError import TrackDirectParseError
-
-
-class PacketDuplicatePolicy():
- """Handles duplicate checks
- """
-
- # static class variables
- latestPacketsHashOrderedDict = collections.OrderedDict()
-
- def __init__(self, stationRepository):
- """The __init__ method.
- """
- self.minutesBackToLookForDuplicates = 30
- self.stationRepository = stationRepository
-
- self.logger = logging.getLogger('trackdirect')
-
- def isDuplicate(self, packet):
- """Method used to check if this packet is a duplicate
-
- Args:
- packet (Packet): Packet that may be a duplicate
-
- Returns:
- Boolean
- """
- if (packet.mapId in [1, 5, 7, 8, 9]
- and (packet.isMoving == 1 or packet.mapId == 8)
- and packet.latitude is not None
- and packet.longitude is not None):
- if (self._isPacketBodyInCache(packet)):
- # It looks like a duplicate, treat it as one if needed
- # (if position is equal to the latest confirmed position it doesn't matter if we treat it as a duplicate or not)
- if (self._isToBeTreateAsDuplicate(packet)):
- return True
- self._addToCache(packet)
-
- elif (packet.sourceId == 3):
- # It is a duplicate (everything from this source is)
- return True
-
- return False
-
- def _isPacketBodyInCache(self, packet):
- """Returns true if packet body is in cache
-
- Args:
- packet (Packet): Packet look for in cashe
-
- Returns:
- Boolean
- """
- packetHash = self._getPacketHash(packet)
- if (packetHash is None):
- return False
-
- if (packetHash in PacketDuplicatePolicy.latestPacketsHashOrderedDict):
- prevPacketValues = PacketDuplicatePolicy.latestPacketsHashOrderedDict[packetHash]
- if (packet.rawPath != prevPacketValues['path']
- and prevPacketValues['timestamp'] > packet.timestamp - (60*self.minutesBackToLookForDuplicates)):
- return True
- return False
-
- def _isToBeTreateAsDuplicate(self, packet):
- """Returns true if packet should be treated as duplicate
-
- Args:
- packet (Packet): Packet to check
-
- Returns:
- Boolean
- """
- station = self.stationRepository.getObjectById(packet.stationId)
- if (station.latestConfirmedLatitude is not None and station.latestConfirmedLongitude is not None):
- stationLatCmp = int(round(station.latestConfirmedLatitude*100000))
- stationLngCmp = int(round(station.latestConfirmedLongitude*100000))
- else:
- stationLatCmp = 0
- stationLngCmp = 0
-
- packetlatCmp = int(round(packet.latitude*100000))
- packetlngCmp = int(round(packet.longitude*100000))
-
- if (station.isExistingObject()
- and stationLatCmp != 0
- and stationLngCmp != 0
- and (packet.mapId == 8 or stationLatCmp != packetlatCmp or stationLngCmp != packetlngCmp)):
-
- # We treat this packet as a duplicate
- return True
- else:
- return False
-
- def _getPacketHash(self, packet):
- """Returns a hash value of the Packet object
-
- Args:
- packet (Packet): Packet to get hash for
-
- Returns:
- A string that contains the hash value
- """
- if (packet.raw is None or packet.raw == ''):
- return None
-
- packetString = packet.raw.split(':', 1)[1]
- if (packetString == ''):
- return None
- else:
- return hash(packetString.strip())
-
- def _addToCache(self, packet):
- """Add packet to cache
-
- Args:
- packet (Packet): Packet to add to cache
- """
- packetHash = self._getPacketHash(packet)
- PacketDuplicatePolicy.latestPacketsHashOrderedDict[packetHash] = {
- 'path': packet.rawPath,
- 'timestamp': packet.timestamp
- }
- self._cacheMaintenance()
-
- def _cacheMaintenance(self):
- """Make sure cache does not contain to many packets
- """
- maxNumberOfPackets = self.minutesBackToLookForDuplicates * 60 * 100 # We assume that we have an average of 100 packets per second
- if (len(PacketDuplicatePolicy.latestPacketsHashOrderedDict) > maxNumberOfPackets):
- try:
- PacketDuplicatePolicy.latestPacketsHashOrderedDict.popitem(
- last=False)
- except (KeyError, StopIteration) as e:
- pass
diff --git a/server/trackdirect/parser/policies/PacketKillCharPolicy.py b/server/trackdirect/parser/policies/PacketKillCharPolicy.py
deleted file mode 100644
index 3b03ccfaf601165d69b880c686ea6711c787d911..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketKillCharPolicy.py
+++ /dev/null
@@ -1,23 +0,0 @@
-class PacketKillCharPolicy():
- """The PacketKillCharPolicy class handles logic related to packet kill character
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def hasKillCharacter(self, data):
- """A packet may contain a kill char, if exists the object/item should be hidden on map
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- Boolean
- """
- if ("object_name" in data
- and data["object_name"] is not None
- and data["object_name"] != ''
- and data["object_name"].endswith('_')):
- return True
- return False
diff --git a/server/trackdirect/parser/policies/PacketMapIdPolicy.py b/server/trackdirect/parser/policies/PacketMapIdPolicy.py
deleted file mode 100644
index 3f87d38aae5b2a03c5604d73243312d70504e421..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketMapIdPolicy.py
+++ /dev/null
@@ -1,278 +0,0 @@
-from trackdirect.parser.policies.PacketOrderPolicy import PacketOrderPolicy
-from trackdirect.parser.policies.PacketMaxSpeedPolicy import PacketMaxSpeedPolicy
-
-
-class PacketMapIdPolicy():
- """PacketMapIdPolicy tries to find the best mapId for the current packet
- """
-
- def __init__(self, packet, prevPacket):
- """The __init__ method.
-
- Args:
- packet (Packet): Packet that we want analyze
- """
- self.packet = packet
- self.prevPacket = prevPacket
- self.hasKillCharacter = False
- # Marker will be confirmed when we receive the third packet
- self.markerCounterConfirmLimit = 3
-
- # Results
- self.mapId = None
- self.markerId = None
- self.isReplacingPrevPacket = False
- self.isConfirmingPrevPacket = False
- self.isKillingPrevPacket = False
-
- def enableHavingKillCharacter(self):
- """Treat this packet as having a kill character
- """
- self.hasKillCharacter = True
-
- def getMapId(self):
- """Returns the map id that corresponds to the found marker id
-
- Returns:
- int
- """
- self._findMapId()
- return self.mapId
-
- def getMarkerId(self):
- """Returns the found marker id
-
- Returns:
- int
- """
- self._findMapId()
- return self.markerId
-
- def isReplacingPreviousPacket(self):
- """Returns true if packet replaces previous packet
-
- Returns:
- boolean
- """
- self._findMapId()
- return self.isReplacingPrevPacket
-
- def isConfirmingPreviousPacket(self):
- """Returns true if packet confirmes previous packet
-
- Returns:
- boolean
- """
- self._findMapId()
- return self.isConfirmingPrevPacket
-
- def isKillingPreviousPacket(self):
- """Returns true if packet kills previous packet
-
- Returns:
- boolean
- """
- self._findMapId()
- return self.isKillingPrevPacket
-
- def _findMapId(self):
- """Find a suitable marker id for the current packet and set correponding attribute (and related attributes)
- """
- if (self.mapId is None):
- packetOrderPolicy = PacketOrderPolicy()
- if (self.packet.sourceId == 2 and len(self.packet.stationIdPath) > 0):
- # A CWOP-station is allways sending directly
- self.mapId = 16
- self.markerId = 1
- elif (not self._isPacketOnMap()):
- self.mapId = 10
- self.markerId = 1
- elif (packetOrderPolicy.isPacketInWrongOrder(self.packet, self.prevPacket)):
- self.mapId = 6
- self.markerId = 1
- elif (self._isFaultyGpsPosition()):
- self._findMapIdForFaultyGpsPosition()
- elif (self.packet.isMoving == 1):
- self._findMapIdForMovingStation()
- else:
- self._findMapIdForStationaryStation()
-
- def _isPacketOnMap(self):
- """Returns true if current packet will be on map
-
- Returns:
- boolean
- """
- if (self.packet.latitude is not None
- and self.packet.longitude is not None
- and type(self.packet.latitude) == float
- and type(self.packet.longitude) == float
- and self.packet.sourceId != 3
- and self.packet.mapId in [1, 5, 7, 9]):
- return True
- else:
- return False
-
- def _findMapIdForStationaryStation(self):
- """Find a suitable marker id for the current packet (assumes it is a stationary station) and set correponding attribute (and related attributes)
- """
- if (self.prevPacket.isExistingObject()
- and self.packet.isPostitionEqual(self.prevPacket)
- and self.packet.isSymbolEqual(self.prevPacket)
- and self.packet.isMoving == self.prevPacket.isMoving
- and self.prevPacket.mapId in [1, 7]):
- # Same position and same symbol
- self.mapId = 1
- self.markerId = self.prevPacket.markerId
- if (self.hasKillCharacter):
- # This station we can actually kill (it's stationary), let the markerId be
- self.mapId = 14
-
- # Also mark this to replace previous packet
- self.isReplacingPrevPacket = True
- elif (self.hasKillCharacter):
- # We found nothing to kill
- self.markerId = 1
- self.mapId = 4
- else:
- # Seems to be a new stationary station (or at least a new symbol for an existing station)
- self.mapId = 1
- self.markerId = None
-
- def _findMapIdForMovingStation(self):
- """Find a suitable marker id for the current packet (assumes it is a moving station) and set correponding attribute (and related attributes)
- """
- if (self.hasKillCharacter):
- # Makes no sense in handling kill characters for moving
- self.mapId = 4
- self.markerId = 1
-
- elif (self.prevPacket.isExistingObject()
- and self.prevPacket.isMoving == 1
- and self.prevPacket.mapId in [1, 7]):
- calculatedDistance = self.packet.getDistance(
- self.prevPacket.latitude, self.prevPacket.longitude)
- calculatedSpeed = self.packet.getCalculatedSpeed(self.prevPacket)
- packetMaxSpeedPolicy = PacketMaxSpeedPolicy()
- maxSpeed = packetMaxSpeedPolicy.getMaxLikelySpeed(
- self.packet, self.prevPacket)
- # distance is likely if distance is shorter than 50km (map performance is bad with to long polylines)
- absoluteMaxDistance = 50000
- # speed may be likely but if it is faster than absoluteMaxSpeed we create a new marker any way
- absoluteMaxSpeed = 2000
-
- if (self.packet.isPostitionEqual(self.prevPacket)):
- # Same position
- self._findMapIdForMovingStationWithSamePosition()
-
- elif (calculatedDistance < 5000 and calculatedSpeed <= absoluteMaxSpeed):
- # Distance is very short (shorter than 5km)
- self._findMapIdForMovingStationWithLikelySpeed()
-
- elif (calculatedSpeed <= maxSpeed and calculatedSpeed <= absoluteMaxSpeed and calculatedDistance <= absoluteMaxDistance):
- # Speed and distance is likely
- self._findMapIdForMovingStationWithLikelySpeed()
-
- elif (calculatedSpeed <= maxSpeed and calculatedDistance > absoluteMaxDistance):
- # Speed is likly but distance is to long or speed is very fast
- self._findMapIdForMovingStationWithToLongDistance()
-
- else:
- # No suitable marker id
- self.mapId = 7
- self.markerId = None
- else:
- if (self.prevPacket.isExistingObject()
- and self.prevPacket.isMoving == 0
- and self.packet.isSymbolEqual(self.prevPacket)):
- # We previously made a mistake, previous packet should have been marked as moving, just mark previous as abnormal (ghost marker)
- self.isKillingPrevPacket = True
-
- # Seems to be a new station
- self.mapId = 1
- self.markerId = None
-
- def _findMapIdForMovingStationWithToLongDistance(self):
- """Sets a suitable marker id for the current packet based on prevPacket and assumes that distance is to long between them
- """
- if (self.prevPacket.markerCounter == 1):
- # Previous packet is not related to any previous and it is not related to this, mark it as abnormal
- self.isKillingPrevPacket = True
-
- # This is kind of a special case, we have no requirements on the previous packet
- # Station is either sending few packets or is moving very fast, we accept everything as long as speed is likely
- # Create new marker
- self.mapId = 1
- self.markerId = None
-
- def _findMapIdForMovingStationWithLikelySpeed(self):
- """Sets a suitable marker id for the current packet based on prevPacket and assumes that speed is likly
- """
- self.markerId = self.prevPacket.markerId
- if (self.prevPacket.mapId == 1
- or (self.prevPacket.markerCounter + 1) >= self.markerCounterConfirmLimit):
- self.mapId = 1
- else:
- self.mapId = self.prevPacket.mapId
-
- if (self.mapId == 1
- and self.prevPacket.mapId == 7):
- # To mark a previous packet as confirmed is not important since client should handle it anyway when a connected packet that is confirmed is recived
- # But we do it when possible to make things easier for the client (currently we are not doiong it if several previous packets is unconfirmed)
- self.isConfirmingPrevPacket = True
-
- def _findMapIdForMovingStationWithSamePosition(self):
- """Sets a suitable marker id for the current packet based on prevPacket and assumes that position is equal
- """
- # Also mark this to replace previous packet
- # If this packet is converted to a 12 it will be treated as confirmed in history
- # (we kind of assumes that markerCounterConfirmLimit == 2, maybe a TODO?)
- self.markerId = self.prevPacket.markerId
- self.isReplacingPrevPacket = True
- if (self.prevPacket.mapId == 1
- or (self.prevPacket.markerCounter + 1) >= self.markerCounterConfirmLimit):
- self.mapId = 1
- else:
- self.mapId = self.prevPacket.mapId
-
- def _findMapIdForFaultyGpsPosition(self):
- """Sets a suitable marker id for the current packet based on prevPacket and assumes that gps position is faulty (mapId 5)
- """
- if (self.hasKillCharacter):
- # No point in killing a ghost-marker
- self.mapId = 4
- self.markerId = 1
- elif (self.prevPacket.mapId == self.mapId
- and self.packet.isPostitionEqual(self.prevPacket)
- and self.packet.isSymbolEqual(self.prevPacket)):
- # Same mapId and position and same symbol
- # Also mark this to replace previous packet
- self.isReplacingPrevPacket = True
- self.mapId = 5 # it is still 5
- self.markerId = self.prevPacket.markerId
- else:
- # Seems to be a new stationary station (or at least a new symbol for an existing station)
- self.mapId = 5
- self.markerId = None
-
- def _isFaultyGpsPosition(self):
- """Parse the packet and modify the mapId attribute if position is faulty
- """
- packetlatCmp = int(round(self.packet.latitude*100000))
- packetlngCmp = int(round(self.packet.longitude*100000))
-
- if (packetlatCmp == int(0) and packetlngCmp == int(0)):
- return True
-
- if (packetlatCmp == int(1*100000) and packetlngCmp == int(1*100000)):
- return True
-
- if (packetlatCmp == int(36*100000) and packetlngCmp == int(136*100000)):
- # Some gps units seems to use this position as default until they find the real position
- # Maybe it is the position of a gps manufacturer?
- return True
-
- if (packetlatCmp == int(-48*100000) and packetlngCmp == int(0)):
- # Some gps units seems to use this position as default until they find the real position
- return True
- return False
diff --git a/server/trackdirect/parser/policies/PacketMaxSpeedPolicy.py b/server/trackdirect/parser/policies/PacketMaxSpeedPolicy.py
deleted file mode 100644
index 991c2f61d52592c013e27bc1592901623638c554..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketMaxSpeedPolicy.py
+++ /dev/null
@@ -1,79 +0,0 @@
-from trackdirect.parser.policies.PacketSpeedComputablePolicy import PacketSpeedComputablePolicy
-
-
-class PacketMaxSpeedPolicy():
- """PacketMaxSpeedPolicy handles logic related to max possible speed (used to filter out faulty packets)
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def getMaxLikelySpeed(self, packet, prevPacket):
- """Returns the max likely speed
-
- Args:
- packet (Packet): Packet that we want analyze
- prevPacket (Packet): Previous related packet for the same station
-
- Returns:
- Max likly speed as float
- """
- maxSpeed = self._getDefaultStationMaxSpeed(packet)
-
- if (packet.speed is not None and packet.speed > maxSpeed):
- # We allow 100% faster speed than the reported speed
- maxSpeed = packet.speed * 2
-
- if (prevPacket.isExistingObject()
- and prevPacket.speed is not None
- and prevPacket.speed > maxSpeed):
- # We allow 100% faster speed than the previous reported speed
- maxSpeed = prevPacket.speed * 2
-
- calculatedSpeed = 0
- if (prevPacket.isExistingObject()):
- calculatedSpeed = packet.getCalculatedSpeed(prevPacket)
- packetSpeedComputablePolicy = PacketSpeedComputablePolicy()
- if (packetSpeedComputablePolicy.isSpeedComputable(packet, prevPacket)
- and prevPacket.mapId == 7
- and calculatedSpeed > maxSpeed):
- # If last position is unconfirmed but still is closer to the last confirmed and calculated speed is trusted we accept that speed
- # This part is IMPORTANT to avoid that all packets get map_id == 7
- maxSpeed = calculatedSpeed
-
- maxSpeed = (maxSpeed * (1 + len(packet.stationIdPath)))
- return maxSpeed
-
- def _getDefaultStationMaxSpeed(self, packet):
- """Returns the station default max speed (not affected by or adaptive speed limit)
-
- Args:
- packet (Packet): Packet that we want analyze
-
- Returns:
- Returns the station default max speed as int
- """
- # Bugatti Veyron Super Sport Record Edition 2010, the fastest production car can do 431 kmh (but a regular car usually drives a bit slower...)
- maxSpeed = 200
- if (packet.altitude is not None):
- highestLandAltitude = 5767 # Uturuncu, Bolivia, highest road altitude
- airPlaneMaxAltitude = 15240 # Very rare that airplanes go higher than 50.000 feet
- # Objects below approximately 160 kilometers (99 mi) will experience very rapid orbital decay and altitude loss.
- satelliteMinAltitude = 160000
-
- if (packet.altitude > satelliteMinAltitude):
- # Seems like this is an satellite
- # Until we know more we dont change anything
- maxSpeed = maxSpeed
-
- elif (packet.altitude > airPlaneMaxAltitude):
- # Higher than a normal airplane but not a satellite, could be a high altitude ballon
- maxSpeed = 50
-
- elif (packet.altitude > highestLandAltitude):
- # Seems like this is a airplane or a ballon
- # 394 kmh is the ground speed record for a hot air ballon
- # 950 kmh is a common upper crouse speed for regular airplanes
- maxSpeed = 950
- return maxSpeed
diff --git a/server/trackdirect/parser/policies/PacketOgnDataPolicy.py b/server/trackdirect/parser/policies/PacketOgnDataPolicy.py
deleted file mode 100644
index 7029bbec98d76b03fa37c617a3f5714bc6b73ca4..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketOgnDataPolicy.py
+++ /dev/null
@@ -1,242 +0,0 @@
-import logging
-from twisted.python import log
-
-from trackdirect.parser.policies.AprsPacketSymbolPolicy import AprsPacketSymbolPolicy
-from trackdirect.parser.policies.PacketPathTcpPolicy import PacketPathTcpPolicy
-
-
-class PacketOgnDataPolicy():
- """PacketOgnDataPolicy can answer questions about OGN data in the packet
- """
-
- def __init__(self, data, ognDeviceRepository, sourceId):
- """The __init__ method.
-
- Args:
- data (dict): Raw packet data
- ognDeviceRepository (OgnDeviceRepository): OgnDeviceRepository instance
- sourceId (int): Source Id
- """
- self.data = data
- self.ognDeviceRepository = ognDeviceRepository
-
- self.logger = logging.getLogger('trackdirect')
-
- self.isOgnPositionPacket = self.isOgnPositionPacket(sourceId)
- self.isAllowedToTrack = True
- self.isAllowedToIdentify = True
-
- self.result = {}
- self._parse()
-
- def getOgnData(self):
- """Returnes raw OGN data
-
- Returns:
- Dict of OGN data
- """
- return self.result
-
- def isOgnPositionPacket(self, sourceId):
- """Returnes true if packet is a OGN Position packet
-
- Args:
- sourceId (int): Source Id
-
- Returns:
- Boolean
- """
- if (sourceId == 5):
- if ("comment" in self.data
- and self.data["comment"] is not None
- and len(self.data["comment"].strip()) > 10
- and self.data["comment"].strip().startswith("id")):
- return True
-
- symbol = self.data['symbol'] if ('symbol' in self.data) else None
- symbolTable = self.data['symbol_table'] if (
- 'symbol_table' in self.data) else None
- aprsPacketSymbolPolicy = AprsPacketSymbolPolicy()
- if (aprsPacketSymbolPolicy.isMaybeMovingSymbol(symbol, symbolTable)):
- return True
- else:
- if ("comment" in self.data
- and self.data["comment"] is not None
- and len(self.data["comment"].strip()) > 10
- and self.data["comment"].strip().startswith("id")
- and "fpm " in self.data["comment"] + " "
- and "rot " in self.data["comment"] + " "
- and "dB " in self.data["comment"] + " "):
- return True
- return False
-
- def _parse(self):
- """Parse the OGN data in packet
- """
- if (not self.isOgnPositionPacket):
- self.result = None
- else:
- packetPathTcpPolicy = PacketPathTcpPolicy(self.data['path'])
- if (not packetPathTcpPolicy.isSentByTCP()):
- self.isAllowedToIdentify = False
-
- if ("comment" in self.data and self.data["comment"] is not None):
- ognParts = self.data["comment"].split()
- for part in ognParts:
- if (part.startswith('id')):
- part = part.replace("-", "")
- self._parseSenderAddress(part)
- self._parseSenderDetails(part)
-
- elif (part.endswith('fpm')):
- self._parseClimbRate(part)
-
- elif (part.endswith('rot')):
- self._parseTurnRate(part)
-
- elif (part.endswith('dB')):
- if (self.isAllowedToIdentify and self.isAllowedToTrack):
- self._parseSignalToNoiseRatio(part)
-
- elif (part.endswith('e')):
- if (self.isAllowedToIdentify and self.isAllowedToTrack):
- self._parseBitErrorsCorrected(part)
-
- elif (part.endswith('kHz')):
- if (self.isAllowedToIdentify and self.isAllowedToTrack):
- self._parseFrequencyOffset(part)
- if (not self.isAllowedToTrack):
- return
-
- if (not self.isAllowedToIdentify):
- if ('ogn_sender_address' in self.result):
- self.result['ogn_sender_address'] = None
-
- def _parseSenderAddress(self, content):
- """Parse th OGN sender address
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_sender_address' not in self.result):
- self.isAllowedToIdentify = True
- self.result['ogn_sender_address'] = content[4:10].strip()
-
- ognDevice = self.ognDeviceRepository.getObjectByDeviceId(
- self.result['ogn_sender_address'])
- if (ognDevice.isExistingObject() and not ognDevice.tracked):
- # Pilot do not want to be tracked, so we skip saving the packet
- self.isAllowedToIdentify = False
- self.isAllowedToTrack = False
-
- elif (self.result['ogn_sender_address'] == 'ICAFFFFFF'):
- # The Device ID ICAFFFFFF is used by several aircrafts, we can not know what to do with them...
- self.isAllowedToIdentify = False
- self.isAllowedToTrack = False
-
- elif (not ognDevice.isExistingObject() or not ognDevice.identified):
- # Pilot has not approved to show identifiable data, so we make up a random station name and clear all identifiable data
- self.isAllowedToIdentify = False
- else:
- self.isAllowedToIdentify = False
-
- def _parseSenderDetails(self, content):
- """Parse OGN aircraft type and OGN address type
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_aircraft_type_id' not in self.result):
- try:
- ognSenderDetailsHex = content[2:4]
- ognSenderDetailsBinary = bin(
- int(ognSenderDetailsHex, 16))[2:].zfill(8)
-
- stealth = ognSenderDetailsBinary[0:1]
- noTracking = ognSenderDetailsBinary[1:2]
- ognAircraftTypeIdBinary = ognSenderDetailsBinary[2:6]
- ognAddressTypeIdBinary = ognSenderDetailsBinary[6:8]
-
- self.result['ogn_aircraft_type_id'] = int(
- ognAircraftTypeIdBinary, 2)
- if (self.result['ogn_aircraft_type_id'] == 0 or self.result['ogn_aircraft_type_id'] > 15):
- self.result['ogn_aircraft_type_id'] = None
-
- self.result['ogn_address_type_id'] = int(
- ognAddressTypeIdBinary, 2)
- if (self.result['ogn_address_type_id'] == 0 or self.result['ogn_address_type_id'] > 4):
- self.result['ogn_address_type_id'] = None
-
- except ValueError:
- # Assume that we should track this aircraft (we should not receive packets that has the noTracking or stealth flag set)
- noTracking = '0'
- stealth = '0'
-
- if (stealth == '1' or noTracking == '1'):
- self.isAllowedToIdentify = False
- self.isAllowedToTrack = False
-
- def _parseClimbRate(self, content):
- """Parse OGN climb rate
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_climb_rate' not in self.result and content.endswith('fpm')):
- content = content.replace("fpm", "")
- try:
- self.result['ogn_climb_rate'] = int(content)
- except ValueError:
- pass
-
- def _parseTurnRate(self, content):
- """Parse OGN turn rate
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_turn_rate' not in self.result and content.endswith('rot')):
- content = content.replace("rot", "")
- try:
- self.result['ogn_turn_rate'] = float(content)
- except ValueError:
- pass
-
- def _parseSignalToNoiseRatio(self, content):
- """Parse OGN SNR
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_signal_to_noise_ratio' not in self.result and content.endswith('dB')):
- content = content.replace("dB", "")
- try:
- self.result['ogn_signal_to_noise_ratio'] = float(content)
- except ValueError:
- pass
-
- def _parseBitErrorsCorrected(self, content):
- """Parse OGN number of bit errors corrected in the packet upon reception
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_bit_errors_corrected' not in self.result and content.endswith('e')):
- content = content.replace("e", "")
- try:
- self.result['ogn_bit_errors_corrected'] = int(content)
- except ValueError:
- pass
-
- def _parseFrequencyOffset(self, content):
- """Parse OGN frequency offset measured upon reception
-
- Arguments:
- content (string) : String that contains information to parse
- """
- if ('ogn_frequency_offset' not in self.result and content.endswith('kHz')):
- content = content.replace("kHz", "")
- try:
- self.result['ogn_frequency_offset'] = float(content)
- except ValueError:
- pass
diff --git a/server/trackdirect/parser/policies/PacketOrderPolicy.py b/server/trackdirect/parser/policies/PacketOrderPolicy.py
deleted file mode 100644
index 0ab847dbc69e900c3be68287feb5d9478ee1c6f7..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketOrderPolicy.py
+++ /dev/null
@@ -1,34 +0,0 @@
-class PacketOrderPolicy():
- """PacketOrderPolicy handles logic related to packet receive order
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def isPacketInWrongOrder(self, packet, previousPacket):
- """Checks if current packet is received in the wrong order compared to the previous specified packet
-
- Note:
- We only care for packets in wrong order if station is moving
-
- Args:
- packet (Packet): Packet that we want analyze
- previousPacket (Packet): Packet objekt that represents the previous packet for this station
-
- Returns:
- True if this packet is received in the wrong order otherwise false
- """
- if (previousPacket is not None
- and previousPacket.isExistingObject()):
- if (previousPacket.reportedTimestamp is not None
- and packet.reportedTimestamp is not None
- and previousPacket.reportedTimestamp != 0
- and previousPacket.senderId == packet.senderId
- and packet.reportedTimestamp != 0
- and previousPacket.isMoving == 1
- and previousPacket.reportedTimestamp < (packet.timestamp + 60*60*24)
- and packet.reportedTimestamp < (packet.timestamp + 60*60*24)
- and previousPacket.reportedTimestamp > packet.reportedTimestamp):
- return True
- return False
diff --git a/server/trackdirect/parser/policies/PacketPathPolicy.py b/server/trackdirect/parser/policies/PacketPathPolicy.py
deleted file mode 100644
index f1195cf3bda6fa73d32c987c779ad0a9262a7b62..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketPathPolicy.py
+++ /dev/null
@@ -1,263 +0,0 @@
-import collections
-import re
-
-from trackdirect.exceptions.TrackDirectMissingStationError import TrackDirectMissingStationError
-from trackdirect.parser.policies.PacketPathTcpPolicy import PacketPathTcpPolicy
-
-
-class PacketPathPolicy():
- """PacketPathPolicy handles logic to generate the path for a specified packet
- """
-
- def __init__(self, path, sourceId, stationRepository, senderRepository):
- """The __init__ method.
-
- Args:
- path (list): Raw packet path list
- sourceId (int): Packet source id
- stationRepository (StationRepository): StationRepository instance
- senderRepository (SenderRepository): SenderRepository instance
- """
- self.path = path
- self.sourceId = sourceId
- self.stationRepository = stationRepository
- self.senderRepository = senderRepository
-
- self.stationIdPath = []
- self.stationNamePath = []
- self.stationLocationPath = []
- self._parsePath()
-
- def getStationIdPath(self):
- """Returns station id path
-
- Returns:
- list
- """
- return self.stationIdPath
-
- def getStationNamePath(self):
- """Returns station name path
-
- Returns:
- list
- """
- return self.stationNamePath
-
- def getStationLocationPath(self):
- """Returns station location path, a list of longitude and latitude values
-
- Returns:
- list
- """
- return self.stationLocationPath
-
- def _parsePath(self):
- """Parse Station path
-
- Note:
- Include station in path if
- - Station name is after q-code (this is the I-gate)
- - Station name is before unused path command and a used command exists after (this is a digipeater that has inserted itself into the path)
- - As a precaution we also include stations where name has a * after it (no matter the position in path)
- """
- isQCodeFound = False
- isNonUsedPathCommandFound = False
- packetPathTcpPolicy = PacketPathTcpPolicy(self.path)
- if (packetPathTcpPolicy.isSentByTCP()):
- return
-
- i = 0
- while i < len(self.path):
- index = i
- i += 1
- name = self.path[index]
-
- if (isinstance(name, int)):
- name = str(name)
-
- if (self._isQCode(name)):
- isQCodeFound = True
- continue
-
- if (self._isPathCommand(name)):
- if (not self._isUsedPathCommand(name)):
- isNonUsedPathCommandFound = True
- continue
-
- pathStationName = name.replace('*', '')
- if (not self._isStationNameValid(pathStationName)):
- continue
-
- if (isQCodeFound
- or name.find('*') >= 0
- or not isNonUsedPathCommandFound):
- self._addStationToPath(pathStationName)
-
- def _addStationToPath(self, name):
- """Returns true if specified string is a Q code
-
- Args:
- name (string): station
- """
- try:
- station = self.stationRepository.getCachedObjectByName(
- name, self.sourceId)
- stationId = station.id
-
- if (stationId not in self.stationIdPath):
- location = self._getStationLatestLocation(stationId)
- if (location is not None):
- self.stationNamePath.append(name)
- self.stationIdPath.append(stationId)
- self.stationLocationPath.append(location)
- except (TrackDirectMissingStationError) as exp:
- pass
-
- def _isQCode(self, value):
- """Returns true if specified string is a Q code
-
- Args:
- value (string): value
-
- Returns:
- Returns true if specified string is a Q code otherwise false
- """
- if (value.upper().find('QA') == 0 and len(value) == 3):
- return True
- else:
- return False
-
- def _isStationNameValid(self, name):
- """Returns true if specified station name is valid. This method is used to filter out common station names that is not valid.
-
- Args:
- name (string): Station name
-
- Returns:
- Returns true if specified station name is valid otherwise false
- """
- if (name.find('NONE') == 0):
- return False
- elif (name.find('0') == 0 and len(name) == 1):
- return False
- elif (name.find('1') == 0 and len(name) == 1):
- return False
- elif (name.find('2') == 0 and len(name) == 1):
- return False
- elif (name.find('3') == 0 and len(name) == 1):
- return False
- elif (name.find('4') == 0 and len(name) == 1):
- return False
- elif (name.find('5') == 0 and len(name) == 1):
- return False
- elif (name.find('6') == 0 and len(name) == 1):
- return False
- elif (name.find('7') == 0 and len(name) == 1):
- return False
- elif (name.find('8') == 0 and len(name) == 1):
- return False
- elif (name.find('9') == 0 and len(name) == 1):
- return False
- elif (name.find('APRS') == 0 and len(name) == 4):
- return False
- elif (name.find('1-1') == 0 and len(name) == 3):
- return False
- elif (name.find('2-1') == 0 and len(name) == 3):
- return False
- elif (name.find('2-2') == 0 and len(name) == 3):
- return False
- elif (name.find('3-1') == 0 and len(name) == 3):
- return False
- elif (name.find('3-2') == 0 and len(name) == 3):
- return False
- elif (name.find('3-3') == 0 and len(name) == 3):
- return False
- elif (name.find('4-1') == 0 and len(name) == 3):
- return False
- elif (name.find('4-2') == 0 and len(name) == 3):
- return False
- elif (name.find('4-3') == 0 and len(name) == 3):
- return False
- elif (name.find('4-4') == 0 and len(name) == 3):
- return False
- elif (name.find('DSTAR') == 0):
- return False
- elif (name.find('TCP') == 0):
- return False
- elif (name.find('NULL') == 0):
- return False
- elif (name.find('LOCAL') == 0):
- return False
- elif (name.find('GATE') == 0):
- return False
- elif (name.find('DIRECT') == 0 and len(name) == 6):
- return False
- elif (name.find('CWOP') == 0 and len(name) == 6):
- return False
- elif (name.find('DMR') == 0 and len(name) == 3):
- return False
- elif (name.find('ECHO') == 0 and len(name) == 4):
- return False
- elif (name.find('OR1-') == 0):
- return False
- elif (name.find('OR2-') == 0):
- return False
-
- else:
- return True
-
- def _isPathCommand(self, value):
- """Returns true if specified value is a path command
-
- Args:
- value (string): value
-
- Returns:
- Returns true if specified value is a path command otherwise false
- """
- if (value.find('WIDE') == 0):
- return True
- elif (value.find('RELAY') == 0):
- return True
- elif (value.find('TRACE') == 0):
- return True
- elif (value.find('RPN') == 0):
- return True
- else:
- return False
-
- def _isUsedPathCommand(self, value):
- """Returns true if specified value is a path command and it is completly used
-
- Args:
- value (string): value
-
- Returns:
- Returns true if specified value is a path command (and it is completly used) otherwise false
- """
- if (value.find('*') >= 0):
- # If a star is added it means that the path command is completly used
- return True
-
- if (value.find('WIDE') == 0 or value.find('TRACE') == 0 or value.find('RPN') == 0):
- if (value.find('-') < 0):
- # if the wide/trace command still has a hyphen it means that it is not used up
- # Example: WIDE2-1 (can be used one more time), WIDE2 (can not be used any more)
- return True
- return False
-
- def _getStationLatestLocation(self, stationId):
- """Get latest location for at specified station
-
- Args:
- None
-
- Returns:
- Returns the location of the specified station as an array, first value is latitude, second is longitude
- """
- station = self.stationRepository.getObjectById(stationId)
- if (station.isExistingObject()):
- if (station.latestConfirmedLatitude is not None and station.latestConfirmedLongitude is not None):
- return [station.latestConfirmedLatitude, station.latestConfirmedLongitude]
- return None
diff --git a/server/trackdirect/parser/policies/PacketPathTcpPolicy.py b/server/trackdirect/parser/policies/PacketPathTcpPolicy.py
deleted file mode 100644
index 03b4f987da1d3caf0bc5c137e71c7f7ad23ab501..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketPathTcpPolicy.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import re
-
-
-class PacketPathTcpPolicy():
- """PacketPathTcpPolicy is used to figure out if packet is sent using radio or TCP
- """
-
- def __init__(self, path):
- """The __init__ method.
-
- Args:
- path (list): Raw packet path list
- """
- self.path = path
-
- def isSentByTCP(self):
- """Returns True if packet is sent through TCPIP
-
- Returns:
- True if packet is sent through TCPIP otherwise False
- """
- if (isinstance(self.path, list)):
- if len(self.path) >= 2 and (re.match(r"^TCPIP\*.*$", self.path[0]) or re.match(r"^TCPXX\*.*$", self.path[0])):
- # first station is TCP (this usually means it is sent over TCP...)
- return True
- if ('qAC' in self.path):
- # Packet was received from the client directly via a verified connection
- return True
- if ('qAX' in self.path):
- # Packet was received from the client directly via a unverified connection
- return True
- if ('qAU' in self.path):
- # Packet was received from the client directly via a UDP connection.
- return True
- return False
diff --git a/server/trackdirect/parser/policies/PacketRelatedMapSectorsPolicy.py b/server/trackdirect/parser/policies/PacketRelatedMapSectorsPolicy.py
deleted file mode 100644
index a0595ef225fc96df404aa4c14e2b93bfa3051007..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketRelatedMapSectorsPolicy.py
+++ /dev/null
@@ -1,133 +0,0 @@
-import time
-
-from trackdirect.parser.policies.MapSectorPolicy import MapSectorPolicy
-
-
-class PacketRelatedMapSectorsPolicy():
- """PacketRelatedMapSectorsPolicy handles logic related to map sectors for a packet
- """
-
- def __init__(self, packetRepository):
- """The __init__ method.
-
- Args:
- packetRepository (PacketRepository): PacketRepository instance
- """
- self.packetRepository = packetRepository
-
- def getAllRelatedMapSectors(self, packet, previousPacket):
- """Returns all related map sectors to current packet
-
- Note:
- A related map sector is a map-sector that is not the map sector of the current packet nor the previous packet,
- it is all the map-sectors in between the current packet and the previous packet.
-
- Args:
- packet (Packet): Packet that we want analyze
- previousPacket (Packet): Packet object that represents the previous packet for this station
-
- Returns:
- Returns any related map sectors (as an array)
- """
- if (not self._mayPacketHaveRelatedMapSectors(packet, previousPacket)):
- return []
-
- relatedMapSectors = []
- if (previousPacket.mapId == 7):
- # When previous packet is unconfirmed we need to add path between prev-prev-packet and prev-packet also
- minTimestamp = int(time.time()) - 86400 # 24 hours
- prevpreviousPacket = self.packetRepository.getLatestConfirmedMovingObjectByStationId(
- previousPacket.stationId, minTimestamp)
- if (prevpreviousPacket.isExistingObject() and prevpreviousPacket.markerCounter > 1):
- # We found a confirmed prev prev packet
- relatedMapSectors.extend(self._getRelatedMapSectors(
- previousPacket, prevpreviousPacket))
-
- relatedMapSectors.extend(
- self._getRelatedMapSectors(packet, previousPacket))
- return relatedMapSectors
-
- def _mayPacketHaveRelatedMapSectors(self, packet, previousPacket):
- """Returns true if packet may be related to other map sectors then the map sector it's in
-
- Args:
- packet (Packet): Packet that we want analyze
- previousPacket (Packet): Packet objekt that represents the previous packet for this station
-
- Returns:
- Returns true if packet may be related to other map sectors otherwise false
- """
- if (packet.isMoving == 1
- and previousPacket.isMoving == 1
- and packet.markerId != 1):
- # We only add related map-sectors to moving stations (that has a marker)
- if (packet.mapId == 1):
- # If new packet is not confirmed (mapId 7) we connect it with related map-sectors later
- if (previousPacket.markerCounter is not None and previousPacket.markerCounter > 1
- or packet.markerId == previousPacket.markerId):
- # We only add related map-sectors if previous packet has a marker with several connected packet
- # A packet with a marker that is not shared with anyone will be converted to a ghost-marker in client
- if (previousPacket.mapId == 1
- or packet.markerId == previousPacket.markerId):
- # If a previous packet has mapId = 7 (unconfirmed position),
- # and new packet has another marker,
- # then the previous marker is doomed to be a ghost-marker forever
- return True
- return False
-
- def _getRelatedMapSectors(self, packet1, packet2):
- """Get any related map sectors between specified packets
-
- Note:
- A related map sector is a map-sector that is not the map sector of the current packet nor the previous packet,
- it is all the map-sectors in between the current packet and the previous packet.
-
- Args:
- packet1 (Packet): Primary packet object
- packet2 (Packet): Prvious packet object
-
- Returns:
- Returns any related map sectors (as an array)
- """
- relatedMapSectors = []
- distance = calculatedDistance = packet1.getDistance(
- packet2.latitude, packet2.longitude)
- if (distance > 500000):
- # if distance is longer than 500km, we consider this station to be world wide...
- # but currently we do not use this information since it would affect performance to much
- # but it is extremly few stations that actually is affected by this (about 0-2 stations)
- relatedMapSectors.append(99999999)
- else:
- minLat = packet2.latitude
- maxLat = packet1.latitude
- minLng = packet2.longitude
- maxLng = packet1.longitude
-
- if (maxLat < minLat):
- minLat = packet1.latitude
- maxLat = packet2.latitude
- if (maxLng < minLng):
- minLng = packet1.longitude
- maxLng = packet2.longitude
-
- mapSectorPolicy = MapSectorPolicy()
- minLng = mapSectorPolicy.getMapSectorLngRepresentation(minLng)
- minLat = mapSectorPolicy.getMapSectorLatRepresentation(minLat)
- maxLng = mapSectorPolicy.getMapSectorLngRepresentation(
- maxLng + 0.5)
- maxLat = mapSectorPolicy.getMapSectorLatRepresentation(
- maxLat + 0.2)
- prevPacketAreaCode = mapSectorPolicy.getMapSector(
- packet2.latitude, packet2.longitude)
- newPacketAreaCode = mapSectorPolicy.getMapSector(
- packet1.latitude, packet1.longitude)
-
- # lat interval: 0 - 18000000
- # lng interval: 0 - 00003600
- # Maybe we can do this smarter? Currently we are adding many map-sectors that is not relevant
- for lat in range(minLat, maxLat, 20000):
- for lng in range(minLng, maxLng, 5):
- mapSectorAreaCode = lat+lng
- if (mapSectorAreaCode != prevPacketAreaCode and mapSectorAreaCode != newPacketAreaCode):
- relatedMapSectors.append(mapSectorAreaCode)
- return relatedMapSectors
diff --git a/server/trackdirect/parser/policies/PacketSpeedComputablePolicy.py b/server/trackdirect/parser/policies/PacketSpeedComputablePolicy.py
deleted file mode 100644
index e1409b480b27900fc12925972fd74b68adf3fc76..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketSpeedComputablePolicy.py
+++ /dev/null
@@ -1,47 +0,0 @@
-class PacketSpeedComputablePolicy():
- """PacketSpeedComputablePolicy handles logic related to parameters that may cause errors in speed calculations
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def isSpeedComputable(self, packet, prevPacket):
- """Returns true if speed is possible to calculate in a way that we can trust it
-
- Args:
- packet (Packet): Packet that we want to know move typ for
- prevPacket (Packet): Previous related packet for the same station
-
- Returns:
- Returns true if speed is possible to calculate
- """
- if (packet is None
- or prevPacket is None
- or prevPacket.isMoving != 1
- or prevPacket.mapId not in [1, 7]
- or packet.markerId == 1
- or packet.isMoving != 1):
- return False
-
- if (packet.reportedTimestamp is not None
- and prevPacket.reportedTimestamp is not None
- and packet.reportedTimestamp != 0
- and prevPacket.reportedTimestamp != 0
- and (packet.reportedTimestamp % 60 != 0 or prevPacket.reportedTimestamp % 60 != 0)
- and prevPacket.reportedTimestamp != packet.reportedTimestamp):
- return True
- else:
- calculatedDistance = packet.getDistance(
- prevPacket.latitude, prevPacket.longitude)
- if (len(packet.stationIdPath) < 1):
- # Packet was sent through internet, delay should be small
- return True
- elif (len(packet.stationIdPath) <= 1 and calculatedDistance > 5000):
- # Packet has not been digipeated (delay should not be extreme)
- # and distance is longer than 5km
- return True
- else:
- # Packet was digipeated (delay can be very long)
- # or distance was short, calculated speed can not be trusted
- return False
diff --git a/server/trackdirect/parser/policies/PacketTailPolicy.py b/server/trackdirect/parser/policies/PacketTailPolicy.py
deleted file mode 100644
index b422f2274bf73c29d19bed3b16e30bc99ba542c2..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PacketTailPolicy.py
+++ /dev/null
@@ -1,46 +0,0 @@
-class PacketTailPolicy():
- """PacketTailPolicy handles logic related to packet tail id
- """
-
- def __init__(self, packet, prevPacket):
- """The __init__ method.
-
- Args:
- packet (Packet): Packet that we want analyze
- prevPacket (Packet): Previous related packet for the same station
- """
- self.packet = packet
- self.prevPacket = prevPacket
- self.packetTailTimestamp = None
-
- def getPacketTailTimestamp(self):
- """Returns the current packet tail timestamp
- """
- if (self.packetTailTimestamp is None):
- self._findPacketTail()
- return self.packetTailTimestamp
-
- def _findPacketTail(self):
- """Finds the current packet tail
- """
- self.packetTailTimestamp = self.packet.timestamp
-
- if (self.prevPacket.isExistingObject()):
- # The packet_tail_id is used to get a faster map, no need to fetch older packets if a station has no tail.
- # It's not a big problem if packet_tail_id is "Has tail" but no tail exists (the opposite is worse)
- if (not self.packet.isPostitionEqual(self.prevPacket)):
- # Both moving and stationary has tail if packet with other position exists
- self.packetTailTimestamp = self.packet.timestamp
-
- if (self.packet.isMoving == 0 and not self.packet.isSymbolEqual(self.prevPacket)):
- # Stationary packet also has a tail if another symbol exists on same position
- self.packetTailTimestamp = self.packet.timestamp
-
- if (self.packetTailTimestamp == self.packet.timestamp):
- # We have not found any tail yet
- if (self.prevPacket.packetTailTimestamp < self.prevPacket.timestamp):
- # prevous packet has a tail
- dbMaxAge = 86400 # 1 day
- if (self.prevPacket.packetTailTimestamp > (self.packet.timestamp - dbMaxAge)):
- # Previous packet indicates that we have a tail and tail is not to old
- self.packetTailTimestamp = self.prevPacket.timestamp
diff --git a/server/trackdirect/parser/policies/PreviousPacketPolicy.py b/server/trackdirect/parser/policies/PreviousPacketPolicy.py
deleted file mode 100644
index feea95b14e100b56079f94ccd513904596035f1e..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/PreviousPacketPolicy.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import logging
-from twisted.python import log
-import datetime
-import time
-
-from trackdirect.parser.policies.PacketAssumedMoveTypePolicy import PacketAssumedMoveTypePolicy
-from trackdirect.parser.policies.PacketOrderPolicy import PacketOrderPolicy
-
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.repositories.StationRepository import StationRepository
-
-
-class PreviousPacketPolicy():
- """The PreviousPacketPolicy class tries to find the most related previous packet for the same station
- """
-
- def __init__(self, packet, db):
- """The __init__ method.
-
- Args:
- packet (Packet): Packet for that we want to find previous most related packet
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.packet = packet
- self.packetRepository = PacketRepository(db)
- self.stationRepository = StationRepository(db)
-
- def getPreviousPacket(self):
- """Tries to find the previous packet for the specified packet
-
- Returns:
- Packet
- """
- if (not self._mayPacketHavePreviousPacket()):
- return self.packetRepository.create()
-
- minTimestamp = int(time.time()) - 86400 # 24 hours
- latestPreviousPacket = self.packetRepository.getLatestObjectByStationId(self.packet.stationId, minTimestamp)
-
- if (not latestPreviousPacket.isExistingObject()):
- return latestPreviousPacket
-
- if (self.packet.mapId == 5):
- return self._getBestPreviousPacketForFaultyGpsPacket(latestPreviousPacket)
- else:
- packetAssumedMoveTypePolicy = PacketAssumedMoveTypePolicy(self.db)
- isMoving = packetAssumedMoveTypePolicy.getAssumedMoveType(self.packet, latestPreviousPacket)
- if (isMoving == 1):
- return self._getBestPreviousPacketForMovingStation(latestPreviousPacket, minTimestamp)
- else:
- return self._getBestPreviousPacketForStationaryStation(latestPreviousPacket)
-
- def _mayPacketHavePreviousPacket(self):
- """Returns true if current packet is ready for previous packet calculation
-
- Returns:
- boolean
- """
- if (self.packet.latitude is not None
- and self.packet.longitude is not None
- and type(self.packet.latitude) == float
- and type(self.packet.longitude) == float
- and self.packet.sourceId != 3
- and self.packet.mapId in [1, 5, 7, 9]):
- return True
- else:
- return False
-
- def _getBestPreviousPacketForFaultyGpsPacket(self, latestPreviousPacket):
- """Find the previous packet that is best related to the current packet
-
- Args:
- latestPreviousPacket (Packet): Packet object that represents the latest previous packet for this station
-
- Returns:
- Packet
- """
- if (latestPreviousPacket.mapId != self.packet.mapId
- or not self.packet.isPostitionEqual(latestPreviousPacket)
- or not self.packet.isSymbolEqual(latestPreviousPacket)):
- # Try to find prev packet
- prevPacketSamePos = self.packetRepository.getLatestObjectByStationIdAndPosition(
- self.packet.stationId,
- self.packet.latitude,
- self.packet.longitude,
- [self.packet.mapId],
- self.packet.symbol,
- self.packet.symbolTable,
- self.packet.timestamp - 86400
- )
- if (prevPacketSamePos.isExistingObject()):
- return prevPacketSamePos
- return latestPreviousPacket
-
- def _getBestPreviousPacketForStationaryStation(self, latestPreviousPacket):
- """Find the previous packet that is best related to the current packet
-
- Args:
- latestPreviousPacket (Packet): Packet object that represents the latest previous packet for this station
-
- Returns:
- Packet
- """
- if (not self.packet.isPostitionEqual(latestPreviousPacket)
- or not self.packet.isSymbolEqual(latestPreviousPacket)
- or self.packet.isMoving != latestPreviousPacket.isMoving
- or latestPreviousPacket.mapId not in [1, 7]):
- # Try to find stationary marker for packet position
- previousPacketSamePos = self.packetRepository.getLatestObjectByStationIdAndPosition(
- self.packet.stationId,
- self.packet.latitude,
- self.packet.longitude,
- [1, 7],
- self.packet.symbol,
- self.packet.symbolTable,
- self.packet.timestamp - 86400
- )
- if (previousPacketSamePos.isExistingObject()):
- return previousPacketSamePos
- return latestPreviousPacket
-
- def _getBestPreviousPacketForMovingStation(self, latestPreviousPacket, minTimestamp):
- """Find the previous packet that is best related to the current packet
-
- Args:
- latestPreviousPacket (Packet): Packet object that represents the latest previous packet for this station
- minTimestamp (int): Oldest accepted timestamp (Unix timestamp)
-
- Returns:
- Packet
- """
- previousPacket = latestPreviousPacket
- if (previousPacket.isExistingObject()
- and (previousPacket.isMoving != 1
- or previousPacket.mapId not in [1, 7])):
- # Current packet is assumed moving but previous is stationary, try to find last moving instead
- prevMovingPacket = self.packetRepository.getLatestMovingObjectByStationId(
- self.packet.stationId, minTimestamp)
- if (prevMovingPacket.isExistingObject()):
- previousPacket = prevMovingPacket
-
- packetOrderPolicy = PacketOrderPolicy()
- if (previousPacket.isExistingObject()
- and previousPacket.isMoving == 1
- and previousPacket.mapId == 7
- and not packetOrderPolicy.isPacketInWrongOrder(self.packet, previousPacket)):
- # previousPacket is not confirmed (see if we have a better alternative)
- prevConfirmedPacket = self.packetRepository.getLatestConfirmedMovingObjectByStationId(
- self.packet.stationId, minTimestamp)
- previousPacket = self._getClosestPacketObject(
- previousPacket, prevConfirmedPacket)
-
- return previousPacket
-
- def _getClosestPacketObject(self, previousPacket1, previousPacket2):
- """Returns the packet closest to the current position
-
- Args:
- previousPacket1 (Packet): Packet object that represents one previous packet for current station
- previousPacket2 (Packet): Packet object that represents one previous packet for current station
-
- Returns:
- Packet
- """
- if (not previousPacket1.isExistingObject()):
- return previousPacket2
-
- if (not previousPacket2.isExistingObject()):
- return previousPacket1
-
- prevPacket1CalculatedDistance = self.packet.getDistance(
- previousPacket1.latitude, previousPacket1.longitude)
- prevPacket2CalculatedDistance = self.packet.getDistance(
- previousPacket2.latitude, previousPacket2.longitude)
-
- if (prevPacket2CalculatedDistance < prevPacket1CalculatedDistance):
- return previousPacket2
- else:
- return previousPacket1
diff --git a/server/trackdirect/parser/policies/StationNameFormatPolicy.py b/server/trackdirect/parser/policies/StationNameFormatPolicy.py
deleted file mode 100644
index ca07c6163d74fd26ffee62f8b03d24354f3685f8..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/StationNameFormatPolicy.py
+++ /dev/null
@@ -1,26 +0,0 @@
-class StationNameFormatPolicy():
- """The StationNameFormatPolicy class handles logic related to station name format
- """
-
- def __init__(self):
- """The __init__ method.
- """
-
- def getCorrectFormat(self, name):
- """ Returns the specified name in correct format
- (without any status characters)
-
- Notes:
- _ == kill character
- ! == live character for item
- * == live character for object
- single quote and double quote is just to annoying
- (of course we can handle it in database but why use it in a name...)
-
- Args:
- name (string): name of station
-
- Returns:
- string
- """
- return name.replace('*', '').replace('!', '').replace('_', '').replace('\'', '').replace('"', '').replace('`', '').strip()
diff --git a/server/trackdirect/parser/policies/__init__.py b/server/trackdirect/parser/policies/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/parser/policies/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/repositories/MarkerRepository.py b/server/trackdirect/repositories/MarkerRepository.py
deleted file mode 100644
index 10b98f1eb254ca90f1e957a08b144c8a49c885f0..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/MarkerRepository.py
+++ /dev/null
@@ -1,45 +0,0 @@
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.Marker import Marker
-
-
-class MarkerRepository(Repository):
- """A Repository class for the Marker class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- Marker
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select %s from marker_seq where last_value > %s""", (id, id, ))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
-
- selectCursor.close()
- return dbObject
-
- def create(self):
- """Creates an empty Marker object
-
- Returns:
- Marker
- """
- return Marker(self.db)
diff --git a/server/trackdirect/repositories/OgnDeviceRepository.py b/server/trackdirect/repositories/OgnDeviceRepository.py
deleted file mode 100644
index b5d678531a52f4764239228bd4779bd0be5cb8b9..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/OgnDeviceRepository.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from random import randint
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.OgnDevice import OgnDevice
-
-
-class OgnDeviceRepository(Repository):
- """A Repository class for the OgnDevice class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- OgnDevice
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from ogn_device where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- else:
- # ogn_device do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectByDeviceId(self, deviceId):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- deviceId (string): Device Id (corresponds to ogn_sender_address)
-
- Returns:
- OgnDevice instance
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from ogn_device where device_id like %s""", (deviceId,))
- record = selectCursor.fetchone()
-
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- else:
- # ogn_device do not exists, return empty object
- dbObject = OgnDevice(self.db)
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromRecord(self, record):
- """Returns a OgnDevice object based on the specified database record dict
-
- Args:
- record (dict): A database record dict from the ogn_device database table
-
- Returns:
- A OgnDevice object
- """
- dbObject = self.create()
- if (record is not None):
- dbObject.id = randint(1, 9999999)
- dbObject.deviceType = record["device_type"]
- dbObject.deviceId = record["device_id"]
- dbObject.aircraftModel = record["aircraft_model"]
- dbObject.registration = record["registration"]
- dbObject.cn = record["cn"]
-
- if (record["tracked"] == 'N'):
- dbObject.tracked = False
- else:
- dbObject.tracked = True
-
- if (record["identified"] == 'N'):
- dbObject.identified = False
- else:
- dbObject.identified = True
-
- try:
- dbObject.ddbAircraftType = int(record["ddb_aircraft_type"])
- except ValueError:
- pass
-
- return dbObject
-
- def create(self):
- """Creates an empty OgnDevice object
-
- Returns:
- OgnDevice instance
- """
- return OgnDevice(self.db)
diff --git a/server/trackdirect/repositories/OgnHiddenStationRepository.py b/server/trackdirect/repositories/OgnHiddenStationRepository.py
deleted file mode 100644
index 2e805e1f4bec85c0a2146a704063bef69b4c93b4..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/OgnHiddenStationRepository.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.OgnHiddenStation import OgnHiddenStation
-
-
-class OgnHiddenStationRepository(Repository):
- """A Repository class for the OgnHiddenStation class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- OgnHiddenStation
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from ogn_hidden_station where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- else:
- # station do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectByHashedName(self, hashedName, createNewIfMissing):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- hashedName (string): Uniqe hash for station
- createNewIfMissing (boolean): Set to true if a new should be created if no one is found
-
- Returns:
- OgnHiddenStation instance
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from ogn_hidden_station where hashed_name = %s""", (str(hashedName),))
- record = selectCursor.fetchone()
-
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- elif (createNewIfMissing):
- # not exist, create it
- dbObject = self.create()
- dbObject.hashedName = hashedName
- dbObject.save()
- else:
- # ogn_device do not exists, return empty object
- dbObject = self.create()
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromRecord(self, record):
- """Returns a OgnHiddenStation object based on the specified database record dict
-
- Args:
- record (dict): A database record dict from the ogn_device database table
-
- Returns:
- A OgnHiddenStation object
- """
- dbObject = self.create()
- if (record is not None):
- dbObject.id = int(record["id"])
- dbObject.name = record["hashed_name"]
-
- return dbObject
-
- def create(self):
- """Creates an empty OgnHiddenStation object
-
- Returns:
- OgnHiddenStation instance
- """
- return OgnHiddenStation(self.db)
diff --git a/server/trackdirect/repositories/PacketOgnRepository.py b/server/trackdirect/repositories/PacketOgnRepository.py
deleted file mode 100644
index 46fff16170bd0ff2a102beb88f43b4c0aa9ccfaa..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/PacketOgnRepository.py
+++ /dev/null
@@ -1,126 +0,0 @@
-import datetime
-import time
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.PacketOgn import PacketOgn
-
-
-class PacketOgnRepository(Repository):
- """A Repository class for the PacketOgn class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- PacketOgn
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from packet_ogn where id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectByPacketIdAndTimestamp(self, id, timestamp):
- """Returns an object based on the specified packet id in database
-
- Args:
- id (int): Database row id
- timestamp (int): Unix timestamp for requested packet (must be samt date as packet was received)
-
- Returns:
- PacketOgn
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from packet_ogn where packet_id = %s and timestamp = %s""", (id, timestamp,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectFromRecord(self, record):
- """Returns a packet OGN object from a record
-
- Args:
- record (dict): Database record dict to convert to a packet OGN object
-
- Returns:
- A packet OGN object
- """
- dbObject = PacketOgn(self.db)
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.packetId = int(record["packet_id"])
- dbObject.stationId = int(record["station_id"])
- dbObject.timestamp = int(record["timestamp"])
-
- dbObject.ognSenderAddress = record['ogn_sender_address']
- dbObject.ognAddressTypeId = record['ogn_address_type_id']
- dbObject.ognAircraftTypeId = record['ogn_aircraft_type_id']
- dbObject.ognClimbRate = record['ogn_climb_rate']
- dbObject.ognTurnRate = record['ogn_turn_rate']
- dbObject.ognSignalToNoiseRatio = record['ogn_signal_to_noise_ratio']
- dbObject.ognBitErrorsCorrected = record['ogn_bit_errors_corrected']
- dbObject.ognFrequencyOffset = record['ogn_frequency_offset']
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- PacketOgn
- """
- newObject = self.create()
- if ("ogn" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.timestamp = int(time.time()) - 1
-
- if ("ogn_sender_address" in data["ogn"]):
- newObject.ognSenderAddress = data["ogn"]["ogn_sender_address"]
-
- if ("ogn_address_type_id" in data["ogn"]):
- newObject.ognAddressTypeId = data["ogn"]["ogn_address_type_id"]
-
- if ("ogn_aircraft_type_id" in data["ogn"]):
- newObject.ognAircraftTypeId = data["ogn"]["ogn_aircraft_type_id"]
-
- if ("ogn_climb_rate" in data["ogn"]):
- newObject.ognClimbRate = data["ogn"]["ogn_climb_rate"]
-
- if ("ogn_turn_rate" in data["ogn"]):
- newObject.ognTurnRate = data["ogn"]["ogn_turn_rate"]
-
- if ("ogn_signal_to_noise_ratio" in data["ogn"]):
- newObject.ognSignalToNoiseRatio = data["ogn"]["ogn_signal_to_noise_ratio"]
-
- if ("ogn_bit_errors_corrected" in data["ogn"]):
- newObject.ognBitErrorsCorrected = data["ogn"]["ogn_bit_errors_corrected"]
-
- if ("ogn_frequency_offset" in data["ogn"]):
- newObject.ognFrequencyOffset = data["ogn"]["ogn_frequency_offset"]
-
- return newObject
-
- def create(self):
- """Creates an empty PacketOgn object
-
- Returns:
- PacketOgn
- """
- return PacketOgn(self.db)
diff --git a/server/trackdirect/repositories/PacketRepository.py b/server/trackdirect/repositories/PacketRepository.py
deleted file mode 100644
index 39380f34f3894e155b3ff6ac63b7fd47ac4d0051..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/PacketRepository.py
+++ /dev/null
@@ -1,764 +0,0 @@
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.Packet import Packet
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-
-
-class PacketRepository(Repository):
- """The PacketRepository class contains different method that creates Packet instances
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.db = db
-
- # After testing I have realized that several queries are faster if you query one packet child at the time
- # That is why we are using packetTableCreator to fetch childtables instead of using the parent packet table
- self.packetTableCreator = PacketTableCreator(self.db)
- self.packetTableCreator.disableCreateIfMissing()
- self.dbObjectFinder = DatabaseObjectFinder(db)
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from packet where id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectByIdAndTimestamp(self, id, timestamp):
- """Returns an object based on the specified id in database
-
- Args:
- id (int): Database row id
- timestamp (int): Unix timestamp for requested packet
-
- Returns:
- Packet
- """
- try:
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- except TrackDirectMissingTableError as e:
- return Packet(self.db)
-
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from """ +
- packetTable + """ where id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectByStationIdAndTimestamp(self, stationId, timestamp):
- """Returns an object based on the specified stationId in database
-
- Args:
- stationId (int): Station id
- timestamp (int): Unix timestamp for requested packet
-
- Returns:
- Packet
- """
- try:
- packetTable = self.packetTableCreator.getPacketTable(timestamp)
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from """ + packetTable +
- """ where station_id = %s and timestamp = %s order by id limit 1""", (stationId, timestamp, ))
- record = selectCursor.fetchone()
-
- selectCursor.close()
- return self.getObjectFromRecord(record)
- except TrackDirectMissingTableError as e:
- return self.create()
-
- def getLatestObjectListByStationIdListAndTimeInterval(self, stationIdList, minPacketTimestamp, maxPacketTimestamp, onlyConfirmed=True):
- """Returns an array of Packet's specified by station id's
- Args:
- stationIdList (array): Station id's to look for
- minPacketTimestamp (int): Min requested unix timestamp
- maxPacketTimestamp (int): Max requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
-
- selectCursor = self.db.cursor()
- result = []
- foundStationIdList = []
- packetTables = self.packetTableCreator.getPacketTables(
- minPacketTimestamp, maxPacketTimestamp)
- mapIdList = [1, 2, 12]
- if (not onlyConfirmed):
- mapIdList = [1, 2, 5, 7, 9, 12]
-
- for packetTable in reversed(packetTables):
- stationIdListToFind = tuple(
- list(set(stationIdList) - set(foundStationIdList)))
-
- if (len(stationIdListToFind) > 0):
- sql1 = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where id in (
- select max(id)
- from """ + packetTable + """ packet
- where map_id in %s
- and station_id in %s
- and timestamp > %s
- and timestamp <= %s
- group by station_id
- )
- order by packet.marker_id desc, packet.id desc""", (tuple(mapIdList), tuple(stationIdListToFind), int(minPacketTimestamp), int(maxPacketTimestamp)))
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql1)
- for record in selectCursor:
- if (record is not None):
- if (record['station_id'] not in foundStationIdList):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
- foundStationIdList.append(record['station_id'])
- if (len(foundStationIdList) >= len(stationIdList)):
- break
-
- if (len(foundStationIdList) < len(stationIdList)):
- for packetTable in reversed(packetTables):
- stationIdListToFind = tuple(
- list(set(stationIdList) - set(foundStationIdList)))
-
- if (len(stationIdListToFind) > 0):
- sql2 = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where map_id = 12
- and station_id in %s
- and position_timestamp <= %s
- and timestamp > %s
- order by packet.marker_id desc, packet.id desc""", (tuple(stationIdListToFind), int(maxPacketTimestamp), int(minPacketTimestamp)))
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql2)
- for record in selectCursor:
- if (record is not None):
- if (record['station_id'] not in foundStationIdList):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
- foundStationIdList.append(record['station_id'])
-
- if (len(foundStationIdList) >= len(stationIdList)):
- break
-
- selectCursor.close()
- return result
-
- def getObjectListByStationIdListAndTimeInterval(self, stationIdList, minPacketTimestamp, maxPacketTimestamp):
- """Returns an array of Packet's specified by station id's
- Args:
- stationIdList (array): Station id's to look for
- minPacketTimestamp (int): Min requested unix timestamp
- maxPacketTimestamp (int): Max requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
-
- selectCursor = self.db.cursor()
-
- result = []
- packetTables = self.packetTableCreator.getPacketTables(
- minPacketTimestamp, maxPacketTimestamp)
-
- for packetTable in packetTables:
- sql1 = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where map_id in (1,2,5,7,9,12)
- and station_id in %s
- and timestamp > %s
- and timestamp <= %s
- order by packet.marker_id, packet.id""", (tuple(stationIdList), int(minPacketTimestamp), int(maxPacketTimestamp)))
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql1)
- for record in selectCursor:
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- # Also add packets that has been replace but where position_timestamp was in or before period
- sql2 = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where map_id = 12
- and station_id in %s
- and position_timestamp <= %s
- and timestamp > %s
- order by packet.marker_id, packet.id""", (tuple(stationIdList), int(maxPacketTimestamp), int(maxPacketTimestamp)))
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql2)
- for record in selectCursor:
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- selectCursor.close()
- return result
-
- def getObjectListByStationIdList(self, stationIdList, minPacketTimestamp):
- """Returns an array of Packet's specified by station id's
- Args:
- stationIdList (array): Station id's to look for
- minPacketTimestamp (int): Min requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
- selectCursor = self.db.cursor()
- result = []
-
- packetTables = self.packetTableCreator.getPacketTables(
- minPacketTimestamp)
- for packetTable in packetTables:
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where map_id in (1,5,7,9)
- and station_id in %s""", (tuple(stationIdList),))
-
- if (minPacketTimestamp != 0):
- sql = sql + \
- selectCursor.mogrify(
- """ and timestamp > %s""", (int(minPacketTimestamp),))
-
- sql = sql + \
- selectCursor.mogrify(
- """ order by packet.marker_id, packet.id""")
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
- selectCursor.execute(sql)
-
- for record in selectCursor:
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
- selectCursor.close()
- return result
-
- def getLatestObjectByStationIdAndPosition(self, stationId, latitude, longitude, mapIdList, symbol=None, symbolTable=None, minTimestamp=0):
- """Returns a packet object specified by station id and position (and map id, symbol and symbol table)
- Args:
- stationId (int): Station id to look for
- latitude (double): Latitude
- longitude (double): Longitude
- mapIdList (int): Array of map id's to look for
- symbol (str): Symbol char
- symbolTable (str): Symbol table char
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
- packetTables = self.packetTableCreator.getPacketTables(minTimestamp)
- for packetTable in reversed(packetTables):
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """
- where station_id = %s
- and latitude = %s
- and longitude = %s
- and map_id in %s""", (stationId, latitude, longitude, tuple(mapIdList),))
-
- if (minTimestamp != 0):
- sql = sql + \
- selectCursor.mogrify(
- """ and timestamp > %s""", (int(minTimestamp),))
-
- if (symbol is not None):
- sql = sql + \
- selectCursor.mogrify(""" and symbol = %s""", (symbol,))
-
- if (symbolTable is not None):
- sql = sql + \
- selectCursor.mogrify(
- """ and symbol_table = %s""", (symbolTable,))
-
- sql = sql + \
- selectCursor.mogrify(
- """ order by marker_id desc, id desc limit 1""")
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql)
- record = selectCursor.fetchone()
-
- if (record is not None):
- selectCursor.close()
- return self.getObjectFromRecord(record)
- selectCursor.close()
- return self.create()
-
- def getLatestConfirmedMovingObjectByStationId(self, stationId, minTimestamp=0):
- """Returns the latest confirmed moving Packet specified by station id
- Args:
- stationId (int): Station id to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
- packetTables = self.packetTableCreator.getPacketTables(minTimestamp)
- for packetTable in reversed(packetTables):
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """
- where station_id = %s
- and is_moving = 1
- and map_id = 1""", (stationId,))
-
- if (minTimestamp != 0):
- sql = sql + \
- selectCursor.mogrify(
- """ and timestamp > %s""", (int(minTimestamp),))
-
- sql = sql + \
- selectCursor.mogrify(
- """ order by marker_id desc, id desc limit 1""")
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql)
- record = selectCursor.fetchone()
-
- if (record is not None):
- selectCursor.close()
- return self.getObjectFromRecord(record)
- selectCursor.close()
- return self.create()
-
- def getLatestMovingObjectByStationId(self, stationId, minTimestamp=0):
- """Returns the latest moving Packet specified by station id
- Args:
- stationId (int): Station id to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
- packetTables = self.packetTableCreator.getPacketTables(minTimestamp)
- for packetTable in reversed(packetTables):
- # We only look for map id 1 and 7 since we use this method to extend a moving marker
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where station_id = %s
- and is_moving = 1
- and map_id in (1,7)""", (stationId,))
-
- if (minTimestamp != 0):
- sql = sql + \
- selectCursor.mogrify(
- """ and timestamp > %s""", (int(minTimestamp),))
-
- sql = sql + \
- selectCursor.mogrify(
- """ order by marker_id desc, id desc limit 1""")
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql)
-
- record = selectCursor.fetchone()
- if (record is not None):
- selectCursor.close()
- return self.getObjectFromRecord(record)
- selectCursor.close()
- return self.create()
-
- def getLatestConfirmedObjectByStationId(self, stationId, minTimestamp=0):
- """Returns the latest confirmed packet object specified by station id
- Args:
- stationId (int): Station id to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
-
- sql = selectCursor.mogrify("""select *
- from station
- where station.id = %s""", (stationId,))
-
- selectCursor.execute(sql)
- record = selectCursor.fetchone()
- selectCursor.close()
-
- if (record is not None and record["latest_confirmed_packet_timestamp"] is not None and record["latest_confirmed_packet_timestamp"] >= minTimestamp):
- return self.getObjectByIdAndTimestamp(record["latest_confirmed_packet_id"], record["latest_confirmed_packet_timestamp"])
- else:
- return self.create()
-
- def getLatestObjectByStationId(self, stationId, minTimestamp=0):
- """Returns the latest Packet specified by station id (that has a location)
- Args:
- stationId (int): Station id to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Packet
- """
- selectCursor = self.db.cursor()
-
- sql = selectCursor.mogrify("""select *
- from station
- where station.id = %s""", (stationId,))
-
- selectCursor.execute(sql)
- record = selectCursor.fetchone()
- selectCursor.close()
-
- if (record is not None and record["latest_location_packet_timestamp"] is not None and record["latest_location_packet_timestamp"] >= minTimestamp):
- return self.getObjectByIdAndTimestamp(record["latest_location_packet_id"], record["latest_location_packet_timestamp"])
- else:
- return self.create()
-
- def getMostRecentConfirmedObjectListByStationIdList(self, stationIdList, minTimestamp):
- """Returns an array of the most recent confirmed Packet's specified by station id's
-
- Note:
- This method returnes the latest packet for moving stations and the latest packet for every uniqe position for stationary stations.
-
- Args:
- stationIdList (array): Station id's to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
- selectCursor = self.db.cursor()
- result = []
-
- # Stationary objects
- packetTables = self.packetTableCreator.getPacketTables(minTimestamp)
- for packetTable in packetTables:
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """
- where station_id in %s
- and timestamp > %s
- and is_moving = 0
- and map_id = 1""", (tuple(stationIdList), int(minTimestamp),))
- # Since we only should get one moving and all other should be stationary an "order by" should not be nessecery
- selectCursor.execute(sql)
-
- for record in selectCursor:
- if (record is not None):
- packet = self.getObjectFromRecord(record)
- result.append(packet)
-
- # Moving objects
- for stationId in stationIdList:
- packet = self.getLatestConfirmedMovingObjectByStationId(
- stationId, minTimestamp)
- if (packet.isExistingObject()):
- result.append(packet)
-
- selectCursor.close()
- return result
-
- def getMostRecentConfirmedObjectListByStationIdListAndTimeInterval(self, stationIdList, minTimestamp, maxTimestamp):
- """Returns an array of the most recent confirmed Packet's specified by station id's
-
- Note:
- This method returnes the latest packet for moving stations and the latest packet for every uniqe position for stationary stations.
-
- Args:
- stationIdList (array): Station id's to look for
- minTimestamp (int): Min requested unix timestamp
- maxTimestamp (int): Max requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
-
- minTimestampRoundedQuarter = int(
- minTimestamp) - (int(minTimestamp) % 900)
- minTimestampRoundedDay = int(
- minTimestamp) - (int(minTimestamp) % 86400)
-
- selectCursor = self.db.cursor()
- result = []
- foundStationaryMarkerHashList = []
- foundMovingMarkerStationIdList = []
-
- packetTables = self.packetTableCreator.getPacketTables(
- minTimestamp, maxTimestamp)
- for packetTable in reversed(packetTables):
- # Stationary objects
- sql = selectCursor.mogrify("""select *
- from """ + packetTable + """ packet
- where id in (
- select max(id)
- from """ + packetTable + """ packet
- where station_id in %s
- and timestamp > %s
- and timestamp <= %s
- and is_moving = 0
- and map_id in (1,2,12)
- group by station_id, latitude, longitude, symbol, symbol_table
- )""", (tuple(stationIdList), int(minTimestamp), int(maxTimestamp)))
- # Since we only should get one moving and all other should be stationary an "order by" should not be nessecery
- selectCursor.execute(sql)
- for record in selectCursor:
- if (record is not None):
- markerHash = hash(str(record['station_id']) + ';' + str(record['station_id']) + ';' + str(
- record['latitude']) + ';' + str(record['longitude']) + ';' + record['symbol'] + ';' + record['symbol_table'])
- if (markerHash not in foundStationaryMarkerHashList):
- foundStationaryMarkerHashList.append(markerHash)
- packet = self.getObjectFromRecord(record)
- result.append(packet)
-
- # Moving objects
- sql = selectCursor.mogrify("""select packet.*
- from """ + packetTable + """ packet
- where id in (
- select max(id)
- from """ + packetTable + """ packet
- where station_id in %s
- and map_id in (1,2,12)
- and packet.timestamp > %s
- and packet.timestamp <= %s
- and packet.is_moving = 1
- group by station_id
- )""", (tuple(stationIdList), int(minTimestamp), int(maxTimestamp)))
- # Since we only should get one moving and all other should be stationary an "order by" should not be nessecery
-
- selectCursor.execute(sql)
- for record in selectCursor:
- if (record is not None):
- if (record['station_id'] not in foundMovingMarkerStationIdList):
- foundMovingMarkerStationIdList.append(
- record['station_id'])
-
- packet = self.getObjectFromRecord(record)
- result.append(packet)
- selectCursor.close()
- return result
-
- def getLatestConfirmedObjectListByStationIdList(self, stationIdList, minTimestamp=0):
- """Returns an array of the latest confirmed packet objects with specified station id's
-
- Args:
- stationIdList (array): station id's to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
-
- result = []
- if (minTimestamp == 0):
- # Apperantly we are looking for the latest no matter the age
- for stationId in stationIdList:
- packet = self.getLatestConfirmedObjectByStationId(stationId)
- if (packet.isExistingObject()):
- result.append(packet)
- else:
- selectCursor = self.db.cursor()
- packetTables = self.packetTableCreator.getPacketTables(
- minTimestamp)
-
- for packetTable in reversed(packetTables):
- sql = selectCursor.mogrify("""select packet.*
- from """ + packetTable + """ packet, station
- where station.id in %s
- and station.latest_confirmed_packet_id = packet.id
- and station.latest_confirmed_packet_timestamp = packet.timestamp """, (tuple(stationIdList),))
-
- if (minTimestamp != 0):
- sql = sql + selectCursor.mogrify(
- """ and station.latest_confirmed_packet_timestamp > %s""" % (int(minTimestamp),))
-
- sql = sql + \
- selectCursor.mogrify(
- """ order by packet.marker_id, packet.id""")
- # Sort by marker_id first and packet as second, otherwise client might render it wrong
-
- selectCursor.execute(sql)
-
- for record in selectCursor:
- if (record is not None):
- result.append(self.getObjectFromRecord(record))
-
- if (len(result) >= len(stationIdList)):
- break
-
- selectCursor.close()
- return result
-
- def getLatestObjectListByStationIdList(self, stationIdList, minTimestamp=0):
- """Returns an array of the latest Packet's (that has a location) with specified station id's
-
- Args:
- stationIdList (array): station id's to look for
- minTimestamp (int): Min requested unix timestamp
-
- Returns:
- Array
- """
- if (len(stationIdList) == 0):
- return []
-
- result = []
- if (minTimestamp == 0):
- # Apperantly we are looking for the latest no matter the age
- for stationId in stationIdList:
- packet = self.getLatestObjectByStationId(stationId)
- if (packet.isExistingObject()):
- result.append(packet)
-
- else:
- selectCursor = self.db.cursor()
- packetTables = self.packetTableCreator.getPacketTables(
- minTimestamp)
- for packetTable in reversed(packetTables):
- sql = selectCursor.mogrify("""select packet.*
- from """ + packetTable + """ packet, station
- where station.id in %s
- and station.latest_location_packet_id = packet.id
- and station.latest_confirmed_packet_timestamp = packet.timestamp """, (tuple(stationIdList),))
-
- if (minTimestamp != 0):
- sql = sql + selectCursor.mogrify(
- """ and station.latest_location_packet_timestamp > %s""" % (int(minTimestamp),))
-
- selectCursor.execute(sql)
-
- for record in selectCursor:
- if (record is not None):
- result.append(self.getObjectFromRecord(record))
-
- if (len(result) >= len(stationIdList)):
- break
-
- selectCursor.close()
- return result
-
- def getObjectFromRecord(self, record):
- """Returns a packet object from a record
-
- Args:
- record (dict): Database record dict to convert to a packet object
-
- Returns:
- Packet
- """
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.stationId = int(record["station_id"])
- dbObject.senderId = int(record["sender_id"])
- dbObject.packetTypeId = record["packet_type_id"]
- dbObject.timestamp = int(record["timestamp"])
-
- if (record["latitude"] is not None):
- dbObject.latitude = float(record["latitude"])
- else:
- dbObject.latitude = None
-
- if (record["longitude"] is not None):
- dbObject.longitude = float(record["longitude"])
- else:
- dbObject.longitude = None
-
- dbObject.posambiguity = record['posambiguity']
- dbObject.symbol = record["symbol"]
- dbObject.symbolTable = record["symbol_table"]
- dbObject.mapSector = record["map_sector"]
- dbObject.relatedMapSectors = record["related_map_sectors"]
- dbObject.mapId = record["map_id"]
- dbObject.sourceId = record["source_id"]
- dbObject.markerId = record["marker_id"]
- dbObject.speed = record["speed"]
- dbObject.course = record["course"]
- dbObject.altitude = record["altitude"]
- dbObject.isMoving = record['is_moving']
-
- if (record["reported_timestamp"] is not None):
- dbObject.reportedTimestamp = int(record["reported_timestamp"])
- else:
- dbObject.reportedTimestamp = record["reported_timestamp"]
-
- if (record["position_timestamp"] is not None):
- dbObject.positionTimestamp = int(record["position_timestamp"])
- else:
- dbObject.positionTimestamp = record["position_timestamp"]
-
- if ("packet_tail_timestamp" in record):
- dbObject.packetTailTimestamp = record['packet_tail_timestamp']
- else:
- dbObject.packetTailTimestamp = dbObject.timestamp
-
- if ("marker_counter" in record):
- dbObject.markerCounter = record['marker_counter']
- else:
- dbObject.markerCounter = 1
-
- if ("comment" in record):
- dbObject.comment = record['comment']
- else:
- dbObject.comment = None
-
- if ("raw_path" in record):
- dbObject.rawPath = record['raw_path']
- else:
- dbObject.rawPath = None
-
- if ("raw" in record):
- dbObject.raw = record['raw']
- else:
- dbObject.raw = None
-
- if ("phg" in record):
- dbObject.phg = record['phg']
- else:
- dbObject.phg = None
-
- if ("rng" in record):
- dbObject.rng = record['rng']
- else:
- dbObject.rng = None
-
- if ("latest_phg_timestamp" in record):
- dbObject.latestPhgTimestamp = record['latest_phg_timestamp']
- else:
- dbObject.latestPhgTimestamp = None
-
- if ("latest_rng_timestamp" in record):
- dbObject.latestRngTimestamp = record['latest_rng_timestamp']
- else:
- dbObject.latestRngTimestamp = None
- return dbObject
-
- def create(self):
- """Creates an empty Packet
-
- Returns:
- Packet
- """
- return Packet(self.db)
diff --git a/server/trackdirect/repositories/PacketTelemetryRepository.py b/server/trackdirect/repositories/PacketTelemetryRepository.py
deleted file mode 100644
index c816f6a87d86ca1bad6097359a66b95720429616..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/PacketTelemetryRepository.py
+++ /dev/null
@@ -1,127 +0,0 @@
-import time
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.PacketTelemetry import PacketTelemetry
-from trackdirect.database.PacketTelemetryTableCreator import PacketTelemetryTableCreator
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketTelemetryRepository(Repository):
- """A Repository class for the PacketTelemetry class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.packetTelemetryTableCreator = PacketTelemetryTableCreator(self.db)
- self.packetTelemetryTableCreator.disableCreateIfMissing()
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- PacketTelemetry
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from packet_telemetry where id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectByPacketIdAndTimestamp(self, id, timestamp):
- """Returns an object based on the specified packet id in database
-
- Args:
- id (int): Database row id
- timestamp (int): Unix timestamp for requested packet
-
- Returns:
- PacketTelemetry
- """
- try:
- table = self.packetTelemetryTableCreator.getPacketTelemetryTable(
- timestamp)
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from """ +
- table + """ where packet_id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
- except TrackDirectMissingTableError as e:
- return self.create()
-
- def getObjectFromRecord(self, record):
- """Returns a packet telemetry object from a record
-
- Args:
- record (dict): Database record dict to convert to a packet telemetry object
-
- Returns:
- A packet telemetry object
- """
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.packetId = int(record["packet_id"])
- dbObject.stationId = int(record["station_id"])
- dbObject.timestamp = int(record["timestamp"])
- dbObject.val1 = int(record["val1"])
- dbObject.val2 = int(record["val2"])
- dbObject.val3 = int(record["val3"])
- dbObject.val4 = int(record["val4"])
- dbObject.val5 = int(record["val5"])
- dbObject.bits = int(record["bits"])
- dbObject.seq = int(record["seq"])
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- PacketTelemetry
- """
- newObject = self.create()
- if ("telemetry" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.timestamp = int(time.time()) - 1
-
- if ("vals" in data["telemetry"]):
- newObject.val1 = data["telemetry"]["vals"][0]
- newObject.val2 = data["telemetry"]["vals"][1]
- newObject.val3 = data["telemetry"]["vals"][2]
- newObject.val4 = data["telemetry"]["vals"][3]
- newObject.val5 = data["telemetry"]["vals"][4]
-
- if ("bits" in data["telemetry"]):
- newObject.bits = data["telemetry"]["bits"]
-
- if ("seq" in data["telemetry"]):
- if isinstance(data["telemetry"]["seq"], str):
- try:
- newObject.seq = int(data["telemetry"]["seq"], 10)
- except ValueError:
- newObject.seq = None
- elif isinstance(data["telemetry"]["seq"], int):
- newObject.seq = data["telemetry"]["seq"]
- return newObject
-
- def create(self):
- """Creates an empty PacketTelemetry object
-
- Returns:
- PacketTelemetry
- """
- return PacketTelemetry(self.db)
diff --git a/server/trackdirect/repositories/PacketWeatherRepository.py b/server/trackdirect/repositories/PacketWeatherRepository.py
deleted file mode 100644
index df2f5058f6d5ff5467d1684227d566bc7013820f..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/PacketWeatherRepository.py
+++ /dev/null
@@ -1,139 +0,0 @@
-import datetime
-import time
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.PacketWeather import PacketWeather
-from trackdirect.database.PacketWeatherTableCreator import PacketWeatherTableCreator
-from trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
-
-
-class PacketWeatherRepository(Repository):
- """A Repository class for the PacketWeather class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.packetWeatherTableCreator = PacketWeatherTableCreator(self.db)
- self.packetWeatherTableCreator.disableCreateIfMissing()
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- PacketWeather
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from packet_weather where id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
-
- def getObjectByPacketIdAndTimestamp(self, id, timestamp):
- """Returns an object based on the specified packet id in database
-
- Args:
- id (int): Database row id
- timestamp (int): Unix timestamp for requested packet (must be samt date as packet was received)
-
- Returns:
- PacketWeather
- """
- try:
- table = self.packetWeatherTableCreator.getPacketWeatherTable(
- timestamp)
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from """ +
- table + """ where packet_id = %s""", (id,))
- record = selectCursor.fetchone()
- selectCursor.close()
- return self.getObjectFromRecord(record)
- except TrackDirectMissingTableError as e:
- return self.create()
-
- def getObjectFromRecord(self, record):
- """Returns a packet weather object from a record
-
- Args:
- record (dict): Database record dict to convert to a packet weather object
-
- Returns:
- A packet weather object
- """
- dbObject = PacketWeather(self.db)
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.packetId = int(record["packet_id"])
- dbObject.stationId = int(record["station_id"])
- dbObject.timestamp = int(record["timestamp"])
- dbObject.humidity = record["humidity"]
- dbObject.pressure = record["pressure"]
- dbObject.rain1h = record["rain_1h"]
- dbObject.rain24h = record["rain_24h"]
- dbObject.rainSinceMidnight = record["rain_since_midnight"]
- dbObject.temperature = record["temperature"]
- dbObject.windDirection = record["wind_direction"]
- dbObject.windGust = record["wind_gust"]
- dbObject.windSpeed = record["wind_speed"]
- dbObject.luminosity = record["luminosity"]
- dbObject.snow = record["snow"]
- dbObject.wxRawTimestamp = record["wx_raw_timestamp"]
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- PacketWeather
- """
- newObject = self.create()
- if ("weather" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.timestamp = int(time.time()) - 1
-
- if ("humidity" in data["weather"]):
- newObject.humidity = data["weather"]["humidity"]
- if ("pressure" in data["weather"]):
- newObject.pressure = data["weather"]["pressure"]
- if ("rain_1h" in data["weather"]):
- newObject.rain1h = data["weather"]["rain_1h"]
- if ("rain_24h" in data["weather"]):
- newObject.rain24h = data["weather"]["rain_24h"]
- if ("rain_since_midnight" in data["weather"]):
- newObject.rainSinceMidnight = data["weather"]["rain_since_midnight"]
- if ("temperature" in data["weather"]):
- newObject.temperature = data["weather"]["temperature"]
- if ("wind_direction" in data["weather"]):
- newObject.windDirection = data["weather"]["wind_direction"]
- if ("wind_gust" in data["weather"]):
- newObject.windGust = data["weather"]["wind_gust"]
- if ("wind_speed" in data["weather"]):
- newObject.windSpeed = data["weather"]["wind_speed"]
- if ("luminosity" in data["weather"]):
- newObject.luminosity = data["weather"]["luminosity"]
- if ("snow" in data["weather"]):
- newObject.snow = data["weather"]["snow"]
- if ("wx_raw_timestamp" in data["weather"]):
- newObject.wxRawTimestamp = data["weather"]["wx_raw_timestamp"]
- return newObject
-
- def create(self):
- """Creates an empty PacketWeather object
-
- Returns:
- PacketWeather
- """
- return PacketWeather(self.db)
diff --git a/server/trackdirect/repositories/SenderRepository.py b/server/trackdirect/repositories/SenderRepository.py
deleted file mode 100644
index 44edc83e03020d7f16f44155288a09529d76fad9..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/SenderRepository.py
+++ /dev/null
@@ -1,167 +0,0 @@
-import logging
-import collections
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.Sender import Sender
-from trackdirect.objects.Station import Station
-from trackdirect.exceptions.TrackDirectMissingSenderError import TrackDirectMissingSenderError
-
-
-class SenderRepository(Repository):
- """A Repository class for the Sender class
- """
-
- # static class variables
- senderIdCache = {}
- senderNameCache = {}
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.logger = logging.getLogger('trackdirect')
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- Sender instance
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from sender where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = Sender(self.db)
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.name = record["name"]
- else:
- # sender do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectByName(self, name, createNewIfMissing=True, sourceId=None):
- """Returns an object based on the specified name
-
- Args:
- name (str): Name of the requested sender
- createNewIfMissing (boolean): Set to true if sender should be created if it can not be found
-
- Returns:
- Sender instance
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from sender where name = %s""", (name.strip(),))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.name = record["name"]
- elif (createNewIfMissing):
- # sender do not exists, create it
- dbObject.name = name
- dbObject.save()
-
- # Also create a related station
- stationObject = Station(self.db)
- stationObject.name = name
- stationObject.sourceId = sourceId
- stationObject.save()
-
- selectCursor.close()
- return dbObject
-
- def getObjectByStationId(self, stationId):
- """Returns an object based on the specified station id
-
- Args:
- stationId (int): Id of the station
-
- Returns:
- Sender instance
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from sender where id in (select latest_sender_id from station where id = %s)""", (stationId,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.name = record["name"]
-
- selectCursor.close()
- return dbObject
-
- def getCachedObjectById(self, senderId):
- """Get Sender based on sender id
-
- Args:
- senderId (int): Id of the sender
-
- Returns:
- Sender
- """
- if (senderId not in SenderRepository.senderIdCache):
- sender = self.getObjectById(senderId)
- if (sender.isExistingObject()):
- maxNumberOfSenders = 100
- if (len(SenderRepository.senderIdCache) > maxNumberOfSenders):
- # reset cache
- SenderRepository.senderIdCache = {}
- SenderRepository.senderIdCache[senderId] = sender
- return sender
- else:
- try:
- return SenderRepository.senderIdCache[senderId]
- except KeyError as e:
- sender = self.getObjectById(senderId)
- if (sender.isExistingObject()):
- return sender
- raise TrackDirectMissingSenderError(
- 'No sender with specified id found')
-
- def getCachedObjectByName(self, senderName):
- """Get Sender based on sender name
-
- Args:
- senderName (string): Sender name
-
- Returns:
- Sender
- """
- if (senderName not in SenderRepository.senderNameCache):
- sender = self.getObjectByName(senderName, False)
- if (sender.isExistingObject()):
- maxNumberOfSenders = 100
- if (len(SenderRepository.senderNameCache) > maxNumberOfSenders):
- # reset cache
- SenderRepository.senderNameCache = {}
- SenderRepository.senderNameCache[senderName] = sender
- return sender
- else:
- try:
- return SenderRepository.senderNameCache[senderName]
- except KeyError as e:
- sender = self.getObjectByName(senderName, False)
- if (sender.isExistingObject()):
- return sender
- raise TrackDirectMissingSenderError(
- 'No sender with specified sender name found')
-
- def create(self):
- """Creates an empty Sender object
-
- Returns:
- Sender instance
- """
- return Sender(self.db)
diff --git a/server/trackdirect/repositories/StationRepository.py b/server/trackdirect/repositories/StationRepository.py
deleted file mode 100644
index 24adde4840be456067ad9ad031ff9910cc2ed623..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/StationRepository.py
+++ /dev/null
@@ -1,375 +0,0 @@
-import collections
-import datetime
-import time
-import calendar
-from math import sin, cos, sqrt, atan2, radians, floor, ceil
-
-import logging
-from twisted.python import log
-
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.Station import Station
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.database.PacketTableCreator import PacketTableCreator
-from trackdirect.exceptions.TrackDirectMissingStationError import TrackDirectMissingStationError
-
-
-class StationRepository(Repository):
- """A Repository class for the Station class
- """
-
- # static class variables
- stationIdCache = {}
- stationNameCache = {}
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.logger = logging.getLogger('trackdirect')
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.packetTableCreator = PacketTableCreator(db)
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- Station
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from station where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- else:
- # station do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectListByStationIdList(self, stationIdList):
- """Returns a list of station objects
-
- Args:
- stationIdList (int): Array of station ids
-
- Returns:
- array
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from station where id in %s""", (tuple(stationIdList), ))
-
- result = []
- for record in selectCursor:
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- selectCursor.close()
- return result
-
- def getTinyObjectList(self):
- """Returns a list of all station id's
-
- Args:
- None
-
- Returns:
- array
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select id, latest_packet_timestamp from station order by id""")
-
- result = []
- for record in selectCursor:
- if (record is not None):
- dbObject = self.create()
- dbObject.id = int(record["id"])
- dbObject.latestPacketTimestamp = record["latest_packet_timestamp"]
- result.append(dbObject)
- selectCursor.close()
- return result
-
- def getObjectList(self):
- """Returns a list of all station object's
-
- Args:
- None
-
- Returns:
- array
- """
- selectCursor = self.db.cursor()
- selectCursor.execute("""select * from station order by id""")
-
- result = []
- for record in selectCursor:
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
- selectCursor.close()
- return result
-
- def getObjectListByName(self, name, stationTypeId=None, sourceId=None, minTimestamp=None):
- """Returns a list of stations based on the specified name
-
- Args:
- name (string): Name of station
- stationTypeId (int): Station type id
- sourceId (int): Station source id
-
- Returns:
- array
- """
- if (sourceId is not None and sourceId == 3):
- # If source is "APRS DUPLICATE" we use "APRS"
- sourceId = 1
-
- if (minTimestamp is None):
- minTimestamp = 0
-
- selectCursor = self.db.cursor()
- if (sourceId is not None and sourceId is not None):
- selectCursor.execute("""select *
- from station
- where station_type_id = %s
- and name = %s
- and (source_id = %s or source_id is null)
- and latest_confirmed_packet_timestamp > %s""", (stationTypeId, name, sourceId, minTimestamp,))
- elif (sourceId is not None):
- selectCursor.execute("""select *
- from station
- where station_type_id = %s
- and name = %s
- and latest_confirmed_packet_timestamp > %s""", (stationTypeId, name, minTimestamp,))
- else:
- selectCursor.execute("""select *
- from station
- where name = %s
- and latest_confirmed_packet_timestamp > %s""", (name, minTimestamp,))
-
- result = []
- for record in selectCursor:
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
- selectCursor.close()
- return result
-
- def getObjectByName(self, name, sourceId, stationTypeId=1, createNewIfMissing=True):
- """Returns an object based on the specified name of the station
-
- Args:
- name (str): Name of the station
- sourceId (int): Station source id
- createNewIfMissing (boolean): Set to true if a new station should be created if no one is found
-
- Returns:
- Station
- """
- if (sourceId == 3):
- # If source is "APRS DUPLICATE" we use "APRS"
- sourceId = 1
-
- selectCursor = self.db.cursor()
- if (sourceId is not None):
- selectCursor.execute(
- """select * from station where name = %s and (source_id is null or source_id = %s) order by id desc""", (name.strip(), sourceId))
- else:
- selectCursor.execute(
- """select * from station where name = %s order by id desc""", (name.strip()))
- record = selectCursor.fetchone()
-
- # Make sure we at least have an empty object...
- dbObject = self.create()
- if (record is not None):
- dbObject = self.getObjectFromRecord(record)
- if (dbObject.sourceId is None and dbObject.sourceId != sourceId):
- dbObject.sourceId = sourceId
- dbObject.save()
- if (dbObject.stationTypeId != stationTypeId and stationTypeId == 1):
- dbObject.stationTypeId = stationTypeId
- dbObject.save()
-
- elif (createNewIfMissing):
- # station do not exists, create it
- dbObject.name = name
- dbObject.sourceId = sourceId
- dbObject.stationTypeId = stationTypeId
- dbObject.save()
-
- selectCursor.close()
- return dbObject
-
- def getObjectListBySearchParameter(self, searchParameter, minTimestamp, limit):
- """Returns an array of the latest packet objects specified by searchParameter
-
- Args:
- searchParameter (str): String to use when searching for packets (will be compared to station name)
- minTimestamp (int): Min unix timestamp
- limit (int): Max number of hits
-
- Returns:
- Array
- """
- searchParameter = searchParameter.strip().replace('%', '\%').replace('*', '%')
- selectCursor = self.db.cursor()
- result = []
-
- # Search for ogn registration
- if (self.dbObjectFinder.checkTableExists('ogn_device')):
- selectCursor.execute("""select * from ogn_device limit 1""")
- record = selectCursor.fetchone()
- if (record is not None):
- selectCursor.execute("""select * from station where latest_confirmed_packet_timestamp is not null and latest_confirmed_packet_timestamp > %s and latest_ogn_sender_address is not null and exists (select 1 from ogn_device where registration ilike %s and device_id = station.latest_ogn_sender_address) limit %s""", (minTimestamp, searchParameter, (limit - len(result)), ))
- for record in selectCursor:
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- # Search for ogn sender address
- if (len(result) < limit):
- selectCursor.execute("""select * from station where latest_confirmed_packet_timestamp is not null and latest_confirmed_packet_timestamp > %s and latest_ogn_sender_address ilike %s limit %s""",
- (minTimestamp, searchParameter, (limit - len(result)), ))
- for record in selectCursor:
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- # Search for station name
- if (len(result) < limit):
- selectCursor.execute("""select * from station where latest_confirmed_packet_timestamp is not null and latest_confirmed_packet_timestamp > %s and name ilike %s limit %s""",
- (minTimestamp, searchParameter, (limit - len(result)), ))
- for record in selectCursor:
- dbObject = self.getObjectFromRecord(record)
- result.append(dbObject)
-
- return result
-
- def getCachedObjectById(self, stationId):
- """Get Station based on station id
-
- Args:
- stationId (int): Id of the station
-
- Returns:
- Station
- """
- if (stationId not in StationRepository.stationIdCache):
- station = self.getObjectById(stationId)
- if (station.isExistingObject()):
- maxNumberOfStations = 100
- if (len(StationRepository.stationIdCache) > maxNumberOfStations):
- # reset cache
- StationRepository.stationIdCache = {}
- StationRepository.stationIdCache[stationId] = station
- return station
- else:
- try:
- return StationRepository.stationIdCache[stationId]
- except KeyError as e:
- station = self.getObjectById(stationId)
- if (station.isExistingObject()):
- return station
- raise TrackDirectMissingStationError(
- 'No station with specified id found')
-
- def getCachedObjectByName(self, stationName, sourceId):
- """Get Station based on station name
-
- Args:
- stationName (string): Station name
- sourceId (int): Station source id
-
- Returns:
- Station
- """
- if (sourceId == 3):
- # If source is "APRS DUPLICATE" we use "APRS"
- sourceId = 1
-
- if (sourceId is not None):
- key = hash(stationName + ';' + str(sourceId))
- else:
- key = hash(stationName)
- if (key not in StationRepository.stationNameCache):
- station = self.getObjectByName(stationName, sourceId, None, False)
- if (station.isExistingObject()):
- maxNumberOfStations = 100
- if (len(StationRepository.stationNameCache) > maxNumberOfStations):
- # reset cache
- StationRepository.stationNameCache = {}
- StationRepository.stationNameCache[key] = station
- return station
- else:
- try:
- return StationRepository.stationNameCache[key]
- except KeyError as e:
- station = self.getObjectByName(
- stationName, sourceId, None, False)
- if (station.isExistingObject()):
- return station
- raise TrackDirectMissingStationError(
- 'No station with specified station name found')
-
- def getObjectFromRecord(self, record):
- """Returns a station object based on the specified database record dict
-
- Args:
- record (dict): A database record dict from the station database table
-
- Returns:
- Station
- """
- dbObject = self.create()
- if (record is not None):
- dbObject.id = int(record["id"])
- dbObject.name = record["name"]
- if (record["latest_sender_id"] is not None):
- dbObject.latestSenderId = int(record["latest_sender_id"])
- dbObject.stationTypeId = int(record["station_type_id"])
- if (record["source_id"] is not None):
- dbObject.sourceId = int(record["source_id"])
-
- dbObject.latestLocationPacketId = record["latest_location_packet_id"]
- dbObject.latestLocationPacketTimestamp = record["latest_location_packet_timestamp"]
-
- dbObject.latestConfirmedPacketId = record["latest_confirmed_packet_id"]
- dbObject.latestConfirmedPacketTimestamp = record["latest_confirmed_packet_timestamp"]
- dbObject.latestConfirmedSymbol = record["latest_confirmed_symbol"]
- dbObject.latestConfirmedSymbolTable = record["latest_confirmed_symbol_table"]
- dbObject.latestConfirmedLatitude = record["latest_confirmed_latitude"]
- dbObject.latestConfirmedLongitude = record["latest_confirmed_longitude"]
- dbObject.latestConfirmedMarkerId = record["latest_confirmed_marker_id"]
-
- dbObject.latestPacketId = record["latest_packet_id"]
- dbObject.latestPacketTimestamp = record["latest_packet_timestamp"]
-
- dbObject.latestWeatherPacketId = record["latest_weather_packet_id"]
- dbObject.latestWeatherPacketTimestamp = record["latest_weather_packet_timestamp"]
-
- dbObject.latestTelemetryPacketId = record["latest_telemetry_packet_id"]
- dbObject.latestTelemetryPacketTimestamp = record["latest_telemetry_packet_timestamp"]
-
- dbObject.latestOgnPacketId = record["latest_ogn_packet_id"]
- dbObject.latestOgnPacketTimestamp = record["latest_ogn_packet_timestamp"]
- dbObject.latestOgnSenderAddress = record["latest_ogn_sender_address"]
- dbObject.latestOgnAircraftTypeId = record["latest_ogn_aircraft_type_id"]
- dbObject.latestOgnAddressTypeId = record["latest_ogn_address_type_id"]
-
- return dbObject
-
- def create(self):
- """Creates an empty Station object
-
- Returns:
- Station
- """
- return Station(self.db)
diff --git a/server/trackdirect/repositories/StationTelemetryBitsRepository.py b/server/trackdirect/repositories/StationTelemetryBitsRepository.py
deleted file mode 100644
index 50dd87ec7f491935d1bc638a2e6e39932b603ea2..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/StationTelemetryBitsRepository.py
+++ /dev/null
@@ -1,75 +0,0 @@
-import datetime
-import time
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.StationTelemetryBits import StationTelemetryBits
-
-
-class StationTelemetryBitsRepository(Repository):
- """A Repository class for the StationTelemetryBits class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- StationTelemetryBits
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from station_telemetry_bits where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.stationId = record["station_id"]
- dbObject.createdTs = record["created_ts"]
- dbObject.latestTs = record["latest_ts"]
- dbObject.validToTs = record["valid_to_ts"]
- dbObject.bits = record["bits"]
- dbObject.title = record["title"]
- else:
- # do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- StationTelemetryBits
- """
- newObject = self.create()
- if ("tBITS" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.createdTs = int(time.time()) - 1
- newObject.bits = data["tBITS"].replace('\x00', '')
- newObject.title = data["title"].replace('\x00', '')
- return newObject
-
- def create(self):
- """Creates an empty StationTelemetryBits object
-
- Returns:
- StationTelemetryBits
- """
- return StationTelemetryBits(self.db)
diff --git a/server/trackdirect/repositories/StationTelemetryEqnsRepository.py b/server/trackdirect/repositories/StationTelemetryEqnsRepository.py
deleted file mode 100644
index 40df56f53234b865ae70b00f8f213834bcedc8bc..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/StationTelemetryEqnsRepository.py
+++ /dev/null
@@ -1,106 +0,0 @@
-import datetime
-import time
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.StationTelemetryEqns import StationTelemetryEqns
-
-
-class StationTelemetryEqnsRepository(Repository):
- """A Repository class for the StationTelemetryEqns class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- StationTelemetryEqns
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from station_telemetry_eqns where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.stationId = record["station_id"]
- dbObject.createdTs = record["created_ts"]
- dbObject.latestTs = record["latest_ts"]
- dbObject.validToTs = record["valid_to_ts"]
- dbObject.a1 = record["a1"]
- dbObject.b1 = record["b1"]
- dbObject.c1 = record["c1"]
- dbObject.a2 = record["a2"]
- dbObject.b2 = record["b2"]
- dbObject.c2 = record["c2"]
- dbObject.a3 = record["a3"]
- dbObject.b3 = record["b3"]
- dbObject.c3 = record["c3"]
- dbObject.a4 = record["a4"]
- dbObject.b4 = record["b4"]
- dbObject.c4 = record["c4"]
- dbObject.a5 = record["a5"]
- dbObject.b5 = record["b5"]
- dbObject.c5 = record["c5"]
- else:
- # do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- StationTelemetryEqns
- """
- newObject = self.create()
- if ("tEQNS" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.createdTs = int(time.time()) - 1
-
- newObject.a1 = data["tEQNS"][0][0]
- newObject.b1 = data["tEQNS"][0][1]
- newObject.c1 = data["tEQNS"][0][2]
-
- newObject.a2 = data["tEQNS"][1][0]
- newObject.b2 = data["tEQNS"][1][1]
- newObject.c2 = data["tEQNS"][1][2]
-
- newObject.a3 = data["tEQNS"][2][0]
- newObject.b3 = data["tEQNS"][2][1]
- newObject.c3 = data["tEQNS"][2][2]
-
- newObject.a4 = data["tEQNS"][3][0]
- newObject.b4 = data["tEQNS"][3][1]
- newObject.c4 = data["tEQNS"][3][2]
-
- newObject.a5 = data["tEQNS"][4][0]
- newObject.b5 = data["tEQNS"][4][1]
- newObject.c5 = data["tEQNS"][4][2]
- return newObject
-
- def create(self):
- """Creates an empty StationTelemetryEqns object
-
- Returns:
- StationTelemetryEqns
- """
- return StationTelemetryEqns(self.db)
diff --git a/server/trackdirect/repositories/StationTelemetryParamRepository.py b/server/trackdirect/repositories/StationTelemetryParamRepository.py
deleted file mode 100644
index 39679954b6ff1b2ef6aac9c5d18e9e71f4ea13c9..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/StationTelemetryParamRepository.py
+++ /dev/null
@@ -1,97 +0,0 @@
-import datetime
-import time
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.StationTelemetryParam import StationTelemetryParam
-
-
-class StationTelemetryParamRepository(Repository):
- """A Repository class for the StationTelemetryParam class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- StationTelemetryParam
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from station_telemetry_param where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.stationId = record["station_id"]
- dbObject.createdTs = record["created_ts"]
- dbObject.latestTs = record["latest_ts"]
- dbObject.validToTs = record["valid_to_ts"]
- dbObject.p1 = record["p1"]
- dbObject.p2 = record["p2"]
- dbObject.p3 = record["p3"]
- dbObject.p4 = record["p4"]
- dbObject.p5 = record["p5"]
- dbObject.b1 = record["b1"]
- dbObject.b2 = record["b2"]
- dbObject.b3 = record["b3"]
- dbObject.b4 = record["b4"]
- dbObject.b5 = record["b5"]
- dbObject.b6 = record["b6"]
- dbObject.b7 = record["b7"]
- dbObject.b8 = record["b8"]
- else:
- # do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- StationTelemetryParam
- """
- newObject = self.create()
- if ("tPARM" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.createdTs = int(time.time()) - 1
- newObject.p1 = data["tPARM"][0].replace('\x00', '')
- newObject.p2 = data["tPARM"][1].replace('\x00', '')
- newObject.p3 = data["tPARM"][2].replace('\x00', '')
- newObject.p4 = data["tPARM"][3].replace('\x00', '')
- newObject.p5 = data["tPARM"][4].replace('\x00', '')
- newObject.b1 = data["tPARM"][5].replace('\x00', '')
- newObject.b2 = data["tPARM"][6].replace('\x00', '')
- newObject.b3 = data["tPARM"][7].replace('\x00', '')
- newObject.b4 = data["tPARM"][8].replace('\x00', '')
- newObject.b5 = data["tPARM"][9].replace('\x00', '')
- newObject.b6 = data["tPARM"][10].replace('\x00', '')
- newObject.b7 = data["tPARM"][11].replace('\x00', '')
- newObject.b8 = data["tPARM"][12].replace('\x00', '')
- return newObject
-
- def create(self):
- """Creates an empty StationTelemetryParam object
-
- Returns:
- StationTelemetryParam
- """
- return StationTelemetryParam(self.db)
diff --git a/server/trackdirect/repositories/StationTelemetryUnitRepository.py b/server/trackdirect/repositories/StationTelemetryUnitRepository.py
deleted file mode 100644
index 5ae6a4c8bb57f2f5a3decb83c49d5568921383a2..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/StationTelemetryUnitRepository.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import datetime
-import time
-from trackdirect.common.Repository import Repository
-from trackdirect.objects.StationTelemetryUnit import StationTelemetryUnit
-
-
-class StationTelemetryUnitRepository(Repository):
- """A Repository class for the StationTelemetryUnit class
- """
-
- def __init__(self, db):
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
-
- def getObjectById(self, id):
- """The getObjectById method is supposed to return an object based on the specified id in database
-
- Args:
- id (int): Database row id
-
- Returns:
- StationTelemetryUnit
- """
- selectCursor = self.db.cursor()
- selectCursor.execute(
- """select * from station_telemetry_unit where id = %s""", (id,))
- record = selectCursor.fetchone()
-
- dbObject = self.create()
- if (record is not None):
- dbObject.id = record["id"]
- dbObject.stationId = record["station_id"]
- dbObject.createdTs = record["created_ts"]
- dbObject.latestTs = record["latest_ts"]
- dbObject.validToTs = record["valid_to_ts"]
- dbObject.u1 = record["u1"]
- dbObject.u2 = record["u2"]
- dbObject.u3 = record["u3"]
- dbObject.u4 = record["u4"]
- dbObject.u5 = record["u5"]
- dbObject.l1 = record["l1"]
- dbObject.l2 = record["l2"]
- dbObject.l3 = record["l3"]
- dbObject.l4 = record["l4"]
- dbObject.l5 = record["l5"]
- dbObject.l6 = record["l6"]
- dbObject.l7 = record["l7"]
- dbObject.l8 = record["l8"]
- else:
- # do not exists, return empty object
- pass
-
- selectCursor.close()
- return dbObject
-
- def getObjectFromPacketData(self, data):
- """Create object from raw packet data
-
- Note:
- stationId will not be set
-
- Args:
- data (dict): Raw packet data
-
- Returns:
- StationTelemetryUnit
- """
- newObject = self.create()
- if ("tUNIT" in data):
- # Remove one second since that will give us a more accurate timestamp
- newObject.createdTs = int(time.time()) - 1
-
- newObject.u1 = data["tUNIT"][0].replace('\x00', '')
- newObject.u2 = data["tUNIT"][1].replace('\x00', '')
- newObject.u3 = data["tUNIT"][2].replace('\x00', '')
- newObject.u4 = data["tUNIT"][3].replace('\x00', '')
- newObject.u5 = data["tUNIT"][4].replace('\x00', '')
- newObject.l1 = data["tUNIT"][5].replace('\x00', '')
- newObject.l2 = data["tUNIT"][6].replace('\x00', '')
- newObject.l3 = data["tUNIT"][7].replace('\x00', '')
- newObject.l4 = data["tUNIT"][8].replace('\x00', '')
- newObject.l5 = data["tUNIT"][9].replace('\x00', '')
- newObject.l6 = data["tUNIT"][10].replace('\x00', '')
- newObject.l7 = data["tUNIT"][11].replace('\x00', '')
- newObject.l8 = data["tUNIT"][12].replace('\x00', '')
-
- return newObject
-
- def create(self):
- """Creates an empty StationTelemetryUnit object
-
- Returns:
- StationTelemetryUnit
- """
- return StationTelemetryUnit(self.db)
diff --git a/server/trackdirect/repositories/__init__.py b/server/trackdirect/repositories/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/repositories/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/websocket/WebsocketConnectionState.py b/server/trackdirect/websocket/WebsocketConnectionState.py
deleted file mode 100644
index 2b7837208b0336d405b2b5ba1c26a77d0055a484..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/WebsocketConnectionState.py
+++ /dev/null
@@ -1,369 +0,0 @@
-import time
-import trackdirect
-from math import ceil
-from trackdirect.parser.policies.MapSectorPolicy import MapSectorPolicy
-
-class WebsocketConnectionState():
- """An WebsocketConnectionState instance contains information about the current state of a websocket connection
- """
-
- def __init__(self) :
- """The __init__ method.
- """
- self.totalReset()
- self.latestRequestType = None
- self.latestRequestTimestamp = 0
- self.latestRequestId = 0
- self.latestHandledRequestId = 0
- self.config = trackdirect.TrackDirectConfig()
- self.noRealTime = False
- self.disconnected = False
-
-
- def isReset(self) :
- """Returns true if state just has been reset
-
- Returns:
- Boolean
- """
- return (not self.stationsOnMapDict
- and not self.maxCompleteStationTimestampDict
- and not self.maxAllStationTimestampDict
- and not self.maxMapSectorPacketTimestampDict
- and not self.maxMapSectorOverwritePacketTimestampDict)
-
-
- def reset(self) :
- """This function will reset information related to what stations that has been added to map
- (this is for example used when the number of minutes is changed by the client)
- """
- self.stationsOnMapDict = {}
- self.maxCompleteStationTimestampDict = {}
- self.maxAllStationTimestampDict = {}
- self.maxMapSectorPacketTimestampDict = {}
- self.maxMapSectorOverwritePacketTimestampDict = {}
-
-
- def totalReset(self) :
- """This function will reset everything
- (this is for example used when client seems to be inactive and we just want to stop everything)
- """
- self.reset()
- self.latestMinutesRequest = 60
- self.latestTimeTravelRequest = None
- self.onlyLatestPacketRequested = None
- self.latestNeLat = 0
- self.latestNeLng = 0
- self.latestSwLat = 0
- self.latestSwLng = 0
- self.filterStationIdDict = {}
-
-
- def isMapEmpty(self) :
- """Returns true if map is empty
-
- Returns:
- Boolean
- """
- if (not self.maxMapSectorPacketTimestampDict
- and not self.maxMapSectorOverwritePacketTimestampDict
- and not self.maxCompleteStationTimestampDict
- and not self.maxAllStationTimestampDict) :
- return True
- else :
- return False
-
-
- def isStationsOnMap(self, stationIds) :
- """Returns true if all specified stations allready exists on map
-
- Args:
- stationIds (int): The station id's that we are interested in
-
- Returns:
- boolean
- """
- for stationId in stationIds :
- if (stationId not in self.stationsOnMapDict) :
- return False
- return True
-
-
- def isStationHistoryOnMap(self, stationId) :
- """Returns true if specified station allready has it's history on map
-
- Args:
- stationId (int): The station id that we are interested in
-
- Returns:
- boolean
- """
- if (stationId not in self.maxCompleteStationTimestampDict) :
- return False
- else :
- return True
-
-
- def getStationLatestTimestampOnMap(self, stationId, onlyIncludeComplete = True) :
- """Returns the timestamp of the latest sent packet to client
-
- Args:
- stationId (int): The station id that we are interested in
- onlyIncludeComplete (bool): When true we only return timestamp data for complete stations
-
- Returns:
- boolean
- """
- if (not onlyIncludeComplete and stationId in self.maxAllStationTimestampDict) :
- return self.maxAllStationTimestampDict[stationId]
- elif (stationId in self.maxCompleteStationTimestampDict) :
- return self.maxCompleteStationTimestampDict[stationId]
- else :
- return None
-
-
- def isValidLatestPosition(self) :
- """Returns true if latest requested map bounds is valid
-
- Note:
- If we received 0,0,0,0 as map bounds we should not send anything,
- not even in filtering mode (filtering mode should send 90,180,-90,-180 when it wants data)
-
- Returns:
- Boolean
- """
- if (self.latestNeLat == 0
- and self.latestNeLng == 0
- and self.latestSwLat == 0
- and self.latestSwLng == 0) :
- return False
- else :
- return True
-
-
- def isMapSectorKnown(self, mapSector):
- """Returns True if we have added any stations with complete history to this map sector
-
- Args:
- mapSector (int): The map sector that we are interested in
-
- Returns:
- Boolean
- """
- if (mapSector in self.maxMapSectorPacketTimestampDict) :
- return True
- else :
- return False
-
-
- def getMapSectorTimestamp(self, mapSector) :
- """Returns the latest handled timestamp in specified map sector (as a Unix timestamp as an integer)
-
- Args:
- mapSector (int): The map sector that we are interested in
-
- Returns:
- int
- """
- if (mapSector in self.maxMapSectorPacketTimestampDict) :
- return self.maxMapSectorPacketTimestampDict[mapSector];
- elif (self.onlyLatestPacketRequested and mapSector in self.maxMapSectorOverwritePacketTimestampDict) :
- return self.maxMapSectorOverwritePacketTimestampDict[mapSector]
- elif (self.latestTimeTravelRequest is not None) :
- return int(self.latestTimeTravelRequest) - (int(self.latestMinutesRequest)*60)
- else :
- return int(time.time()) - (int(self.latestMinutesRequest)*60)
-
-
- def getVisibleMapSectors(self) :
- """Get the map sectors currently visible
-
- Returns:
- Array of map sectors (array of integers)
- """
- maxLat = self.latestNeLat
- maxLng = self.latestNeLng
- minLat = self.latestSwLat
- minLng = self.latestSwLng
-
- result = []
- if (maxLng < minLng) :
- result.extend(self.getMapSectorsByInterval(minLat, maxLat, minLng, 180.0));
- minLng = -180.0;
-
- result.extend(self.getMapSectorsByInterval(minLat, maxLat, minLng, maxLng))
-
- # Add the world wide area code
- # This seems to result in very bad performance....
- #result.append(99999999)
-
- return result[::-1]
-
-
- def getMapSectorsByInterval(self, minLat, maxLat, minLng, maxLng) :
- """Get the map sectors for specified interval
-
- Returns:
- Array of map sectors (array of integers)
- """
- result = []
- mapSectorPolicy = MapSectorPolicy()
- minAreaCode = mapSectorPolicy.getMapSector(minLat,minLng)
- maxAreaCode = mapSectorPolicy.getMapSector(maxLat,maxLng)
- if (minAreaCode is not None and maxAreaCode is not None) :
- lngDiff = int(ceil(maxLng)) - int(ceil(minLng))
- areaCode = minAreaCode
- while (areaCode <= maxAreaCode) :
- if (areaCode % 10 == 5) :
- result.append(areaCode)
- else :
- result.append(areaCode)
- result.append(areaCode + 5)
-
- for i in range(1, lngDiff+1) :
- if (areaCode % 10 == 5) :
- result.append(areaCode + (10*i) - 5)
- result.append(areaCode + (10*i))
- else :
- result.append(areaCode + (10*i))
- result.append(areaCode + (10*i) + 5)
-
- # Lat takes 0.2 jumps
- areaCode = areaCode + 20000
-
- return result
-
-
- def setLatestMinutes(self, minutes, referenceTime) :
- """Set the latest requested number of minutes, returnes true if something has changed
-
- Args:
- minutes (int): latest requested number of minutes
- referenceTime (int): latest requested reference time
-
- Returns:
- Boolean
- """
- if (minutes is None) :
- minutes = 60
- elif (len(self.filterStationIdDict) == 0
- and int(minutes) > int(self.config.maxDefaultTime)) :
- # max 24h
- minutes = int(self.config.maxDefaultTime)
- elif (len(self.filterStationIdDict) > 0
- and int(minutes) > int(self.config.maxFilterTime)) :
- # max 10 days
- minutes = int(self.config.maxFilterTime)
-
- if (not self.config.allowTimeTravel
- and int(minutes) > int(1440)) :
- # max 24h
- minutes = 1440
-
- if referenceTime is not None and referenceTime < 0 :
- referenceTime = 0
-
- changed = False
- if (self.config.allowTimeTravel) :
- if ((self.latestTimeTravelRequest is not None
- and referenceTime is not None
- and self.latestTimeTravelRequest != referenceTime)
- or (self.latestTimeTravelRequest is not None
- and referenceTime is None)
- or (self.latestTimeTravelRequest is None
- and referenceTime is not None)) :
- self.latestTimeTravelRequest = referenceTime
- self.reset()
- changed = True
-
- if (self.latestMinutesRequest is None
- or self.latestMinutesRequest != minutes) :
- self.latestMinutesRequest = minutes
- self.reset()
- changed = True
- return changed
-
-
- def setOnlyLatestPacketRequested(self, onlyLatestPacketRequested) :
- """Set if only latest packets is requested or not
-
- Args:
- onlyLatestPacketRequested (Boolean): Boolean that sys if
-
- """
- self.onlyLatestPacketRequested = onlyLatestPacketRequested
-
-
- def setLatestMapBounds(self, neLat, neLng, swLat, swLng) :
- """Set map bounds requested by client
-
- Args:
- neLat (float): Requested north east latitude
- neLng (float): Requested north east longitude
- swLat (float): Requested south west latitude
- swLng (float): Requested south west longitude
- """
- if (neLat is None or neLng is None or swLat is None or swLng is None) :
- self.latestNeLat = 0
- self.latestNeLng = 0
- self.latestSwLat = 0
- self.latestSwLng = 0
- else :
- self.latestNeLat = neLat
- self.latestNeLng = neLng
- self.latestSwLat = swLat
- self.latestSwLng = swLng
-
-
- def setMapSectorLatestOverwriteTimeStamp(self, mapSector, timestamp) :
- """Set a new latest handled timestamp for a map sector (in this case the overwritable type of packets)
-
- Args:
- mapSector (int): The map sector that we should add a new timestamp to
- timestamp (int): The unix timestamp that should be added
- """
- if (mapSector not in self.maxMapSectorOverwritePacketTimestampDict or self.maxMapSectorOverwritePacketTimestampDict[mapSector] < timestamp) :
- self.maxMapSectorOverwritePacketTimestampDict[mapSector] = timestamp
-
-
- def setMapSectorLatestTimeStamp(self, mapSector, timestamp) :
- """Set a new latest handled timestamp for a map sector
-
- Args:
- mapSector (int): The map sector that we should add a new timestamp to
- timestamp (int): The unix timestamp that should be added
- """
- if (mapSector not in self.maxMapSectorPacketTimestampDict or self.maxMapSectorPacketTimestampDict[mapSector] < timestamp) :
- # To avoid that we miss packet that was recived later during the same second we mark map-sector to be complete for the previous second.
- # This may result in that we sent the same apcket twice but client will handle that.
- self.maxMapSectorPacketTimestampDict[mapSector] = timestamp - 1
-
-
- def setCompleteStationLatestTimestamp(self, stationId, timestamp) :
- """Set a new latest handled timestamp for a complete station (a station with all packets added to map)
-
- Args:
- stationId (int): The station that we add want to add a new timestamp for
- timestamp (int): The unix timestamp that should be added
- """
- if (stationId not in self.maxCompleteStationTimestampDict or self.maxCompleteStationTimestampDict[stationId] < timestamp) :
- # For stations we do not need to set the previous second since a station is rarly sending several packets the same second
- self.maxCompleteStationTimestampDict[stationId] = timestamp
-
-
- def setStationLatestTimestamp(self, stationId, timestamp) :
- """Set a new latest handled timestamp for station
-
- Args:
- stationId (int): The station that we add want to add a new timestamp for
- timestamp (int): The unix timestamp that should be added
- """
- if (stationId not in self.maxAllStationTimestampDict or self.maxAllStationTimestampDict[stationId] < timestamp) :
- # For stations we do not need to set the previous second since a station is rarly sending several packets the same second
- self.maxAllStationTimestampDict[stationId] = timestamp
-
-
- def disableRealTime(self) :
- """Disable real time functionality
- """
- self.noRealTime = True
\ No newline at end of file
diff --git a/server/trackdirect/websocket/WebsocketResponseCreator.py b/server/trackdirect/websocket/WebsocketResponseCreator.py
deleted file mode 100644
index a572edc809adfa7715632c000afee97c2313eff7..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/WebsocketResponseCreator.py
+++ /dev/null
@@ -1,91 +0,0 @@
-import logging
-from twisted.python import log
-
-from math import floor, ceil
-import datetime, time
-
-import psycopg2, psycopg2.extras
-
-from trackdirect.websocket.responses.FilterResponseCreator import FilterResponseCreator
-from trackdirect.websocket.responses.HistoryResponseCreator import HistoryResponseCreator
-from trackdirect.websocket.responses.FilterHistoryResponseCreator import FilterHistoryResponseCreator
-
-class WebsocketResponseCreator():
- """The WebsocketResponseCreator will make sure that we create a response for every valid received request
- """
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): WebsocketConnectionState instance that contains current state
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
-
- self.logger = logging.getLogger('trackdirect')
-
- self.filterResponseCreator = FilterResponseCreator(state, db)
- self.historyResponseCreator = HistoryResponseCreator(state, db)
- self.filterHistoryResponseCreator = FilterHistoryResponseCreator(state, db)
-
- def getResponses(self, request, requestId) :
- """Process a received request
-
- Args:
- request (dict): The request to process
- requestId (int): Request id of processed request
-
- Returns:
- generator
- """
- try:
- if (self.state.isReset()) :
- yield self._getResetResponse()
-
- if (request["payload_request_type"] == 1 or request["payload_request_type"] == 11) :
- yield self._getLoadingResponse()
- if (len(self.state.filterStationIdDict) > 0) :
- response = self.filterHistoryResponseCreator.getResponse()
- if (response is not None) :
- yield response
- else :
- for response in self.historyResponseCreator.getResponses(request, requestId) :
- yield response
-
- elif (request["payload_request_type"] == 7) :
- # Update request for single station
- for response in self.historyResponseCreator.getResponses(request, requestId) :
- yield response
-
- elif (request["payload_request_type"] in [4, 6, 8]) :
- yield self._getLoadingResponse()
- for response in self.filterResponseCreator.getResponses(request) :
- yield response
-
- else :
- self.logger.error('Request is not supported')
- self.logger.error(request)
-
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- def _getLoadingResponse(self) :
- """This method creates a loading response
-
- Returns:
- Dict
- """
- return {'payload_response_type': 32}
-
- def _getResetResponse(self) :
- """This method creates a reset response
-
- Returns:
- Dict
- """
- payload = {'payload_response_type': 40}
- return payload
diff --git a/server/trackdirect/websocket/__init__.py b/server/trackdirect/websocket/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/websocket/aprsis/AprsISPayloadCreator.py b/server/trackdirect/websocket/aprsis/AprsISPayloadCreator.py
deleted file mode 100644
index 6f1158eb0d9ce4ef5b00bd8cacbb3c30cf17218f..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/aprsis/AprsISPayloadCreator.py
+++ /dev/null
@@ -1,175 +0,0 @@
-import logging
-
-import time
-
-import aprslib
-
-from trackdirect.parser.AprsPacketParser import AprsPacketParser
-
-
-import trackdirect
-
-from trackdirect.exceptions.TrackDirectParseError import TrackDirectParseError
-
-from trackdirect.websocket.responses.ResponseDataConverter import ResponseDataConverter
-from trackdirect.websocket.responses.HistoryResponseCreator import HistoryResponseCreator
-
-
-class AprsISPayloadCreator():
- """The AprsISPayloadCreator creates a payload to send to client based on data received form the APRS-IS server
- """
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (ConnectionState): Instance of ConnectionState which contains the current state of the connection
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.logger = logging.getLogger('trackdirect')
- self.state = state
- self.db = db
- self.responseDataConverter = ResponseDataConverter(state, db)
- self.historyResponseCreator = HistoryResponseCreator(state, db)
- self.config = trackdirect.TrackDirectConfig()
- self.stationHashTimestamps = {}
-
- self.saveOgnStationsWithMissingIdentity = False
- if (self.config.saveOgnStationsWithMissingIdentity) :
- self.saveOgnStationsWithMissingIdentity = True
-
-
- def getPayloads(self, line, sourceId):
- """Takes a raw packet and returnes a dict with the parsed result
-
- Args:
- line (string): The raw packet as a string
- sourceId (int): The id of the source
-
- Returns:
- generator
- """
- try :
- packet = self._parse(line, sourceId)
- if (not self._isPacketValid(packet)) :
- return
-
- if (packet.stationId not in self.state.stationsOnMapDict) :
- self.state.stationsOnMapDict[packet.stationId] = True
-
- if (len(self.state.filterStationIdDict) > 0 and packet.stationId in self.state.filterStationIdDict) :
- for response in self._getPreviousPacketsPayload(packet):
- yield response
-
- yield self._getRealTimePacketPayload(packet)
- except (aprslib.ParseError, aprslib.UnknownFormat, TrackDirectParseError) as exp:
- # We could send the raw part even if we failed to parse it...
- pass
- except (UnicodeDecodeError) as exp:
- # just forget about this packet
- pass
-
-
- def _parse(self, line, sourceId) :
- """Parse packet raw
-
- Args:
- line (string): The raw packet as a string
- sourceId (int): The id of the source
-
- Returns:
- Packet
- """
- basicPacketDict = aprslib.parse(line)
- parser = AprsPacketParser(self.db, self.saveOgnStationsWithMissingIdentity)
- parser.setDatabaseWriteAccess(False)
- parser.setSourceId(sourceId)
- try :
- packet = parser.getPacket(basicPacketDict)
- if (packet.mapId == 15) :
- return None
-
- if (packet.mapId == 4) :
- # Looks like we don't have enough info in db to get a markerId, wait some and try again
- time.sleep(1)
- return parser.getPacket(basicPacketDict)
-
- return packet
- except (aprslib.ParseError, aprslib.UnknownFormat, TrackDirectParseError) as exp:
- return None
-
-
- def _isPacketValid(self, packet) :
- """Returns True if specified packet is valid to send to client
-
- Args:
- packet (Packet): Found packet that we may want to send to client
-
- Returns:
- True if specified packet is valid to send to client
- """
- if (packet is None) :
- return False
-
- if (packet.mapId == 4) :
- return False
-
- if (packet.stationId is None) :
- return False
-
- if (packet.markerId is None or packet.markerId == 1) :
- return False
-
- if (packet.latitude is None or packet.longitude is None) :
- return False
-
- if (len(self.state.filterStationIdDict) > 0) :
- if (packet.stationId not in self.state.filterStationIdDict) :
- # This packet does not belong to the station Id that the user is filtering on
- return False
- return True
-
-
- def _getRealTimePacketPayload(self, packet) :
- """Takes a packet received directly from APRS-IS and a creates a payload response
-
- Args:
- packet (Packet): The packet direclty received from APRS-IS
-
- Returns:
- Dict
- """
- options = ["realtime"]
- data = self.responseDataConverter.getResponseData([packet], None, options)
- payload = {'payload_response_type': 2, 'data': data}
- return payload
-
-
- def _getPreviousPacketsPayload(self, packet) :
- """Creates payload that contains previous packets for the station that has sent the specified packet
-
- Args:
- packet (Packet): The packet direclty received from APRS-IS
-
- Returns:
- generator
- """
- latestTimestampOnMap = self.state.getStationLatestTimestampOnMap(packet.stationId)
- if (latestTimestampOnMap is None) :
- latestTimestampOnMap = 0
- latestTimestampOnMap = latestTimestampOnMap + 5
- if (self.state.isStationHistoryOnMap(packet.stationId)
- and packet.markerPrevPacketTimestamp is not None
- and packet.timestamp > latestTimestampOnMap
- and packet.markerPrevPacketTimestamp > latestTimestampOnMap) :
- # Ups! We got a problem, the previous packet for this station has not been sent to client
- # If no packets at all had been sent we would have marked the realtime-packet to be overwritten,
- # but now we have a missing packet from current station that may never be sent!
- # Send it now! This may result in that we send the same packet twice (but client should handle that)
- request = {}
- request["station_id"] = packet.stationId
- request["payload_request_type"] = 7
-
- # This request will send all packets that is missing (maybe also this real-time packet, but we can live with that...)
- for response in self.historyResponseCreator.getResponses(request, None) :
- yield response
diff --git a/server/trackdirect/websocket/aprsis/AprsISReader.py b/server/trackdirect/websocket/aprsis/AprsISReader.py
deleted file mode 100644
index a5be779c2b23bd221f376f3d6808b5401747c912..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/aprsis/AprsISReader.py
+++ /dev/null
@@ -1,174 +0,0 @@
-import logging
-import trackdirect
-
-from trackdirect.parser.AprsISConnection import AprsISConnection
-from trackdirect.repositories.SenderRepository import SenderRepository
-
-class AprsISReader():
- """The AprsISReader class will connect to a APRS-IS server and listen for APRS-packets
- """
-
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (ConnectionState): Instance of ConnectionState which contains the current state of the connection
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
- self.latestRealTimeFilter = None
-
- self.senderRepository = SenderRepository(db)
-
- self.aprsISConnection1 = None
- self.aprsISConnection2 = None
-
- self.logger = logging.getLogger('trackdirect')
- self.config = trackdirect.TrackDirectConfig()
-
-
- def start(self):
- """Connect to APRS-IS servers based on current state
- """
- self._connect()
- self._modifyFilter()
-
-
- def read(self, callback) :
- """Read data from the APRS-IS servers, specified callback will be called once for every waiting packet
-
- Args:
- callback (method): Method to call when we read a packet from the APRS IS connection
-
- Note:
- Callback function is expecting to take 2 arguments, the "packet raw" as a string and a "source id" as an integer
- """
- try :
- if (self.aprsISConnection1 is not None or self.aprsISConnection2 is not None) :
- def aprsISCallback1(line) :
- callback(line, self.config.websocketAprsSourceId1)
-
- def aprsISCallback2(line) :
- callback(line, self.config.websocketAprsSourceId2)
-
- if (self.aprsISConnection2 is not None) :
- self.aprsISConnection2.filteredConsumer(aprsISCallback2, False, True)
-
- if (self.aprsISConnection1 is not None) :
- self.aprsISConnection1.filteredConsumer(aprsISCallback1, False, True)
- except IOError as e:
- callback(None, None)
- except Exception as e:
- self.logger.error(e, exc_info=1)
- callback(None, None)
-
-
- def pause(self) :
- """Pause without closing the aprsISConnection, we just set filter to nothing, that will result in no received packets
- """
- if (self.aprsISConnection1 is not None) :
- self.latestRealTimeFilter = None
- self.aprsISConnection1.set_filter('')
-
- if (self.aprsISConnection2 is not None) :
- self.latestRealTimeFilter = None
- self.aprsISConnection2.set_filter('')
-
-
- def stop(self):
- """Kill the connections to the APRS-IS servers
- """
- if (self.aprsISConnection2 is not None) :
- self.aprsISConnection2.close()
- self.aprsISConnection2 = None
-
- if (self.aprsISConnection1 is not None) :
- self.aprsISConnection1.close()
- self.aprsISConnection1 = None
-
-
- def clear(self, limit = None):
- """Clear the socket from all waiting lines
-
- Args:
- limit (int): Max number of packets to clear (per connection)
- """
- counter1 = 0
- counter2 = 0
- if (self.aprsISConnection2 is not None) :
- for line in self.aprsISConnection1._socket_readlines(False):
- counter1 += 1
- if (limit is not None and counter1 >= limit) :
- break
- if (self.aprsISConnection1 is not None) :
- for line in self.aprsISConnection1._socket_readlines(False):
- counter2 += 1
- if (limit is not None and counter2 >= limit) :
- break
- return counter1 + counter2
-
-
- def _connect(self):
- """Connect to APRS-IS servers (if not allready connected)
- """
- if (self.aprsISConnection1 is None) :
- self.latestRealTimeFilter = None
- # Avoid using a verified user since server will not accept two verfied users with same name
- if (self.config.websocketAprsHost1 is not None) :
- try:
- self.aprsISConnection1 = AprsISConnection("NOCALL", "-1", self.config.websocketAprsHost1, self.config.websocketAprsPort1)
- if (self.config.websocketFrequencyLimit != 0) :
- self.aprsISConnection1.setFrequencyLimit(self.config.websocketFrequencyLimit)
- self.aprsISConnection1.connect()
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
- if (self.aprsISConnection2 is None) :
- self.latestRealTimeFilter = None
- # Avoid using a verified user since server will not accept two verfied users with same name
- if (self.config.websocketAprsHost2 is not None) :
- try:
- self.aprsISConnection2 = AprsISConnection("NOCALL", "-1", self.config.websocketAprsHost2, self.config.websocketAprsPort2)
- if (self.config.websocketFrequencyLimit != 0) :
- self.aprsISConnection2.setFrequencyLimit(self.config.websocketFrequencyLimit)
- self.aprsISConnection2.connect()
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
-
- def _modifyFilter(self) :
- """Set a new filter for the APRS-IS connections according to the latest requested map bounds
- """
- newFilter = self._getNewFilter()
- if (self.latestRealTimeFilter is not None and newFilter == self.latestRealTimeFilter) :
- # If new filter is equal to latest, do not do anything
- return
-
- # Just empty any waiting data on socket
- self.clear()
-
- self.latestRealTimeFilter = newFilter
- if (self.aprsISConnection1 is not None) :
- self.aprsISConnection1.set_filter(newFilter)
-
- if (self.aprsISConnection2 is not None) :
- self.aprsISConnection2.set_filter(newFilter)
-
-
- def _getNewFilter(self) :
- """Create new APRS-IS filter based latest requested map bounds
- """
- if (len(self.state.filterStationIdDict) > 0) :
- filter = "b"
- for stationId in self.state.filterStationIdDict:
- sender = self.senderRepository.getObjectByStationId(stationId)
- if (sender.name is not None) :
- call, sep, ssid = sender.name.partition('-')
- filter = filter + "/" + sender.name
- else :
- # We add some area arround current view
- #filter = "a/" + str(self.state.latestNeLat+1) + "/" + str(self.state.latestSwLng-2) + "/" + str(self.state.latestSwLat-1) + "/" + str(self.state.latestNeLng+2)
- filter = "a/" + str(self.state.latestNeLat+0.1) + "/" + str(self.state.latestSwLng-0.1) + "/" + str(self.state.latestSwLat-0.1) + "/" + str(self.state.latestNeLng+0.1)
-
- return filter
diff --git a/server/trackdirect/websocket/aprsis/__init__.py b/server/trackdirect/websocket/aprsis/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/aprsis/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/websocket/queries/MissingPacketsQuery.py b/server/trackdirect/websocket/queries/MissingPacketsQuery.py
deleted file mode 100644
index 9a836c924b831ad5f3280144439765ebdf906802..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/queries/MissingPacketsQuery.py
+++ /dev/null
@@ -1,169 +0,0 @@
-import datetime, time, calendar
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.repositories.StationRepository import StationRepository
-from trackdirect.parser.policies.MapSectorPolicy import MapSectorPolicy
-
-class MissingPacketsQuery() :
- """This query class is used to find a packet for all stations that we are missing a packet for (when we rely need a packet for them)
-
- Note:
- If no packet are found we will simulate them
- """
-
- def __init__(self, state, db) :
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): The current state for a websocket connection
- db (psycopg2.Connection): Database connection
- """
- self.state = state
- self.db = db
- self.packetRepository = PacketRepository(db)
- self.stationRepository = StationRepository(db)
- self.simulateEmptyStation = False
-
-
- def enableSimulateEmptyStation(self) :
- """Enable simulation even if we have no packet from station at all
- """
- self.simulateEmptyStation = True
-
-
- def getMissingPackets(self, stationIds, foundPackets) :
- """Fetch latest packets for stations that has no packet in foundPackets
-
- Args:
- stationIds (array): An array of all stations we should filter on
- foundPackets (array): Packets that we have found
-
- Returns:
- array
- """
- foundMissingPackets = []
- for stationId in stationIds :
- foundStationPacket = False
- for packet in foundPackets :
- if packet.stationId == stationId :
- foundStationPacket = True
- break # will go to next stationId
-
- # Get latest packet for this station
- if (not foundStationPacket) :
- missingPacket = self._getLatestPacket(stationId)
- if (missingPacket is not None) :
- foundMissingPackets.append(missingPacket)
-
- def getSortKey(item) :
- return item.timestamp
- return sorted(foundMissingPackets, key = getSortKey)
-
-
- def _getLatestPacket(self, stationId) :
- """This method tries to find a packet for the specified station, in worst case a packet will be simulated based on old data
-
- Args:
- stationId (int): Stations id that we need a packet for
-
- Returns:
- Packet
- """
- if (self.state.latestTimeTravelRequest is not None) :
- ts = int(self.state.latestTimeTravelRequest) - (30*24*60*60) # For time travelers we need a limit
- olderPackets = self.packetRepository.getLatestObjectListByStationIdListAndTimeInterval([stationId], ts, self.state.latestTimeTravelRequest)
- else :
- olderPackets = self.packetRepository.getLatestConfirmedObjectListByStationIdList([stationId], 0)
-
- if (len(olderPackets) > 0) :
- return olderPackets[0] # The lastet is the first in array
- else :
- # Lets try not confirmed packets
- if (self.state.latestTimeTravelRequest is not None) :
- ts = int(self.state.latestTimeTravelRequest) - (30*24*60*60) # For time travelers we need a limit
- olderNonConfirmedPackets = self.packetRepository.getLatestObjectListByStationIdListAndTimeInterval([stationId], ts, self.state.latestTimeTravelRequest, False)
- else :
- olderNonConfirmedPackets = self.packetRepository.getLatestObjectListByStationIdList([stationId], 0)
-
- if (len(olderNonConfirmedPackets) > 0) :
- # Make this ghost-packet visible...
- packet = olderNonConfirmedPackets[0]
- packet.mapId = 1
- packet.sourceId = 0 #simulated
- return packet
- else :
- # We still do not have packets for this station, just get what we have from the station-table
- return self._getSimulatedPacket(stationId)
- return None
-
-
- def _getSimulatedPacket(self, stationId) :
- """Creates a simulated packet based on data saved in the station table
-
- Args:
- stationId (int): The station that we want a packet from
-
- Returns:
- Packet
- """
- station = self.stationRepository.getObjectById(stationId)
- if (station.isExistingObject()
- and (station.latestConfirmedPacketId is not None
- or self.simulateEmptyStation)) :
- packet = self.packetRepository.create()
- packet.stationId = station.id
- packet.senderId = station.latestSenderId
- packet.sourceId = station.sourceId
- packet.ogn_sender_address = station.latestOgnSenderAddress
-
- if (station.latestConfirmedPacketId is not None) :
- packet.id = station.latestConfirmedPacketId
- else :
- packet.id = -station.id # simulate a packet id that is uniqe
-
- if (station.latestConfirmedMarkerId is not None) :
- packet.markerId = station.latestConfirmedMarkerId
- else :
- packet.markerId = -station.id # simulate a marker id
-
- packet.isMoving = 0
- packet.packetTypeId = 1 # Assume it was a position packet...
-
- if (station.latestConfirmedLatitude is not None and station.latestConfirmedLongitude is not None) :
- packet.latitude = station.latestConfirmedLatitude
- packet.longitude = station.latestConfirmedLongitude
- else :
- packet.latitude = float(0.0)
- packet.longitude = float(0.0)
-
- if (self.state.latestTimeTravelRequest is not None) :
- packet.timestamp = 0 # don't know anything better to set here...
- elif (station.latestConfirmedPacketTimestamp is not None) :
- packet.timestamp = station.latestConfirmedPacketTimestamp
- else :
- packet.timestamp = 0
-
- packet.reportedTimestamp = None
- packet.positionTimestamp = packet.timestamp
- packet.posambiguity = 0
-
- if (station.latestConfirmedSymbol is not None and station.latestConfirmedSymbolTable is not None) :
- packet.symbol = station.latestConfirmedSymbol
- packet.symbolTable = station.latestConfirmedSymbolTable
- else :
- packet.symbol = None
- packet.symbolTable = None
-
- mapSectorPolicy = MapSectorPolicy()
- packet.mapSector = mapSectorPolicy.getMapSector(packet.latitude, packet.longitude)
- packet.relatedMapSectors = []
- packet.mapId = 1
- packet.speed = None
- packet.course = None
- packet.altitude = None
- packet.packetTailTimestamp = packet.timestamp
- packet.comment = None
- packet.rawPath = None
- packet.raw = None
-
- return packet
- return None
diff --git a/server/trackdirect/websocket/queries/MostRecentPacketsQuery.py b/server/trackdirect/websocket/queries/MostRecentPacketsQuery.py
deleted file mode 100644
index ca2a4f63136e882798552cf2030c734ebd05b024..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/queries/MostRecentPacketsQuery.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import datetime, time, calendar
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.websocket.queries.MissingPacketsQuery import MissingPacketsQuery
-
-
-class MostRecentPacketsQuery() :
- """This query class returnes the latest packet for moving stations and the latest packet for every uniqe position for stationary stations.
-
- Note:
- If no packet are found we will simulate them
- """
-
- def __init__(self, state, db) :
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): The current state for a websocket connection
- db (psycopg2.Connection): Database connection
- """
- self.state = state
- self.db = db
- self.packetRepository = PacketRepository(db)
- self.simulateEmptyStation = False
-
-
- def enableSimulateEmptyStation(self) :
- """Enable simulation even if we have no packet from station at all
- """
- self.simulateEmptyStation = True
-
-
- def getPackets(self, stationIds) :
- """Fetch the most recent packets for the specified stations.
- Returns the latest packet for moving stations and the latest packet for every uniqe position for stationary stations.
-
- Args:
- stationIds (array): An array of all stations we want packets for
-
- Returns:
- array
- """
- if (self.state.latestTimeTravelRequest is not None) :
- timestamp = int(self.state.latestTimeTravelRequest) - (int(self.state.latestMinutesRequest)*60)
- packets = self.packetRepository.getMostRecentConfirmedObjectListByStationIdListAndTimeInterval(stationIds, timestamp, self.state.latestTimeTravelRequest)
- else :
- timestamp = int(time.time()) - (int(self.state.latestMinutesRequest)*60)
- packets = self.packetRepository.getMostRecentConfirmedObjectListByStationIdList(stationIds, timestamp)
-
- if (len(packets) < len(stationIds)) :
- # If we have no recent markers we just send the latest that we have
- query = MissingPacketsQuery(self.state, self.db)
- if (self.simulateEmptyStation) :
- query.enableSimulateEmptyStation()
-
- foundMissingPackets = query.getMissingPackets(stationIds, packets)
- if (foundMissingPackets) :
- foundMissingPackets.extend(packets)
- packets = foundMissingPackets
- return packets
diff --git a/server/trackdirect/websocket/queries/StationIdByMapSectorQuery.py b/server/trackdirect/websocket/queries/StationIdByMapSectorQuery.py
deleted file mode 100644
index 2a44a0fef9a34dbd537518c4636d5c6f2a179dc1..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/queries/StationIdByMapSectorQuery.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import datetime, time, calendar
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-
-
-class StationIdByMapSectorQuery() :
- """A query class used to find station ids in a map sector
- """
-
- def __init__(self, db) :
- """The __init__ method.
-
- Args:
- db (psycopg2.Connection): Database connection
- """
- self.db = db
- self.dbObjectFinder = DatabaseObjectFinder(db)
-
- def getStationIdListByMapSector(self, mapSector, startPacketTimestamp, endPacketTimestamp) :
- """Returns a list station ids based on the specified map sector and time interval
-
- Args:
- mapSector (int): Map sector integer
- startPacketTimestamp (int): Min unix timestamp
- endPacketTimestamp (int): Max unix timestamp
-
- Returns:
- array
- """
- result = {}
- selectCursor = self.db.cursor()
-
- # Create list of packet tables to look in
- # After testing I have realized that this query is faster if you query one child table at the time
-
- if (endPacketTimestamp is None):
- endPacketTimestamp = int(time.time())
- endDateTime = datetime.datetime.utcfromtimestamp(int(endPacketTimestamp))
- endDateTime = endDateTime.replace(hour=0, minute=0, second=0, microsecond=0) + datetime.timedelta(days=1)
- endTimestamp = calendar.timegm(endDateTime.timetuple())
-
- packetTables = []
- ts = startPacketTimestamp
- while (ts < endTimestamp) :
- date = datetime.datetime.utcfromtimestamp(int(ts)).strftime('%Y%m%d')
- datePacketTable = 'packet' + date
- if (self.dbObjectFinder.checkTableExists(datePacketTable)) :
- packetTables.append(datePacketTable)
- ts = ts + 86400 # 1 day in seconds
-
- # Go through packet tables and search for stations
- for packetTable in reversed(packetTables) :
- sql1 = selectCursor.mogrify("""select distinct station_id id
- from """ + packetTable + """
- where map_sector = %s
- and timestamp > %s
- and timestamp <= %s
- and map_id in (1,5,7,9)""", (mapSector, startPacketTimestamp, endPacketTimestamp))
-
- selectCursor.execute(sql1)
- for record in selectCursor :
- if (record is not None) :
- result[int(record["id"])] = True
-
- sql2 = selectCursor.mogrify("""select distinct station_id id
- from """ + packetTable + """
- where map_sector = %s
- and position_timestamp <= %s
- and timestamp > %s
- and map_id in (12)""", (mapSector, endPacketTimestamp, startPacketTimestamp))
-
- selectCursor.execute(sql2)
- for record in selectCursor :
- if (record is not None) :
- result[int(record["id"])] = True
-
- selectCursor.close()
- return list(result.keys())
\ No newline at end of file
diff --git a/server/trackdirect/websocket/queries/__init__.py b/server/trackdirect/websocket/queries/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/queries/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/server/trackdirect/websocket/responses/FilterHistoryResponseCreator.py b/server/trackdirect/websocket/responses/FilterHistoryResponseCreator.py
deleted file mode 100644
index 122e7c5b6c35b24bcaa777a69c218ff72438dbfd..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/responses/FilterHistoryResponseCreator.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import logging
-from twisted.python import log
-
-from math import floor, ceil
-import datetime, time
-import psycopg2, psycopg2.extras
-
-from trackdirect.repositories.PacketRepository import PacketRepository
-
-from trackdirect.websocket.queries.MissingPacketsQuery import MissingPacketsQuery
-from trackdirect.websocket.responses.ResponseDataConverter import ResponseDataConverter
-
-class FilterHistoryResponseCreator():
- """The FilterHistoryResponseCreator class creates history responses for stations that we are filtering on
- """
-
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): WebsocketConnectionState instance that contains current state
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
- self.logger = logging.getLogger('trackdirect')
-
- self.db = db
- self.responseDataConverter = ResponseDataConverter(state, db)
- self.packetRepository = PacketRepository(db)
-
-
- def getResponse(self) :
- """Returns a filter history response
-
- Returns:
- Dict
- """
- filterStationIds = self.state.filterStationIdDict.keys()
-
- # When filtering we send everything in the same packet
- # We need to do this since we do not send related objects,
- # if user is filtering on two related OBJECTS they need to be sent together
- packets = self._getPackets(filterStationIds)
-
- # If map is empty we need to make sure that all specified stations is included
- if (self.state.isMapEmpty()) :
- query = MissingPacketsQuery(self.state, self.db)
- query.enableSimulateEmptyStation()
- sortedFoundMissingPackets = query.getMissingPackets(filterStationIds, packets)
- sortedFoundMissingPackets.extend(packets)
- packets = sortedFoundMissingPackets
-
- if (packets) :
- data = self.responseDataConverter.getResponseData(packets, [])
- payload = {'payload_response_type': 2, 'data': data}
- return payload
-
-
- def _getPackets(self, stationIds) :
- """Returns packets to be used in a filter history response
-
- Args:
- stationIds (array): The station id's that we want history data for
-
- Returns:
- array
- """
- minTimestamp = None
- if (len(stationIds) > 0) :
- minTimestamp = self.state.getStationLatestTimestampOnMap(list(stationIds)[0])
- if (minTimestamp is None) :
- minTimestamp = self.state.getMapSectorTimestamp(None) # None as argument is useful even when not dealing with map-sectors
- if (len(stationIds) > 1) :
- for stationId in stationIds :
- timestamp = self.state.getStationLatestTimestampOnMap(stationId)
- if (timestamp is not None and timestamp > minTimestamp) :
- minTimestamp = timestamp
-
- if (self.state.latestTimeTravelRequest is not None) :
- if (not self.state.isStationsOnMap(stationIds)) :
- return self.packetRepository.getObjectListByStationIdListAndTimeInterval(stationIds, minTimestamp, self.state.latestTimeTravelRequest)
- else :
- return self.packetRepository.getObjectListByStationIdList(stationIds, minTimestamp)
diff --git a/server/trackdirect/websocket/responses/FilterResponseCreator.py b/server/trackdirect/websocket/responses/FilterResponseCreator.py
deleted file mode 100644
index e4a5508dd55f1e33f7aaba5d410b91d5e5c086a4..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/responses/FilterResponseCreator.py
+++ /dev/null
@@ -1,144 +0,0 @@
-import logging
-
-import time
-
-
-import trackdirect
-
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.repositories.StationRepository import StationRepository
-
-from trackdirect.websocket.queries.MostRecentPacketsQuery import MostRecentPacketsQuery
-from trackdirect.websocket.responses.ResponseDataConverter import ResponseDataConverter
-
-
-class FilterResponseCreator():
- """The FilterResponseCreator is used to create filter responses, a response sent to client when client wants to filter on a station
- """
-
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): WebsocketConnectionState instance that contains current state
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
- self.db = db
- self.logger = logging.getLogger('trackdirect')
- self.responseDataConverter = ResponseDataConverter(state, db)
- self.packetRepository = PacketRepository(db)
- self.stationRepository = StationRepository(db)
- self.config = trackdirect.TrackDirectConfig()
-
-
- def getResponses(self, request) :
- """Creates responses related to a filter request
-
- Args:
- request (dict): The request to process
-
- Returns:
- generator
- """
- self._updateState(request)
- if (self.state.isReset()) :
- yield self._getResetResponse()
- yield self._getFilterResponse()
-
-
- def _updateState(self, request) :
- """Update connection state based on filter request
-
- Args:
- request (dict): The request to process
- """
- if (request["payload_request_type"] == 4 and "list" in request) :
- if (len(request["list"]) > 0) :
- for stationId in request["list"]:
- # Only send data about specified objects
- self.state.filterStationIdDict[int(stationId)] = True
- else :
- # User wants to see everything again
- self.state.filterStationIdDict = {}
- self.state.setLatestMapBounds(0, 0, 0, 0)
- self.state.setLatestMinutes(60, None)
- self.state.reset()
-
- elif (request["payload_request_type"] == 6 and "station_id" in request) :
- self.state.filterStationIdDict.pop(int(request["station_id"]), None)
- self.state.reset()
-
- elif (request["payload_request_type"] == 8 and "namelist" in request) :
- if (len(request["namelist"]) > 0) :
- minTimestamp = int(time.time()) - (10*365*24*60*60)
- if (not self.config.allowTimeTravel) :
- minTimestamp = int(time.time()) - (24*60*60)
-
- for stationName in request["namelist"]:
- # Only send data about specified objects
- stations = self.stationRepository.getObjectListByName(stationName, None, None, minTimestamp)
- for station in stations:
- self.state.filterStationIdDict[int(station.id)] = True
- else :
- # User wants to see everything again
- self.state.filterStationIdDict = {}
- self.state.setLatestMapBounds(0, 0, 0, 0)
- self.state.setLatestMinutes(60, None)
- self.state.reset()
-
- def _getResetResponse(self) :
- """This method creates a reset response
-
- Returns:
- Dict
- """
- payload = {'payload_response_type': 40}
- return payload
-
-
- def _getFilterResponse(self) :
- """This method creates a filter response
-
- Returns:
- Dict
- """
- data = []
- if (self.state.filterStationIdDict) :
- filterStationIds = list(self.state.filterStationIdDict.keys())
- data = self._getFilterResponseData(filterStationIds)
-
- payload = {'payload_response_type': 5, 'data': data}
- return payload
-
-
- def _getFilterResponseData(self, filterStationIds) :
- """Creates data to be included in a filter response
-
- Args:
- filterStationIds (array): An array of all stations we should filter on
- """
- if (self.state.latestTimeTravelRequest is not None) :
- timestamp = int(self.state.latestTimeTravelRequest) - (int(self.state.latestMinutesRequest)*60)
- else :
- timestamp = int(time.time()) - (int(self.state.latestMinutesRequest)*60)
-
- query = MostRecentPacketsQuery(self.state, self.db)
- query.enableSimulateEmptyStation()
- packets = query.getPackets(filterStationIds)
- data = self.responseDataConverter.getResponseData(packets, [])
- self.state.reset() # Reset to make sure client will get the same packet on history request
- result = []
- for packetData in data :
- if (self.config.allowTimeTravel or packetData['timestamp'] > int(time.time()) - (24*60*60)) :
- packetData['overwrite'] = 1
- packetData['realtime'] = 0
- packetData['packet_order_id'] = 1 # Last packet for this station in this response
- packetData['requested_timestamp'] = timestamp
- if packetData['station_id'] in filterStationIds:
- packetData['related'] = 0
- else :
- packetData['related'] = 1
- result.append(packetData)
- return result
diff --git a/server/trackdirect/websocket/responses/HistoryResponseCreator.py b/server/trackdirect/websocket/responses/HistoryResponseCreator.py
deleted file mode 100644
index 71c521ba6008c4dc371ca3dbb533fed6f5fd75c0..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/responses/HistoryResponseCreator.py
+++ /dev/null
@@ -1,235 +0,0 @@
-import logging
-from twisted.python import log
-
-from math import floor, ceil
-import datetime, time
-import psycopg2, psycopg2.extras
-
-from trackdirect.repositories.PacketRepository import PacketRepository
-
-from trackdirect.websocket.queries.StationIdByMapSectorQuery import StationIdByMapSectorQuery
-from trackdirect.websocket.responses.ResponseDataConverter import ResponseDataConverter
-
-
-class HistoryResponseCreator():
- """The HistoryResponseCreator class creates websocket history responses for the latest websocket request
- """
-
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState): WebsocketConnectionState instance that contains current state
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
- self.logger = logging.getLogger('trackdirect')
-
- self.db = db
- self.packetRepository = PacketRepository(db)
- self.responseDataConverter = ResponseDataConverter(state, db)
-
-
- def getResponses(self, request, requestId) :
- """Create all history responses for the current request
-
- Args:
- request (dict): The request to process
- requestId (int): Request id of processed request
-
- Returns:
- generator
- """
- if (request["payload_request_type"] == 1 or request["payload_request_type"] == 11) :
- if (not self.state.isValidLatestPosition()) :
- return
-
- if (self.state.latestNeLat >= 90
- and self.state.latestNeLng >= 180
- and self.state.latestSwLat <= -90
- and self.state.latestSwLng <= -180) :
- # request is requesting to much
- return
-
- for response in self._getMapSectorHistoryResponses(requestId) :
- yield response
-
- elif (request["payload_request_type"] == 7 and "station_id" in request) :
- for response in self._getStationHistoryResponses([request["station_id"]], None, True) :
- yield response
-
- else :
- self.logger.error('Request is not supported')
- self.logger.error(request)
-
-
- def _getMapSectorHistoryResponses(self, requestId) :
- """Creates all needed history responses for the currently visible map sectors
-
- Args:
- requestId (int): Request id of processed request
-
- Returns:
- generator
- """
- mapSectorArray = self.state.getVisibleMapSectors()
- if (len(mapSectorArray) > 20000) :
- # Our client will never send a request like this
- self.logger.error("To many map sectors requested!")
- return
-
- handledStationIdDict = {}
- for mapSector in mapSectorArray :
- try:
- # Handle one map sector at the time
- if (requestId is not None and self.state.latestRequestId > requestId) :
- # If new request is recived we want to skip this one (this request is not that important)
- # As long as we handle a complete map sector everything is ok
- return
-
- foundStationIds = self._getStationIdsByMapSector(mapSector)
- stationIds = []
- for stationId in foundStationIds :
- if (stationId not in handledStationIdDict) :
- stationIds.append(stationId)
- handledStationIdDict[stationId] = True
-
- if (stationIds) :
- for response in self._getStationHistoryResponses(stationIds, mapSector, False) :
- yield response
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
-
- def _getStationHistoryResponses(self, stationIds, mapSector, includeCompleteHistory = False) :
- """Creates one history response per station
-
- Args:
- stationIds (array): An array of the stations that we want history data for
- mapSector (int): The map sector that we want history data for
- includeCompleteHistory (boolean): Include all previous packets (even if we currently only request the latest packets)
-
- Returns:
- generator
- """
- # Important to fetch map sector timestamp before loop (may be updated in loop)
- minTimestamp = self.state.getMapSectorTimestamp(mapSector)
- for stationId in stationIds:
- try:
- if (self.state.latestTimeTravelRequest is not None) :
- response = self._getPastHistoryResponse(stationId, mapSector, minTimestamp, includeCompleteHistory)
- else :
- response = self._getRecentHistoryResponse(stationId, mapSector, minTimestamp, includeCompleteHistory)
- if (response is not None) :
- yield response
- except psycopg2.InterfaceError as e:
- # Connection to database is lost, better just exit
- raise e
- except Exception as e:
- self.logger.error(e, exc_info=1)
-
-
- def _getRecentHistoryResponse(self, stationId, mapSector, minTimestamp, includeCompleteHistory = False) :
- """Creates a history response for the specified station, includes all packets from minTimestamp until now
-
- Args:
- stationId (int): The station id that we want history data for
- mapSector (int): The map sector that we want history data for
- minTimestamp (int): The map sector min timestamp to use in query
- includeCompleteHistory (boolean): Include all previous packets (even if we currently only request the latest packets)
-
- Returns:
- Dict
- """
- packets = []
- onlyLatestPacketFetched = False
- currentStationIds = [stationId]
-
- currentMinTimestamp = self.state.getStationLatestTimestampOnMap(stationId)
- if (currentMinTimestamp is None) :
- currentMinTimestamp = minTimestamp
- else :
- # Since station already exists on map we should continue adding all packets
- includeCompleteHistory = True
-
- if (not self.state.onlyLatestPacketRequested or includeCompleteHistory) :
- packets = self.packetRepository.getObjectListByStationIdList(currentStationIds, currentMinTimestamp)
- else :
- # We could call getMostRecentConfirmedObjectListByStationIdList, would take longer time but would show all positions for a station
- packets = self.packetRepository.getLatestConfirmedObjectListByStationIdList(currentStationIds, currentMinTimestamp)
- if (packets) :
- packets = [packets[-1]] # we only need the latest
- onlyLatestPacketFetched = True
-
- if (packets) :
- flags = []
- if (onlyLatestPacketFetched) :
- flags = ["latest"]
- data = self.responseDataConverter.getResponseData(packets, [mapSector], flags)
- payload = {'payload_response_type': 2, 'data': data}
- return payload
-
-
- def _getPastHistoryResponse(self, stationId, mapSector, minTimestamp, includeCompleteHistory = False) :
- """Creates a history response for the specified station, includes all packets between minTimestamp and the current latestTimeTravelRequest timestamp
-
- Args:
- stationId (int): The station id that we want history data for
- mapSector (int): The map sector that we want history data for
- minTimestamp (int): The map sector min timestamp to use in query
- includeCompleteHistory (boolean): Include all previous packets (even if we currently only request the latest packets)
-
- Returns:
- Dict
- """
- packets = []
- onlyLatestPacketFetched = False
- currentStationIds = [stationId]
-
- currentMinTimestamp = self.state.getStationLatestTimestampOnMap(stationId)
- if (currentMinTimestamp is None) :
- currentMinTimestamp = minTimestamp
-
- if (self.state.onlyLatestPacketRequested and not includeCompleteHistory) :
- if (stationId not in self.state.stationsOnMapDict) :
- # we only need to fetch latest packet for a time-travel request if station is not on map
- onlyLatestPacketFetched = True
- packets = self.packetRepository.getLatestObjectListByStationIdListAndTimeInterval(currentStationIds, currentMinTimestamp, self.state.latestTimeTravelRequest)
- else :
- if (not self.state.isStationHistoryOnMap(stationId)) :
- packets = self.packetRepository.getObjectListByStationIdListAndTimeInterval(currentStationIds, currentMinTimestamp, self.state.latestTimeTravelRequest)
-
- if (packets) :
- flags = []
- if (onlyLatestPacketFetched) :
- flags = ["latest"]
- data = self.responseDataConverter.getResponseData(packets, [mapSector], flags)
- payload = {'payload_response_type': 2, 'data': data}
- return payload
-
-
- def _getStationIdsByMapSector(self, mapSector) :
- """Returns the station Id's in specified map sector
-
- Args:
- mapSector (int): The map sector that we are interested in
-
- Returns:
- array of ints
- """
- query = StationIdByMapSectorQuery(self.db)
- if (self.state.latestTimeTravelRequest is not None) :
- if (self.state.isMapSectorKnown(mapSector)) :
- # This map sector is under control
- return []
- else :
- startTimestamp = self.state.latestTimeTravelRequest - (int(self.state.latestMinutesRequest)*60)
- endTimestamp = self.state.latestTimeTravelRequest;
- return query.getStationIdListByMapSector(mapSector, startTimestamp, endTimestamp)
- else :
- timestamp = self.state.getMapSectorTimestamp(mapSector)
- return query.getStationIdListByMapSector(mapSector, timestamp, None)
diff --git a/server/trackdirect/websocket/responses/ResponseDataConverter.py b/server/trackdirect/websocket/responses/ResponseDataConverter.py
deleted file mode 100644
index 9ad3c1a8862ce5fb6dd19e25d41e3b5bfa9b412d..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/responses/ResponseDataConverter.py
+++ /dev/null
@@ -1,377 +0,0 @@
-import logging
-from twisted.python import log
-
-from math import floor, ceil
-import datetime, time
-
-import psycopg2, psycopg2.extras
-
-from trackdirect.repositories.PacketRepository import PacketRepository
-from trackdirect.repositories.StationRepository import StationRepository
-from trackdirect.repositories.PacketWeatherRepository import PacketWeatherRepository
-from trackdirect.repositories.PacketOgnRepository import PacketOgnRepository
-from trackdirect.repositories.OgnDeviceRepository import OgnDeviceRepository
-
-from trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
-from trackdirect.database.DatabaseConnection import DatabaseConnection
-
-from trackdirect.websocket.queries.MostRecentPacketsQuery import MostRecentPacketsQuery
-from trackdirect.websocket.queries.MissingPacketsQuery import MissingPacketsQuery
-
-
-class ResponseDataConverter():
- """An ResponseDataConverter instance is used to create response content data based on packet objects
- """
-
-
- def __init__(self, state, db):
- """The __init__ method.
-
- Args:
- state (WebsocketConnectionState):
- db (psycopg2.Connection): Database connection (with autocommit)
- """
- self.state = state
- self.logger = logging.getLogger('trackdirect')
-
- self.db = db
- self.packetRepository = PacketRepository(db)
- self.stationRepository = StationRepository(db)
- self.packetWeatherRepository = PacketWeatherRepository(db)
- self.dbObjectFinder = DatabaseObjectFinder(db)
- self.packetOgnRepository = PacketOgnRepository(db)
- self.ognDeviceRepository = OgnDeviceRepository(db)
-
-
- def getResponseData(self, packets, mapSectorList = None, flags = [], iterationCounter = 0) :
- """Create response data based on specified packets
-
- Args:
- packets (array): An array of the Packet's that should be converted to packet dict responses
- mapSectorList (array): An array of the current handled map sectors
- flags (array): An array with additional flags (like "realtime", "latest")
- iterationCounter (int) This functionality will call itself to find related packets, this argument is used to remember the number of iterations
-
- Returns:
- An array of packet dicts
- """
- responseData = []
- for index, packet in enumerate(packets) :
- packetDict = packet.getDict(True)
- packetDict['packet_order_id'] = self._getPacketOrderId(packets, index, flags)
-
- self._updateState(packet, mapSectorList, flags)
- self._addOverwriteStatus(packetDict)
- if (("latest" not in flags and "realtime" not in flags) or self.state.isStationHistoryOnMap(packet.stationId)) :
- if (packetDict['packet_order_id'] == 1) :
- self._addStationWeatherData(packetDict)
- self._addStationTelemetryData(packetDict)
- if (packet.sourceId == 5) :
- self._addStationOgnData(packetDict)
- if (packet.sourceId == 5) :
- self._addStationOgnDeviceData(packetDict)
- self._addPacketPhgRng(packetDict)
-
- if ("realtime" not in flags) :
- self._addStationIdPath(packetDict)
-
- self._setFlags(packetDict, flags)
- responseData.append(packetDict)
- return self._extendResponseWithMorePackets(responseData, flags, iterationCounter)
-
-
- def _getPacketOrderId(self, packets, index, flags) :
- """Returns the order id of the packet at specified index
-
- Args:
- packets (array): An array of the Packet's that should be converted to packet dict responses
- index (int): Index of the packet that we want an order id for
- flags (array): An array with additional flags (like "realtime", "latest")
-
- Returns:
- int
- """
- if ("realtime" in flags) :
- return 1
- elif (len(packets) -1 == index):
- # This is the last packet of all
- return 1 # Last packet in response for this marker
- elif (packets[index].markerId != packets[index + 1].markerId) :
- # This is the last packet for this marker
- return 1 # Last packet in response for this marker
- elif (index == 0 or packets[index].markerId != packets[index - 1].markerId) :
- # This is the first packet for this marker
- return 3 # First packet in response for this marker
- else :
- return 2 # Middle packet in response for this marker
-
-
- def _updateState(self, packet, mapSectorList, flags) :
- """Update connection state based on packet on the way to client
-
- Args:
- packet (Packet): The packet that is on the way to client
- mapSectorList (array): An array of the current handled map sectors
- flags (array): An array with additional flags (like "realtime", "latest")
- """
- self.state.setStationLatestTimestamp(packet.stationId, packet.timestamp)
-
- if (packet.stationId not in self.state.stationsOnMapDict) :
- # Station should be added to stationsOnMapDict even if only latest packet is added
- self.state.stationsOnMapDict[packet.stationId] = True
-
- # self.state.setCompleteStationLatestTimestamp
- # Note that we depend on that the real-time aprs-is sender make sure to send previous missing packets when a new is sent
- if (self.state.isStationHistoryOnMap(packet.stationId)) :
- self.state.setCompleteStationLatestTimestamp(packet.stationId, packet.timestamp)
- elif ("latest" not in flags and "realtime" not in flags and "related" not in flags) :
- self.state.setCompleteStationLatestTimestamp(packet.stationId, packet.timestamp)
- elif ("related" in flags and packet.packetTailTimestamp == packet.timestamp) :
- self.state.setCompleteStationLatestTimestamp(packet.stationId, packet.timestamp)
-
- if (mapSectorList and packet.mapSector is not None and packet.mapSector in mapSectorList) :
- if "latest" not in flags:
- self.state.setMapSectorLatestTimeStamp(packet.mapSector, packet.timestamp)
- else :
- self.state.setMapSectorLatestOverwriteTimeStamp(packet.mapSector, packet.timestamp)
-
-
- def _setFlags(self, packetDict, flags) :
- """Set additional flags that will tell client a bit more about the packet
-
- Args:
- packetDict (dict): The packet to which we should modify
- flags (array): An array with additional flags (like "realtime", "latest")
- """
- if ("realtime" in flags) :
- packetDict["db"] = 0
- packetDict["realtime"] = 1
- else :
- packetDict["db"] = 1
- packetDict["realtime"] = 0
-
- def _addOverwriteStatus(self, packetDict) :
- """Set packet overwrite status
-
- Args:
- packetDict (dict): The packet to which we should modify
- """
- packetDict['overwrite'] = 0
-
- # We assume that this method is called after the "complete station on map"-state has been updated
- if (not self.state.isStationHistoryOnMap(packetDict["station_id"])) :
- packetDict['overwrite'] = 1
-
-
- def _addPacketPhgRng(self, packetDict) :
- """Add previous reported phg and rng to the specified packet
-
- Args:
- packetDict (dict): The packet to which we should modify
- """
- if ('phg' in packetDict and 'rng' in packetDict) :
- if (packetDict['phg'] is None and packetDict['latest_phg_timestamp'] is not None and packetDict['latest_phg_timestamp'] < packetDict['timestamp']) :
- relatedPacket = self.packetRepository.getObjectByStationIdAndTimestamp(packetDict['station_id'], packetDict['latest_phg_timestamp'])
- if (relatedPacket.phg is not None and relatedPacket.markerId == packetDict['marker_id']) :
- packetDict['phg'] = relatedPacket.phg
-
- if (packetDict['rng'] is None and packetDict['latest_rng_timestamp'] is not None and packetDict['latest_rng_timestamp'] < packetDict['timestamp']) :
- relatedPacket = self.packetRepository.getObjectByStationIdAndTimestamp(packetDict['station_id'], packetDict['latest_rng_timestamp'])
- if (relatedPacket.rng is not None and relatedPacket.markerId == packetDict['marker_id']) :
- packetDict['rng'] = relatedPacket.rng
-
-
- def _addStationOgnData(self, packetDict) :
- """Add OGN data to packet
-
- Args:
- packetDict (dict): The packet to which we should add the related data
- """
- if ('ogn' not in packetDict or packetDict['ogn'] is None) :
- station = self.stationRepository.getObjectById(packetDict['station_id'])
- ts = int(packetDict['timestamp']) - (24*60*60)
- if (station.latestOgnPacketTimestamp is not None
- and station.latestOgnPacketTimestamp > ts) :
- packetDict['latest_ogn_packet_timestamp'] = station.latestOgnPacketTimestamp
-
- relatedPacketDict = None
- if (station.latestOgnPacketId == packetDict['id']) :
- relatedPacketDict = packetDict
- else :
- relatedPacket = self.packetRepository.getObjectByIdAndTimestamp(station.latestOgnPacketId, station.latestOgnPacketTimestamp)
- if (relatedPacket.isExistingObject()) :
- relatedPacketDict = relatedPacket.getDict()
-
- if (relatedPacketDict is not None) :
- if (relatedPacketDict['marker_id'] is not None and relatedPacketDict['marker_id'] == packetDict['marker_id']) :
- packetOgn = self.packetOgnRepository.getObjectByPacketIdAndTimestamp(station.latestOgnPacketId, station.latestOgnPacketTimestamp)
- if (packetOgn.isExistingObject()) :
- packetDict['ogn'] = packetOgn.getDict()
-
-
- def _addStationOgnDeviceData(self, packetDict) :
- """Add OGN device data to packet
-
- Args:
- packetDict (dict): The packet to which we should add the related data
- """
- station = self.stationRepository.getObjectById(packetDict['station_id'])
- if (station.latestOgnSenderAddress is not None) :
- ognDevice = self.ognDeviceRepository.getObjectByDeviceId(station.latestOgnSenderAddress)
- if (ognDevice.isExistingObject()) :
- packetDict['ogn_device'] = ognDevice.getDict()
-
-
- def _addStationWeatherData(self, packetDict) :
- """Add weather data to packet
-
- Args:
- packetDict (dict): The packet to which we should add the related data
- """
- if ('weather' not in packetDict or packetDict['weather'] is None) :
- station = self.stationRepository.getObjectById(packetDict['station_id'])
- ts = int(packetDict['timestamp']) - (24*60*60)
- if (station.latestWeatherPacketTimestamp is not None
- and station.latestWeatherPacketTimestamp > ts) :
- packetDict['latest_weather_packet_timestamp'] = station.latestWeatherPacketTimestamp
-
- relatedPacketDict = None
- if (station.latestWeatherPacketId == packetDict['id']) :
- relatedPacketDict = packetDict
- else :
- relatedPacket = self.packetRepository.getObjectByIdAndTimestamp(station.latestWeatherPacketId, station.latestWeatherPacketTimestamp)
- if (relatedPacket.isExistingObject()) :
- relatedPacketDict = relatedPacket.getDict()
-
- if (relatedPacketDict is not None) :
- if (relatedPacketDict['marker_id'] is not None and relatedPacketDict['marker_id'] == packetDict['marker_id']) :
- packetWeather = self.packetWeatherRepository.getObjectByPacketIdAndTimestamp(station.latestWeatherPacketId, station.latestWeatherPacketTimestamp)
- if (packetWeather.isExistingObject()) :
- packetDict['weather'] = packetWeather.getDict()
-
-
- def _addStationTelemetryData(self, packetDict) :
- """Add telemetry data to packet
-
- Args:
- packetDict (dict): The packet to which we should add the related data
- """
- if ('telemetry' not in packetDict or packetDict['telemetry'] is None) :
- station = self.stationRepository.getObjectById(packetDict['station_id'])
- ts = int(packetDict['timestamp']) - (24*60*60)
- if (station.latestTelemetryPacketTimestamp is not None
- and station.latestTelemetryPacketTimestamp > ts) :
- packetDict['latest_telemetry_packet_timestamp'] = station.latestTelemetryPacketTimestamp
-
-
- def _addStationIdPath(self, packetDict) :
- """Add the station id path to the specified packet
-
- Args:
- packetDict (dict): The packet to which we should add the related station id path
- """
- stationIdPath = []
- stationNamePath = []
- stationLocationPath = []
-
- if (packetDict['raw_path'] is not None and "TCPIP*" not in packetDict['raw_path'] and "TCPXX*" not in packetDict['raw_path']) :
- packetDate = datetime.datetime.utcfromtimestamp(int(packetDict['timestamp'])).strftime('%Y%m%d')
- datePacketTable = 'packet' + packetDate
- datePacketPathTable = datePacketTable + '_path'
-
- if (self.dbObjectFinder.checkTableExists(datePacketPathTable)) :
- selectCursor = self.db.cursor()
- sql = """select station_id, station.name station_name, latitude, longitude from """ + datePacketPathTable + """, station where station.id = station_id and packet_id = %s order by number""" % (packetDict['id'])
- selectCursor.execute(sql)
-
- for record in selectCursor :
- stationIdPath.append(record[0])
- stationNamePath.append(record[1])
- stationLocationPath.append([record[2], record[3]])
- selectCursor.close()
- packetDict['station_id_path'] = stationIdPath
- packetDict['station_name_path'] = stationNamePath
- packetDict['station_location_path'] = stationLocationPath
-
-
- def getDictListFromPacketList(self, packets) :
- """Returns a packet dict list from a packet list
-
- Args:
- packets (array): Array of Packet instances
-
- Returns:
- A array och packet dicts
- """
- packetDicts = []
- for packet in packets :
- packetDicts.append(packet.getDict())
- return packetDicts
-
-
- def _extendResponseWithMorePackets(self, packetDicts, flags, iterationCounter) :
- """Extend the specified array with related packets
-
- Args:
- packetDicts (array): An array of the packet response dicts
- flags (array): An array with additional flags (like "realtime", "latest")
- iterationCounter (int): This functionality will call itself to find related packets, this argument is used to remember the number of iterations
-
- Returns:
- The modified packet array
- """
- allPacketDicts = []
- hasSeveralSendersForOneStation = False
-
- # Add related packets (stations that the original packets depend on)
- if (packetDicts) :
- relatedStationIds = {}
- for index, packetDict in enumerate(packetDicts) :
- if (packetDict['is_moving'] == 1 or packetDict['packet_order_id'] == 1) :
- # Only fetch related stations for the last stationary packet (in some cases query will return older packets)
- if (packetDict['station_id_path']) :
- # Also add latest packets from stations that has been involved in sending any packets in array "packets"
- for stationId in packetDict['station_id_path'] :
- if (stationId not in self.state.stationsOnMapDict) :
- relatedStationIds[stationId] = True
-
- for index, packetDict in enumerate(packetDicts) :
- if (packetDict['station_id'] in relatedStationIds) :
- del relatedStationIds[packetDict['station_id']]
-
- if (relatedStationIds) :
- relatedStationPackets = self._getRelatedStationPacketsByStationIds(list(relatedStationIds.keys()))
-
- # To avoid infinit loop we mark all related stations as added to map even we we failed doing it
- for relatedStationId in list(relatedStationIds.keys()):
- if (relatedStationId not in self.state.stationsOnMapDict) :
- self.state.stationsOnMapDict[relatedStationId] = True
-
- if (relatedStationPackets) :
- if ("latest" in flags) :
- relatedStationPacketDicts = self.getResponseData(relatedStationPackets, None, ["latest", "related"], iterationCounter + 1)
- else :
- relatedStationPacketDicts = self.getResponseData(relatedStationPackets, None, ["related"], iterationCounter + 1)
- allPacketDicts.extend(relatedStationPacketDicts)
-
- # Add original packets
- allPacketDicts.extend(packetDicts)
-
- #return allPacketDicts.sort(key=lambda x: x['id'], reverse=False)
- return allPacketDicts
-
- def _getRelatedStationPacketsByStationIds(self, relatedStationIdList) :
- """Returns a list of the latest packet for the specified stations, this method should be used to find packets for a packet's related stations
-
- Args:
- relatedStationIdList (array): Array of related station id's
-
- Returns:
- An array of the latest packet for the specified stations
- """
- if (relatedStationIdList) :
- query = MostRecentPacketsQuery(self.state, self.db)
- query.enableSimulateEmptyStation()
- return query.getPackets(relatedStationIdList)
- return []
-
diff --git a/server/trackdirect/websocket/responses/__init__.py b/server/trackdirect/websocket/responses/__init__.py
deleted file mode 100644
index 984c177fb076a4043052fbf54a72dea7dbc0a8ba..0000000000000000000000000000000000000000
--- a/server/trackdirect/websocket/responses/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "1.0"
-__author__ = "Per Qvarforth"
diff --git a/trackdirect-python.dockerfile b/trackdirect-python.dockerfile
deleted file mode 100644
index fb1dae36c0fdf20bc30ba5faf580fdea2c7a1cdc..0000000000000000000000000000000000000000
--- a/trackdirect-python.dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-
-FROM ubuntu:20.04
-RUN apt-get update && apt-get install -y \
- python3 \
- python3-dev \
- python3-pip \
- python-is-python3 \
- git \
- && rm -rf /var/lib/apt/lists/*
-
-COPY . /root/trackdirect
-
-RUN pip install -r /root/trackdirect/requirements.txt