trackdirect2/server/trackdirect/repositories/PacketRepository.py

431 lines
20 KiB
Python

from server.trackdirect.common.Repository import Repository
from server.trackdirect.objects.Packet import Packet
from server.trackdirect.database.PacketTableCreator import PacketTableCreator
from server.trackdirect.exceptions.TrackDirectMissingTableError import TrackDirectMissingTableError
from server.trackdirect.database.DatabaseObjectFinder import DatabaseObjectFinder
class PacketRepository(Repository):
"""The PacketRepository class contains different methods that create Packet instances."""
def __init__(self, db):
"""Initialize PacketRepository with a database connection."""
super().__init__(db)
self.packet_table_creator = PacketTableCreator(self.db)
self.packet_table_creator.disable_create_if_missing()
self.db_object_finder = DatabaseObjectFinder(db)
def get_object_by_id(self, id):
"""Return a Packet object based on the specified id in the database."""
with self.db.cursor() as cursor:
cursor.execute("SELECT * FROM packet WHERE id = %s", (id,))
record = cursor.fetchone()
return self.get_object_from_record(record)
def get_object_by_id_and_timestamp(self, id, timestamp):
"""Return a Packet object based on the specified id and timestamp."""
try:
packet_table = self.packet_table_creator.get_table(timestamp)
with self.db.cursor() as cursor:
cursor.execute(f"SELECT * FROM {packet_table} WHERE id = %s", (id,))
record = cursor.fetchone()
return self.get_object_from_record(record)
except TrackDirectMissingTableError:
return self.create()
def get_object_by_station_id_and_timestamp(self, station_id, timestamp):
"""Return a Packet object based on the specified station_id and timestamp."""
try:
packet_table = self.packet_table_creator.get_table(timestamp)
with self.db.cursor() as cursor:
cursor.execute(f"""
SELECT * FROM {packet_table}
WHERE station_id = %s AND timestamp = %s
ORDER BY id LIMIT 1
""", (station_id, timestamp))
record = cursor.fetchone()
return self.get_object_from_record(record)
except TrackDirectMissingTableError:
return self.create()
def get_latest_object_list_by_station_id_list_and_time_interval(self, station_id_list, min_packet_timestamp, max_packet_timestamp, only_confirmed=True):
"""Return an array of the latest Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
found_station_id_list = []
packet_tables = self.packet_table_creator.get_tables(min_packet_timestamp, max_packet_timestamp)
map_id_list = [1, 2, 12] if only_confirmed else [1, 2, 5, 7, 9, 12]
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
station_id_list_to_find = tuple(set(station_id_list) - set(found_station_id_list))
if station_id_list_to_find:
cursor.execute(f"""
SELECT * FROM {packet_table} packet
WHERE id IN (
SELECT MAX(id)
FROM {packet_table} 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(map_id_list), station_id_list_to_find, min_packet_timestamp, max_packet_timestamp))
for record in cursor:
if record and record['station_id'] not in found_station_id_list:
result.append(self.get_object_from_record(record))
found_station_id_list.append(record['station_id'])
if len(found_station_id_list) >= len(station_id_list):
break
return result
def get_object_list_by_station_id_list_and_time_interval(self, station_id_list, min_packet_timestamp, max_packet_timestamp):
"""Return an array of Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
packet_tables = self.packet_table_creator.get_tables(min_packet_timestamp, max_packet_timestamp)
with self.db.cursor() as cursor:
for packet_table in packet_tables:
cursor.execute(f"""
SELECT * FROM {packet_table} 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(station_id_list), min_packet_timestamp, max_packet_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
cursor.execute(f"""
SELECT * FROM {packet_table} 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(station_id_list), max_packet_timestamp, min_packet_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
return result
def get_object_list_by_station_id_list(self, station_id_list, min_packet_timestamp):
"""Return an array of Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
packet_tables = self.packet_table_creator.get_tables(min_packet_timestamp)
with self.db.cursor() as cursor:
for packet_table in packet_tables:
cursor.execute(f"""
SELECT * FROM {packet_table} packet
WHERE map_id IN (1, 5, 7, 9)
AND station_id IN %s
AND timestamp > %s
ORDER BY packet.marker_id, packet.id
""", (tuple(station_id_list), min_packet_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
return result
def get_latest_object_by_station_id_and_position(self, station_id, latitude, longitude, map_id_list, symbol=None, symbol_table=None, min_timestamp=0):
"""Return a Packet object specified by station id and position."""
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT * FROM {packet_table}
WHERE station_id = %s
AND latitude = %s
AND longitude = %s
AND map_id IN %s
AND timestamp > %s
{f"AND symbol = %s" if symbol else ""}
{f"AND symbol_table = %s" if symbol_table else ""}
ORDER BY marker_id DESC, id DESC LIMIT 1
""", (station_id, latitude, longitude, tuple(map_id_list), min_timestamp, symbol, symbol_table))
record = cursor.fetchone()
if record:
return self.get_object_from_record(record)
return self.create()
def get_latest_confirmed_moving_object_by_station_id(self, station_id, min_timestamp=0):
"""Return the latest confirmed moving Packet specified by station id."""
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT * FROM {packet_table}
WHERE station_id = %s
AND is_moving = 1
AND map_id = 1
AND timestamp > %s
ORDER BY marker_id DESC, id DESC LIMIT 1
""", (station_id, min_timestamp))
record = cursor.fetchone()
if record:
return self.get_object_from_record(record)
return self.create()
def get_latest_moving_object_by_station_id(self, station_id, min_timestamp=0):
"""Return the latest moving Packet specified by station id."""
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT * FROM {packet_table} packet
WHERE station_id = %s
AND is_moving = 1
AND map_id IN (1, 7)
AND timestamp > %s
ORDER BY marker_id DESC, id DESC LIMIT 1
""", (station_id, min_timestamp))
record = cursor.fetchone()
if record:
return self.get_object_from_record(record)
return self.create()
def get_latest_confirmed_object_by_station_id(self, station_id, min_timestamp=0):
"""Return the latest confirmed Packet object specified by station id."""
with self.db.cursor() as cursor:
cursor.execute("""
SELECT * FROM station
WHERE id = %s
""", (station_id,))
record = cursor.fetchone()
if record and record["latest_confirmed_packet_timestamp"] is not None and record["latest_confirmed_packet_timestamp"] >= min_timestamp:
return self.get_object_by_id_and_timestamp(record["latest_confirmed_packet_id"], record["latest_confirmed_packet_timestamp"])
return self.create()
def get_latest_object_by_station_id(self, station_id, min_timestamp=0):
"""Return the latest Packet specified by station id."""
with self.db.cursor() as cursor:
cursor.execute("""
SELECT * FROM station
WHERE id = %s
""", (station_id,))
record = cursor.fetchone()
if record and record["latest_location_packet_timestamp"] is not None and record["latest_location_packet_timestamp"] >= min_timestamp:
return self.get_object_by_id_and_timestamp(record["latest_location_packet_id"], record["latest_location_packet_timestamp"])
return self.create()
def get_most_recent_confirmed_object_list_by_station_id_list(self, station_id_list, min_timestamp):
"""Return an array of the most recent confirmed Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in packet_tables:
cursor.execute(f"""
SELECT * FROM {packet_table}
WHERE station_id IN %s
AND timestamp > %s
AND is_moving = 0
AND map_id = 1
""", (tuple(station_id_list), min_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
for station_id in station_id_list:
packet = self.get_latest_confirmed_moving_object_by_station_id(station_id, min_timestamp)
if packet.is_existing_object():
result.append(packet)
return result
def get_most_recent_confirmed_object_list_by_station_id_list_and_time_interval(self, station_id_list, min_timestamp, max_timestamp):
"""Return an array of the most recent confirmed Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
found_stationary_marker_hash_list = []
found_moving_marker_station_id_list = []
packet_tables = self.packet_table_creator.get_tables(min_timestamp, max_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT * FROM {packet_table} packet
WHERE id IN (
SELECT MAX(id)
FROM {packet_table} 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(station_id_list), min_timestamp, max_timestamp))
for record in cursor:
if record:
marker_hash = hash(f"{record['station_id']};{record['latitude']};{record['longitude']};{record['symbol']};{record['symbol_table']}")
if marker_hash not in found_stationary_marker_hash_list:
found_stationary_marker_hash_list.append(marker_hash)
result.append(self.get_object_from_record(record))
cursor.execute(f"""
SELECT packet.* FROM {packet_table} packet
WHERE id IN (
SELECT MAX(id)
FROM {packet_table} packet
WHERE station_id IN %s
AND map_id IN (1, 2, 12)
AND timestamp > %s
AND timestamp <= %s
AND is_moving = 1
GROUP BY station_id
)
""", (tuple(station_id_list), min_timestamp, max_timestamp))
for record in cursor:
if record and record['station_id'] not in found_moving_marker_station_id_list:
found_moving_marker_station_id_list.append(record['station_id'])
result.append(self.get_object_from_record(record))
return result
def get_latest_confirmed_object_list_by_station_id_list(self, station_id_list, min_timestamp=0):
"""Return an array of the latest confirmed Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
if min_timestamp == 0:
for station_id in station_id_list:
packet = self.get_latest_confirmed_object_by_station_id(station_id)
if packet.is_existing_object():
result.append(packet)
else:
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT packet.* FROM {packet_table} packet, station
WHERE station.id IN %s
AND station.latest_confirmed_packet_id = packet.id
AND station.latest_confirmed_packet_timestamp = packet.timestamp
AND station.latest_confirmed_packet_timestamp > %s
ORDER BY packet.marker_id, packet.id
""", (tuple(station_id_list), min_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
if len(result) >= len(station_id_list):
break
return result
def get_latest_object_list_by_station_id_list(self, station_id_list, min_timestamp=0):
"""Return an array of the latest Packet objects specified by station ids."""
if not station_id_list:
return []
result = []
if min_timestamp == 0:
for station_id in station_id_list:
packet = self.get_latest_object_by_station_id(station_id)
if packet.is_existing_object():
result.append(packet)
else:
packet_tables = self.packet_table_creator.get_tables(min_timestamp)
with self.db.cursor() as cursor:
for packet_table in reversed(packet_tables):
cursor.execute(f"""
SELECT packet.* FROM {packet_table} packet, station
WHERE station.id IN %s
AND station.latest_location_packet_id = packet.id
AND station.latest_confirmed_packet_timestamp = packet.timestamp
AND station.latest_location_packet_timestamp > %s
""", (tuple(station_id_list), min_timestamp))
for record in cursor:
if record:
result.append(self.get_object_from_record(record))
if len(result) >= len(station_id_list):
break
return result
def get_object_from_record(self, record):
"""Return a Packet object from a database record."""
db_object = self.create()
if record:
db_object.id = record["id"]
db_object.station_id = int(record["station_id"])
db_object.sender_id = int(record["sender_id"])
db_object.packet_type_id = record["packet_type_id"]
db_object.timestamp = int(record["timestamp"])
db_object.latitude = float(record["latitude"]) if record["latitude"] is not None else None
db_object.longitude = float(record["longitude"]) if record["longitude"] is not None else None
db_object.posambiguity = record['posambiguity']
db_object.symbol = record["symbol"]
db_object.symbol_table = record["symbol_table"]
db_object.map_sector = record["map_sector"]
db_object.related_map_sectors = record["related_map_sectors"]
db_object.map_id = record["map_id"]
db_object.source_id = record["source_id"]
db_object.marker_id = record["marker_id"]
db_object.speed = record["speed"]
db_object.course = record["course"]
db_object.altitude = record["altitude"]
db_object.is_moving = record['is_moving']
db_object.reported_timestamp = int(record["reported_timestamp"]) if record["reported_timestamp"] is not None else None
db_object.position_timestamp = int(record["position_timestamp"]) if record["position_timestamp"] is not None else None
db_object.packet_tail_timestamp = record.get('packet_tail_timestamp', db_object.timestamp)
db_object.marker_counter = record.get('marker_counter', 1)
db_object.comment = record.get('comment')
db_object.raw_path = record.get('raw_path')
db_object.raw = record.get('raw')
db_object.phg = record.get('phg')
db_object.rng = record.get('rng')
db_object.latest_phg_timestamp = record.get('latest_phg_timestamp')
db_object.latest_rng_timestamp = record.get('latest_rng_timestamp')
return db_object
def create(self):
"""Create an empty Packet."""
return Packet(self.db)