01234567890123456789012345678901234567890123456789012345678901234567890123456789
1234567891011121314151617181920 21222324252627282930313233343536373839404142434445464748 4950515253545556575859606162636465666768 63806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402 64036404640564066407640864096410641164126413641464156416641764186419642064216422 6750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792 69046905690669076908690969106911691269136914691569166917691869196920692169226923 69246925692669276928692969306931693269336934693569366937693869396940694169426943 698969906991699269936994699569966997699869997000700170027003700470057006700770087009 70107011701270137014701570167017701870197020702170227023702470257026702770287029 70737074707570767077707870797080708170827083708470857086708770887089709070917092 709370947095709670977098709971007101710271037104710571067107710871097110711171127113 71157116711771187119712071217122712371247125712671277128712971307131713271337134 71357136713771387139714071417142714371447145714671477148714971507151715271537154 72197220722172227223722472257226722772287229723072317232723372347235723672377238 7239724072417242724372447245724672477248724972507251725272537254725572567257725872597260 | #!/usr/bin/python3 import datetime import gc import io import json import math import multiprocessing import numbers import os import pickle import queue import re import shutil import signal import statistics import sys import textwrap import time import tracemalloc import bs4 import dateutils import numpy import matplotlib import matplotlib.pyplot import psutil import pycurl import pytz import requests import tzlocal import unidecode # pylint: disable=line-too-long from constants import RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, KEY, SECRET, SUBSCRIPTION_ID # pylint: enable=line-too-long import arduino if RASPBERRY_PI: import gpiozero # pylint: disable=E0401 import RPi.GPIO # pylint: disable=E0401 VERBOSE = False # additional messages logged SHUTDOWN_SIGNAL = '' REBOOT_SIGNAL = False SIMULATION = False SIMULATION_COUNTER = 0 SIMULATION_PREFIX = 'SIM_' PICKLE_DUMP_JSON_FILE = 'pickle/dump_json.pk' PICKLE_FA_JSON_FILE = 'pickle/fa_json.pk' MEMORY_DIRECTORY = 'memory/' DUMP_JSONS = None # loaded only if in simulation mode FA_JSONS = None # loaded only if in simulation mode HOME_LAT = 37.64406 HOME_LON = -122.43463 HOME = (HOME_LAT, HOME_LON) # lat / lon tuple of antenna HOME_ALT = 29 #altitude in meters RADIUS = 6371.0e3 # radius of earth in meters FEET_IN_METER = 3.28084 FEET_IN_MILE = 5280 METERS_PER_SECOND_IN_KNOTS = 0.514444 <----SKIPPED LINES----> body_as_file_object = io.StringIO(body_as_json_string) # prepare and send. See also: pycurl.READFUNCTION to pass function instead curl.setopt(pycurl.READDATA, body_as_file_object) curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string)) failure_message = '' try: curl.perform() except pycurl.error as e: timing_message = CurlTimingDetailsToString(curl) failure_message = ( 'curl.perform() failed with message %s; timing details: %s' % (e, timing_message)) Log(failure_message) error_code = True else: # you may want to check HTTP response code, e.g. timing_message = CurlTimingDetailsToString(curl) status_code = curl.getinfo(pycurl.RESPONSE_CODE) if status_code != 200: Log( 'Server returned HTTP status code %d for message %s; ' 'timing details: %s' % (status_code, s, timing_message)) error_code = True curl.close() UpdateStatusLight( GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message) def CurlTimingDetailsToString(curl): """Extracts timing details of a curl request into a readable string.""" timing = {} timing['total-time'] = curl.getinfo(pycurl.TOTAL_TIME) timing['namelookup-time'] = curl.getinfo(pycurl.NAMELOOKUP_TIME) timing['connect-time'] = curl.getinfo(pycurl.CONNECT_TIME) timing['pretransfer-time'] = curl.getinfo(pycurl.PRETRANSFER_TIME) timing['redirect-time'] = curl.getinfo(pycurl.REDIRECT_TIME) timing['starttransfer-time'] = curl.getinfo(pycurl.STARTTRANSFER_TIME) results = [label + '=' + '%.4f' % timing[label] for label in timing] results = '; '.join(results) return results <----SKIPPED LINES----> """Writes to disk a tuple with status details about a particular system. The independent monitoring.py module allows us to see in one place the status of all the subsystems and of the overall system; it does that monitoring based on these tuples of data. Args: value: Boolean indicating whether a failure has occurred (True) or system is nominal (False). subsystem: A tuple describing the system; though that description may have multiple attributes, the 0th element is the numeric identifier of that system. monitoring.py depends on other attributes of that tuple being present as well. Since the overall system does not have a tuple defined for it, it gets a default identifier of 0. failure_message: an (optional) message describing why the system / subsystem is being disabled or failing. """ versions = (VERSION_MESSAGEBOARD, VERSION_ARDUINO) if subsystem: subsystem = subsystem[0] PickleObjectToFile( (time.time(), subsystem, value, versions, failure_message), PICKLE_DASHBOARD, True) def RemoveFile(file): """Removes a file, returning a boolean indicating if it had existed.""" if os.path.exists(file): try: os.remove(file) except PermissionError: return False return True return False def ConfirmNewFlight(flight, flights): """Replaces last-seen flight with new flight if identifiers overlap. Flights are identified by the radio over time by a tuple of identifiers: flight_number and squawk. Due to unknown communication issues, one or the <----SKIPPED LINES----> VERSION_MESSAGEBOARD = MakeVersionCopy('messageboard') VERSION_ARDUINO = MakeVersionCopy('arduino') def MakeVersionCopy(python_prefix): """Copies current instance of python file into repository.""" file_extension = '.py' live_name = python_prefix + '.py' live_path = os.path.join(CODE_REPOSITORY, live_name) epoch = os.path.getmtime(live_path) last_modified_suffix = EpochDisplayTime( epoch, format_string='-%Y-%m-%d-%H%M') version_name = python_prefix + last_modified_suffix + file_extension version_path = os.path.join(VERSION_REPOSITORY, version_name) if not os.path.exists(version_path): shutil.copyfile(live_path, version_path) return version_name def DumpMemorySnapsnot( configuration, iteration, main_start_time, initial_frame_count): """Dump the memory snapshot to disk for later analysis. This dumps the memory snapshot to disk with a file name defined by the timestamp and iteration, in the directory MEMORY_DIRECTORY, for later analysis by tracemalloc load class; this can be used to do a memory leak detection by looking at a single snapshot, or potentially by doing a compare_to to look at the deltas from an earlier snapshot. If the 'memory' configuration is greater than 0, then snapshotting is enabled and we dump the configuration every time iteration is evenly divisible by 1000 times the 'memory' setting (because the setting as described on the settings.php page is in thousands of iterations). Args: configuration: dictionary of configuration attributes. iteration: counter that indicates how many times through the main <----SKIPPED LINES----> # Redirect any errors to a log file instead of the screen, and add a datestamp if not SIMULATION: sys.stderr = open(STDERR_FILE, 'a') Log('', STDERR_FILE) init_timing.append((time.time(), 1)) Log('Starting up process %d' % os.getpid()) already_running_ids = FindRunningParents() if already_running_ids: for pid in already_running_ids: Log('Sending termination signal to %d' % pid) os.kill(pid, signal.SIGTERM) init_timing.append((time.time(), 2)) SetPinMode() configuration = ReadAndParseSettings(CONFIG_FILE) Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration))) initial_frame_count = configuration.get('memory_frames', 1) if configuration.get('memory', 0): tracemalloc.start(initial_frame_count) startup_time = time.time() json_desc_dict = {} init_timing.append((time.time(), 3)) flights = UnpickleObjectFromFile( PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS, heartbeat=True) # Clear the loaded flight of any cached data, identified by keys # with a specific suffix, since code fixes may change the values for # some of those cached elements init_timing.append((time.time(), 4)) for flight in flights: for key in list(flight.keys()): if key.endswith(CACHED_ELEMENT_PREFIX): flight.pop(key) init_timing.append((time.time(), 5)) screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2) <----SKIPPED LINES----> # time is long, we don't wait another x seconds after processing completes next_loop_time = time.time() + LOOP_DELAY_SECONDS # These files are read only if the version on disk has been modified more # recently than the last time it was read last_dump_json_timestamp = 0 init_timing.append((time.time(), 7)) WaitUntilKillComplete(already_running_ids) init_timing.append((time.time(), 8)) personal_message = None # Unknown what personal message is displayed temp_last_logged = 0 # Keeps track of when temperature was last logged LogTimes(init_timing) reboot = False iteration = 0 # counter that tracks how many times thru while loop start_time = time.time() DumpMemorySnapsnot(configuration, iteration, start_time, initial_frame_count) Log('Finishing initialization of %d; starting radio polling loop' % os.getpid()) while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS)) and not SHUTDOWN_SIGNAL): last_heartbeat_time = Heartbeat(last_heartbeat_time) new_configuration = ReadAndParseSettings(CONFIG_FILE) UpdateRollingLogSize(new_configuration) CheckForNewFilterCriteria( configuration, new_configuration, message_queue, flights) configuration = new_configuration ResetLogs(configuration) # clear the logs if requested UpdateRollingLogSize(configuration) # if this is a SIMULATION, then process every diff dump. But if it # isn't a simulation, then only read & do related processing for the # next dump if the last-modified timestamp indicates the file has been <----SKIPPED LINES----> tmp_timestamp = 0 if not SIMULATION: dump_json_exists = os.path.exists(DUMP_JSON_FILE) if dump_json_exists: tmp_timestamp = os.path.getmtime(DUMP_JSON_FILE) if (SIMULATION and DumpJsonChanges()) or ( not SIMULATION and dump_json_exists and tmp_timestamp > last_dump_json_timestamp): last_dump_json_timestamp = tmp_timestamp (persistent_nearby_aircraft, flight, now, json_desc_dict, persistent_path) = ScanForNewFlights( persistent_nearby_aircraft, persistent_path, configuration.get('log_jsons', False), flights) # because this might just be an updated instance of the previous # flight as more identifier information (squawk and or flight number) # comes in, we only want to process this if its a truly new flight new_flight_flag = ConfirmNewFlight(flight, flights) if new_flight_flag: flights.append(flight) remote, servo = RefreshArduinos( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration, screen_history) if FlightMeetsDisplayCriteria(flight, configuration, log=True): personal_message = None # Any personal message displayed now cleared flight_message = ( FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight) # display the next message about this flight now! next_message_time = time.time() message_queue.insert(0, flight_message) <----SKIPPED LINES----> # check time & if appropriate, display next message from queue next_message_time = ManageMessageQueue( message_queue, next_message_time, configuration, screen_history) reboot = CheckRebootNeeded( startup_time, message_queue, json_desc_dict, configuration) temp_last_logged = CheckTemperature(configuration, temp_last_logged) if not SIMULATION: time.sleep(max(0, next_loop_time - time.time())) next_loop_time = time.time() + LOOP_DELAY_SECONDS else: SIMULATION_COUNTER += 1 if simulation_slowdown: SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft) # now that we've completed the loop, lets potentially dump the # memory snapshot iteration += 1 # this completes the iteration-th time thru the loop DumpMemorySnapsnot( configuration, iteration, start_time, initial_frame_count) if SIMULATION: SimulationEnd(message_queue, flights, screen_history) PerformGracefulShutdown(shutdown, reboot) if __name__ == "__main__": #interrupt, as in ctrl-c signal.signal(signal.SIGINT, InterruptShutdownFromSignal) #terminate, when another instance found or via kill signal.signal(signal.SIGTERM, InterruptShutdownFromSignal) if '-i' in sys.argv: BootstrapInsightList() else: main_settings = ReadAndParseSettings(CONFIG_FILE) if 'code_profiling_enabled' in main_settings: import cProfile cProfile.run( <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 63856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428 6756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798 691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969 701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056 7100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142 714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194 7259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301 | #!/usr/bin/python3 import datetime import gc import io import json import math import multiprocessing import numbers import os import pickle import queue import re import shutil import signal import statistics import sys import textwrap import time import tracemalloc import types import bs4 import dateutils import numpy import matplotlib import matplotlib.pyplot import psutil import pycurl import pytz import requests import tzlocal import unidecode # pylint: disable=line-too-long from constants import RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, KEY, SECRET, SUBSCRIPTION_ID # pylint: enable=line-too-long import arduino if RASPBERRY_PI: import gpiozero # pylint: disable=E0401 import RPi.GPIO # pylint: disable=E0401 VERBOSE = False # additional messages logged SHUTDOWN_SIGNAL = '' REBOOT_SIGNAL = False # to be tracked in the dashboard messages so that we know when a # restart due to exit (vs. a long delay in some processing) happened INSTANCE_START_TIME = time.time() SIMULATION = False SIMULATION_COUNTER = 0 SIMULATION_PREFIX = 'SIM_' PICKLE_DUMP_JSON_FILE = 'pickle/dump_json.pk' PICKLE_FA_JSON_FILE = 'pickle/fa_json.pk' MEMORY_DIRECTORY = 'memory/' DUMP_JSONS = None # loaded only if in simulation mode FA_JSONS = None # loaded only if in simulation mode HOME_LAT = 37.64406 HOME_LON = -122.43463 HOME = (HOME_LAT, HOME_LON) # lat / lon tuple of antenna HOME_ALT = 29 #altitude in meters RADIUS = 6371.0e3 # radius of earth in meters FEET_IN_METER = 3.28084 FEET_IN_MILE = 5280 METERS_PER_SECOND_IN_KNOTS = 0.514444 <----SKIPPED LINES----> body_as_file_object = io.StringIO(body_as_json_string) # prepare and send. See also: pycurl.READFUNCTION to pass function instead curl.setopt(pycurl.READDATA, body_as_file_object) curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string)) failure_message = '' try: curl.perform() except pycurl.error as e: timing_message = CurlTimingDetailsToString(curl) failure_message = ( 'curl.perform() failed with message %s; timing details: %s' % (e, timing_message)) Log(failure_message) error_code = True else: # you may want to check HTTP response code, e.g. timing_message = CurlTimingDetailsToString(curl) status_code = curl.getinfo(pycurl.RESPONSE_CODE) if status_code != 200: failure_message = ( 'Server returned HTTP status code %d for message %s; ' 'timing details: %s' % (status_code, s, timing_message)) Log(failure_message) error_code = True curl.close() UpdateStatusLight( GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message) def CurlTimingDetailsToString(curl): """Extracts timing details of a curl request into a readable string.""" timing = {} timing['total-time'] = curl.getinfo(pycurl.TOTAL_TIME) timing['namelookup-time'] = curl.getinfo(pycurl.NAMELOOKUP_TIME) timing['connect-time'] = curl.getinfo(pycurl.CONNECT_TIME) timing['pretransfer-time'] = curl.getinfo(pycurl.PRETRANSFER_TIME) timing['redirect-time'] = curl.getinfo(pycurl.REDIRECT_TIME) timing['starttransfer-time'] = curl.getinfo(pycurl.STARTTRANSFER_TIME) results = [label + '=' + '%.4f' % timing[label] for label in timing] results = '; '.join(results) return results <----SKIPPED LINES----> """Writes to disk a tuple with status details about a particular system. The independent monitoring.py module allows us to see in one place the status of all the subsystems and of the overall system; it does that monitoring based on these tuples of data. Args: value: Boolean indicating whether a failure has occurred (True) or system is nominal (False). subsystem: A tuple describing the system; though that description may have multiple attributes, the 0th element is the numeric identifier of that system. monitoring.py depends on other attributes of that tuple being present as well. Since the overall system does not have a tuple defined for it, it gets a default identifier of 0. failure_message: an (optional) message describing why the system / subsystem is being disabled or failing. """ versions = (VERSION_MESSAGEBOARD, VERSION_ARDUINO) if subsystem: subsystem = subsystem[0] PickleObjectToFile(( time.time(), subsystem, value, versions, failure_message, INSTANCE_START_TIME), PICKLE_DASHBOARD, True) def RemoveFile(file): """Removes a file, returning a boolean indicating if it had existed.""" if os.path.exists(file): try: os.remove(file) except PermissionError: return False return True return False def ConfirmNewFlight(flight, flights): """Replaces last-seen flight with new flight if identifiers overlap. Flights are identified by the radio over time by a tuple of identifiers: flight_number and squawk. Due to unknown communication issues, one or the <----SKIPPED LINES----> VERSION_MESSAGEBOARD = MakeVersionCopy('messageboard') VERSION_ARDUINO = MakeVersionCopy('arduino') def MakeVersionCopy(python_prefix): """Copies current instance of python file into repository.""" file_extension = '.py' live_name = python_prefix + '.py' live_path = os.path.join(CODE_REPOSITORY, live_name) epoch = os.path.getmtime(live_path) last_modified_suffix = EpochDisplayTime( epoch, format_string='-%Y-%m-%d-%H%M') version_name = python_prefix + last_modified_suffix + file_extension version_path = os.path.join(VERSION_REPOSITORY, version_name) if not os.path.exists(version_path): shutil.copyfile(live_path, version_path) return version_name BLACKLIST = type, types.ModuleType, types.FunctionType def GetSize(obj): """Returns number of bytes an object uses.""" if isinstance(obj, BLACKLIST): raise TypeError( 'getsize() does not take argument of type: '+ str(type(obj))) seen_ids = set() size = 0 objects = [obj] while objects: need_referents = [] for o in objects: if not isinstance(o, BLACKLIST) and id(o) not in seen_ids: seen_ids.add(id(o)) size += sys.getsizeof(o) need_referents.append(o) objects = gc.get_referents(*need_referents) return size def DumpMemorySnapsnot( configuration, iteration, main_start_time, initial_frame_count): """Dump the memory snapshot to disk for later analysis. This dumps the memory snapshot to disk with a file name defined by the timestamp and iteration, in the directory MEMORY_DIRECTORY, for later analysis by tracemalloc load class; this can be used to do a memory leak detection by looking at a single snapshot, or potentially by doing a compare_to to look at the deltas from an earlier snapshot. If the 'memory' configuration is greater than 0, then snapshotting is enabled and we dump the configuration every time iteration is evenly divisible by 1000 times the 'memory' setting (because the setting as described on the settings.php page is in thousands of iterations). Args: configuration: dictionary of configuration attributes. iteration: counter that indicates how many times through the main <----SKIPPED LINES----> # Redirect any errors to a log file instead of the screen, and add a datestamp if not SIMULATION: sys.stderr = open(STDERR_FILE, 'a') Log('', STDERR_FILE) init_timing.append((time.time(), 1)) Log('Starting up process %d' % os.getpid()) already_running_ids = FindRunningParents() if already_running_ids: for pid in already_running_ids: Log('Sending termination signal to %d' % pid) os.kill(pid, signal.SIGTERM) init_timing.append((time.time(), 2)) SetPinMode() configuration = ReadAndParseSettings(CONFIG_FILE) Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration))) initial_frame_count = configuration.get('memory_frames', 1) initial_memory_dump = configuration.get('memory', 0) if initial_memory_dump: tracemalloc.start(initial_frame_count) startup_time = time.time() json_desc_dict = {} init_timing.append((time.time(), 3)) flights = UnpickleObjectFromFile( PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS, heartbeat=True) # Clear the loaded flight of any cached data, identified by keys # with a specific suffix, since code fixes may change the values for # some of those cached elements init_timing.append((time.time(), 4)) for flight in flights: for key in list(flight.keys()): if key.endswith(CACHED_ELEMENT_PREFIX): flight.pop(key) init_timing.append((time.time(), 5)) screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2) <----SKIPPED LINES----> # time is long, we don't wait another x seconds after processing completes next_loop_time = time.time() + LOOP_DELAY_SECONDS # These files are read only if the version on disk has been modified more # recently than the last time it was read last_dump_json_timestamp = 0 init_timing.append((time.time(), 7)) WaitUntilKillComplete(already_running_ids) init_timing.append((time.time(), 8)) personal_message = None # Unknown what personal message is displayed temp_last_logged = 0 # Keeps track of when temperature was last logged LogTimes(init_timing) reboot = False iteration = 0 # counter that tracks how many times thru while loop start_time = time.time() if initial_memory_dump: DumpMemorySnapsnot( configuration, iteration, start_time, initial_frame_count) Log('Finishing initialization of %d; starting radio polling loop' % os.getpid()) while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS)) and not SHUTDOWN_SIGNAL): last_heartbeat_time = Heartbeat(last_heartbeat_time) new_configuration = ReadAndParseSettings(CONFIG_FILE) UpdateRollingLogSize(new_configuration) CheckForNewFilterCriteria( configuration, new_configuration, message_queue, flights) configuration = new_configuration ResetLogs(configuration) # clear the logs if requested UpdateRollingLogSize(configuration) # if this is a SIMULATION, then process every diff dump. But if it # isn't a simulation, then only read & do related processing for the # next dump if the last-modified timestamp indicates the file has been <----SKIPPED LINES----> tmp_timestamp = 0 if not SIMULATION: dump_json_exists = os.path.exists(DUMP_JSON_FILE) if dump_json_exists: tmp_timestamp = os.path.getmtime(DUMP_JSON_FILE) if (SIMULATION and DumpJsonChanges()) or ( not SIMULATION and dump_json_exists and tmp_timestamp > last_dump_json_timestamp): last_dump_json_timestamp = tmp_timestamp (persistent_nearby_aircraft, flight, now, json_desc_dict, persistent_path) = ScanForNewFlights( persistent_nearby_aircraft, persistent_path, configuration.get('log_jsons', False), flights) # DEBUG: As part of the memory instrumentation, let's track # the size of these data structures iteration_divisor = configuration.get('memory', 0) if iteration_divisor and not iteration % iteration_divisor: sizes = [ GetSize(persistent_nearby_aircraft), GetSize(flight), GetSize(json_desc_dict), GetSize(flights)] Log('Iteration: %d: object sizes (bytes): %s' % (iteration, sizes)) # because this might just be an updated instance of the previous # flight as more identifier information (squawk and or flight number) # comes in, we only want to process this if its a truly new flight new_flight_flag = ConfirmNewFlight(flight, flights) if new_flight_flag: flights.append(flight) remote, servo = RefreshArduinos( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration, screen_history) if FlightMeetsDisplayCriteria(flight, configuration, log=True): personal_message = None # Any personal message displayed now cleared flight_message = ( FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight) # display the next message about this flight now! next_message_time = time.time() message_queue.insert(0, flight_message) <----SKIPPED LINES----> # check time & if appropriate, display next message from queue next_message_time = ManageMessageQueue( message_queue, next_message_time, configuration, screen_history) reboot = CheckRebootNeeded( startup_time, message_queue, json_desc_dict, configuration) temp_last_logged = CheckTemperature(configuration, temp_last_logged) if not SIMULATION: time.sleep(max(0, next_loop_time - time.time())) next_loop_time = time.time() + LOOP_DELAY_SECONDS else: SIMULATION_COUNTER += 1 if simulation_slowdown: SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft) # now that we've completed the loop, lets potentially dump the # memory snapshot iteration += 1 # this completes the iteration-th time thru the loop if initial_memory_dump: DumpMemorySnapsnot( configuration, iteration, start_time, initial_frame_count) if SIMULATION: SimulationEnd(message_queue, flights, screen_history) PerformGracefulShutdown(shutdown, reboot) if __name__ == "__main__": #interrupt, as in ctrl-c signal.signal(signal.SIGINT, InterruptShutdownFromSignal) #terminate, when another instance found or via kill signal.signal(signal.SIGTERM, InterruptShutdownFromSignal) if '-i' in sys.argv: BootstrapInsightList() else: main_settings = ReadAndParseSettings(CONFIG_FILE) if 'code_profiling_enabled' in main_settings: import cProfile cProfile.run( <----SKIPPED LINES----> |