Files
spothole/core/data_providers.py
T

104 lines
4.0 KiB
Python

import logging
import threading
import time
from core.config import config, create_provider_from_config
logger = logging.getLogger(__name__)
class DataProviders:
"""Global object for storing data providers."""
def __init__(self):
self.spot_providers = []
self.alert_providers = []
self.solar_condition_providers = []
self.static_data_providers = []
self.sig_ref_data_providers = []
self.callsign_data_providers = []
self._startup_timers = []
def setup(self):
for entry in config["spot_providers"]:
self.spot_providers.append(create_provider_from_config("providers.spot", entry))
for entry in config["alert_providers"]:
self.alert_providers.append(create_provider_from_config("providers.alert", entry))
for entry in config.get("solar_condition_providers", []):
self.solar_condition_providers.append(create_provider_from_config("providers.solarconditions", entry))
for entry in config.get("static_data_providers", []):
self.static_data_providers.append(create_provider_from_config("providers.staticdata", entry))
for entry in config.get("sig_ref_data_providers", []):
self.sig_ref_data_providers.append(create_provider_from_config("providers.activityrefdata", entry))
for entry in config.get("callsign_data_providers", []):
self.callsign_data_providers.append(create_provider_from_config("providers.callsigndata", entry))
@staticmethod
def start_providers(providers, provider_type):
"""Helper method to activate enabled providers in the list."""
logger.info(f"Starting {provider_type} providers...")
for p in providers:
if p.enabled:
p.start()
def start(self):
# Start data providers before spot/alert providers so the lookup data is there already for incoming spots.
# Each category is fired off after a small delay to give the rest of Spothole chance to start up.
self._startup_timers = [
threading.Timer(5.0, lambda: self.start_providers(self.static_data_providers, "static data")),
threading.Timer(10.0, lambda: self.start_providers(self.callsign_data_providers, "callsign data")),
threading.Timer(15.0, lambda: self.start_providers(self.spot_providers, "spot")),
threading.Timer(20.0, lambda: self.start_providers(self.alert_providers, "alert")),
threading.Timer(
25.0,
lambda: self.start_providers(self.solar_condition_providers, "solar condition"),
),
threading.Timer(30.0, lambda: self.start_providers(self.sig_ref_data_providers, "activity ref data")),
]
for t in self._startup_timers:
t.daemon = True
t.start()
def stop(self):
# Cancel any startup timers that haven't fired yet
for t in self._startup_timers:
t.cancel()
# Stop all providers
all_providers = [
p
for p in (
self.spot_providers
+ self.alert_providers
+ self.solar_condition_providers
+ self.sig_ref_data_providers
+ self.static_data_providers
+ self.callsign_data_providers
)
if p.enabled
]
if not all_providers:
return
def stop_provider(p):
try:
p.stop()
except Exception:
logger.exception("Exception stopping provider")
threads = [threading.Thread(target=stop_provider, args=(p,), daemon=True) for p in all_providers]
for t in threads:
t.start()
deadline = time.monotonic() + 40
for t in threads:
t.join(timeout=max(0.0, deadline - time.monotonic()))
still_running = [t for t in threads if t.is_alive()]
if still_running:
logger.warning("Some threads did not stop in time!")
# Global object
DATA_PROVIDERS = DataProviders()