218 lines
10 KiB
Python
218 lines
10 KiB
Python
import time
|
|
from math import ceil
|
|
|
|
from server.trackdirect.TrackDirectConfig import TrackDirectConfig
|
|
from server.trackdirect.parser.policies.MapSectorPolicy import MapSectorPolicy
|
|
|
|
class WebsocketConnectionState:
|
|
"""An instance contains information about the current state of a websocket connection."""
|
|
|
|
def __init__(self):
|
|
"""Initialize the WebsocketConnectionState."""
|
|
self.filter_station_id_dict = {}
|
|
self.latest_sw_lng = 0
|
|
self.latest_sw_lat = 0
|
|
self.latest_ne_lng = 0
|
|
self.latest_ne_lat = 0
|
|
self.only_latest_packet_requested = None
|
|
self.latest_time_travel_request = None
|
|
self.latest_minutes_request = 60
|
|
self.max_map_sector_overwrite_packet_timestamp_dict = {}
|
|
self.max_map_sector_packet_timestamp_dict = {}
|
|
self.max_all_station_timestamp_dict = {}
|
|
self.max_complete_station_timestamp_dict = {}
|
|
self.stations_on_map_dict = {}
|
|
self.latest_request_type = None
|
|
self.latest_request_timestamp = 0
|
|
self.latest_requestId = 0
|
|
self.latest_handled_request_id = 0
|
|
self.config = TrackDirectConfig()
|
|
self.no_real_time = False
|
|
self.disconnected = False
|
|
|
|
def is_reset(self):
|
|
"""Returns True if state just has been reset."""
|
|
return not (self.stations_on_map_dict or
|
|
self.max_complete_station_timestamp_dict or
|
|
self.max_all_station_timestamp_dict or
|
|
self.max_map_sector_packet_timestamp_dict or
|
|
self.max_map_sector_overwrite_packet_timestamp_dict)
|
|
|
|
def reset(self):
|
|
"""Reset information related to what stations have been added to the map."""
|
|
self.stations_on_map_dict = {}
|
|
self.max_complete_station_timestamp_dict = {}
|
|
self.max_all_station_timestamp_dict = {}
|
|
self.max_map_sector_packet_timestamp_dict = {}
|
|
self.max_map_sector_overwrite_packet_timestamp_dict = {}
|
|
|
|
def total_reset(self):
|
|
"""Reset everything."""
|
|
self.reset()
|
|
self.latest_minutes_request = 60
|
|
self.latest_time_travel_request = None
|
|
self.only_latest_packet_requested = None
|
|
self.latest_ne_lat = 0
|
|
self.latest_ne_lng = 0
|
|
self.latest_sw_lat = 0
|
|
self.latest_sw_lng = 0
|
|
self.filter_station_id_dict = {}
|
|
|
|
def is_map_empty(self):
|
|
"""Returns True if map is empty."""
|
|
return not (self.max_map_sector_packet_timestamp_dict or
|
|
self.max_map_sector_overwrite_packet_timestamp_dict or
|
|
self.max_complete_station_timestamp_dict or
|
|
self.max_all_station_timestamp_dict)
|
|
|
|
def is_stations_on_map(self, station_ids):
|
|
"""Returns True if all specified stations already exist on the map."""
|
|
return all(stationId in self.stations_on_map_dict for stationId in station_ids)
|
|
|
|
def is_station_history_on_map(self, station_id):
|
|
"""Returns True if specified station already has its history on the map."""
|
|
return station_id in self.max_complete_station_timestamp_dict
|
|
|
|
def get_station_latest_timestamp_on_map(self, station_id, only_include_complete=True):
|
|
"""Returns the timestamp of the latest sent packet to client."""
|
|
if not only_include_complete and station_id in self.max_all_station_timestamp_dict:
|
|
return self.max_all_station_timestamp_dict[station_id]
|
|
return self.max_complete_station_timestamp_dict.get(station_id)
|
|
|
|
def is_valid_latest_position(self):
|
|
"""Returns True if latest requested map bounds are valid."""
|
|
return not (self.latest_ne_lat == 0 and self.latest_ne_lng == 0 and
|
|
self.latest_sw_lat == 0 and self.latest_sw_lng == 0)
|
|
|
|
def is_map_sector_known(self, map_sector):
|
|
"""Returns True if we have added any stations with complete history to this map sector."""
|
|
return map_sector in self.max_map_sector_packet_timestamp_dict
|
|
|
|
def get_map_sector_timestamp(self, map_sector):
|
|
"""Returns the latest handled timestamp in specified map sector."""
|
|
if map_sector in self.max_map_sector_packet_timestamp_dict:
|
|
return self.max_map_sector_packet_timestamp_dict[map_sector]
|
|
if self.only_latest_packet_requested and map_sector in self.max_map_sector_overwrite_packet_timestamp_dict:
|
|
return self.max_map_sector_overwrite_packet_timestamp_dict[map_sector]
|
|
if self.latest_time_travel_request is not None:
|
|
return int(self.latest_time_travel_request) - (int(self.latest_minutes_request) * 60)
|
|
return int(time.time()) - (int(self.latest_minutes_request) * 60)
|
|
|
|
def get_visible_map_sectors(self):
|
|
"""Get the map sectors currently visible."""
|
|
max_lat = self.latest_ne_lat
|
|
max_lng = self.latest_ne_lng
|
|
min_lat = self.latest_sw_lat
|
|
min_lng = self.latest_sw_lng
|
|
|
|
result = []
|
|
if max_lng < min_lng:
|
|
result.extend(self.get_map_sectors_by_interval(min_lat, max_lat, min_lng, 180.0))
|
|
min_lng = -180.0
|
|
|
|
result.extend(self.get_map_sectors_by_interval(min_lat, max_lat, min_lng, max_lng))
|
|
return result[::-1]
|
|
|
|
def get_map_sectors_by_interval(self, min_lat, max_lat, min_lng, max_lng):
|
|
"""Get the map sectors for specified interval."""
|
|
result = []
|
|
map_sector_policy = MapSectorPolicy()
|
|
min_area_code = map_sector_policy.get_map_sector(min_lat, min_lng)
|
|
max_area_code = map_sector_policy.get_map_sector(max_lat, max_lng)
|
|
if min_area_code is not None and max_area_code is not None:
|
|
lng_diff = int(ceil(max_lng)) - int(ceil(min_lng))
|
|
area_code = min_area_code
|
|
while area_code <= max_area_code:
|
|
if area_code % 10 == 5:
|
|
result.append(area_code)
|
|
else:
|
|
result.append(area_code)
|
|
result.append(area_code + 5)
|
|
|
|
for i in range(1, lng_diff + 1):
|
|
if area_code % 10 == 5:
|
|
result.append(area_code + (10 * i) - 5)
|
|
result.append(area_code + (10 * i))
|
|
else:
|
|
result.append(area_code + (10 * i))
|
|
result.append(area_code + (10 * i) + 5)
|
|
|
|
area_code += 20000
|
|
|
|
return result
|
|
|
|
def set_latest_minutes(self, minutes, reference_time):
|
|
"""Set the latest requested number of minutes, returns True if something has changed."""
|
|
if minutes is None:
|
|
minutes = 60
|
|
elif len(self.filter_station_id_dict) == 0 and int(minutes) > int(self.config.max_default_time):
|
|
minutes = int(self.config.max_default_time)
|
|
elif len(self.filter_station_id_dict) > 0 and int(minutes) > int(self.config.max_filter_time):
|
|
minutes = int(self.config.max_filter_time)
|
|
|
|
if not self.config.allow_time_travel and int(minutes) > 1440:
|
|
minutes = 1440
|
|
|
|
if reference_time is not None and reference_time < 0:
|
|
reference_time = 0
|
|
|
|
changed = False
|
|
if self.config.allow_time_travel:
|
|
if ((self.latest_time_travel_request is not None and reference_time is not None and
|
|
self.latest_time_travel_request != reference_time) or
|
|
(self.latest_time_travel_request is not None and reference_time is None) or
|
|
(self.latest_time_travel_request is None and reference_time is not None)):
|
|
self.latest_time_travel_request = reference_time
|
|
self.reset()
|
|
changed = True
|
|
|
|
if self.latest_minutes_request is None or self.latest_minutes_request != minutes:
|
|
self.latest_minutes_request = minutes
|
|
self.reset()
|
|
changed = True
|
|
return changed
|
|
|
|
def set_only_latest_packet_requested(self, only_latest_packet_requested):
|
|
"""Set if only latest packets are requested or not."""
|
|
self.only_latest_packet_requested = only_latest_packet_requested
|
|
|
|
def set_latest_map_bounds(self, ne_lat, ne_lng, sw_lat, sw_lng):
|
|
"""Set map bounds requested by client."""
|
|
if ne_lat is None or ne_lng is None or sw_lat is None or sw_lng is None:
|
|
self.latest_ne_lat = 0
|
|
self.latest_ne_lng = 0
|
|
self.latest_sw_lat = 0
|
|
self.latest_sw_lng = 0
|
|
else:
|
|
self.latest_ne_lat = ne_lat
|
|
self.latest_ne_lng = ne_lng
|
|
self.latest_sw_lat = sw_lat
|
|
self.latest_sw_lng = sw_lng
|
|
|
|
def set_map_sector_latest_overwrite_time_stamp(self, map_sector, timestamp):
|
|
"""Set a new latest handled timestamp for a map sector (overwritable type of packets)."""
|
|
if (map_sector not in self.max_map_sector_overwrite_packet_timestamp_dict or
|
|
self.max_map_sector_overwrite_packet_timestamp_dict[map_sector] < timestamp):
|
|
self.max_map_sector_overwrite_packet_timestamp_dict[map_sector] = timestamp
|
|
|
|
def set_map_sector_latest_time_stamp(self, map_sector, timestamp):
|
|
"""Set a new latest handled timestamp for a map sector."""
|
|
if (map_sector not in self.max_map_sector_packet_timestamp_dict or
|
|
self.max_map_sector_packet_timestamp_dict[map_sector] < timestamp):
|
|
self.max_map_sector_packet_timestamp_dict[map_sector] = timestamp - 1
|
|
|
|
def set_complete_station_latest_timestamp(self, station_id, timestamp):
|
|
"""Set a new latest handled timestamp for a complete station."""
|
|
if (station_id not in self.max_complete_station_timestamp_dict or
|
|
self.max_complete_station_timestamp_dict[station_id] < timestamp):
|
|
self.max_complete_station_timestamp_dict[station_id] = timestamp
|
|
|
|
def set_station_latest_timestamp(self, station_id, timestamp):
|
|
"""Set a new latest handled timestamp for a station."""
|
|
if (station_id not in self.max_all_station_timestamp_dict or
|
|
self.max_all_station_timestamp_dict[station_id] < timestamp):
|
|
self.max_all_station_timestamp_dict[station_id] = timestamp
|
|
|
|
def disable_real_time(self):
|
|
"""Disable real-time functionality."""
|
|
self.no_real_time = True |