# Main script import logging import os import signal import sys from datetime import datetime from time import sleep import psutil import pytz from core.cleanup import CleanupTimer from core.config import config, MAX_SPOT_AGE, WEB_SERVER_PORT, SERVER_OWNER_CALLSIGN from core.constants import SOFTWARE_VERSION from providers.aprsis import APRSIS from providers.dxcluster import DXCluster from providers.gma import GMA from providers.hema import HEMA from providers.parksnpeaks import ParksNPeaks from providers.pota import POTA from providers.rbn import RBN from providers.sota import SOTA from providers.wwbota import WWBOTA from providers.wwff import WWFF from server.webserver import WebServer # Globals spot_list = [] status_data = {} providers = [] cleanup_timer = None run = True # Shutdown function def shutdown(sig, frame): logging.info("Stopping program, this may take a few seconds...") global run run = False for p in providers: if p.enabled: p.stop() cleanup_timer.stop() # Utility method to get a data provider based on its config entry. def get_provider_from_config(config_providers_entry): match config_providers_entry["type"]: case "POTA": return POTA(config_providers_entry) case "SOTA": return SOTA(config_providers_entry) case "WWFF": return WWFF(config_providers_entry) case "GMA": return GMA(config_providers_entry) case "WWBOTA": return WWBOTA(config_providers_entry) case "HEMA": return HEMA(config_providers_entry) case "ParksNPeaks": return ParksNPeaks(config_providers_entry) case "DXCluster": return DXCluster(config_providers_entry) case "RBN": return RBN(config_providers_entry) case "APRS-IS": return APRSIS(config_providers_entry) return None # Main function if __name__ == '__main__': # Set up logging root = logging.getLogger() root.setLevel(logging.INFO) handler = logging.StreamHandler(sys.stdout) handler.setLevel(logging.INFO) formatter = logging.Formatter("%(message)s") handler.setFormatter(formatter) root.addHandler(handler) logging.info("Starting...") startup_time = datetime.now(pytz.UTC) status_data["software-version"] = SOFTWARE_VERSION status_data["server-owner-callsign"] = SERVER_OWNER_CALLSIGN # Shut down gracefully on SIGINT signal.signal(signal.SIGINT, shutdown) for entry in config["providers"]: providers.append(get_provider_from_config(entry)) # Set up data providers for p in providers: p.setup(spot_list=spot_list) # Start data providers for p in providers: if p.enabled: p.start() # Set up timer to clear spot list of old data cleanup_timer = CleanupTimer(spot_list=spot_list, cleanup_interval=60, max_spot_age=MAX_SPOT_AGE) cleanup_timer.start() # Set up web server web_server = WebServer(spot_list=spot_list, status_data=status_data, port=WEB_SERVER_PORT) web_server.start() logging.info("Startup complete.") # While running, update the status information at a regular interval while run: sleep(5) status_data["uptime"] = str(datetime.now(pytz.UTC) - startup_time).split(".")[0] status_data["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3) status_data["num_spots"] = len(spot_list) status_data["providers"] = list(map(lambda p: {"name": p.name, "enabled": p.enabled, "status": p.status, "last_updated": p.last_update_time, "last_spot": p.last_spot_time}, providers)) status_data["cleanup"] = {"status": cleanup_timer.status, "last_ran": cleanup_timer.last_cleanup_time} status_data["webserver"] = {"status": web_server.status, "last_api_access": web_server.last_api_access_time, "last_page_access": web_server.last_page_access_time}