import logging import re from datetime import datetime, timezone from threading import Thread from time import sleep import pytz import telnetlib3 from core.constants import SERVER_OWNER_CALLSIGN from data.spot import Spot from providers.provider import Provider # Provider for a DX Cluster. Hostname and port provided as parameters. class DXCluster(Provider): CALLSIGN_PATTERN = "([a-z|0-9|/]+)" FREQUENCY_PATTERM = "([0-9|.]+)" LINE_PATTERN = re.compile( "^DX de " + CALLSIGN_PATTERN + ":\\s+" + FREQUENCY_PATTERM + "\\s+" + CALLSIGN_PATTERN + "\\s+(.*)\\s+(\\d{4}Z)", re.IGNORECASE) # Constructor requires hostname and port def __init__(self, hostname, port): super().__init__() self.hostname = hostname self.port = port self.telnet = None self.thread = None self.run = True def name(self): return "DX Cluster " + self.hostname def start(self): self.thread = Thread(target=self.handle) self.thread.start() def stop(self): self.run = False self.telnet.close() self.thread.join() def handle(self): while self.run: connected = False while not connected and self.run: try: self.status = "Connecting" self.telnet = telnetlib3.Telnet(self.hostname, self.port) self.telnet.read_until("login: ".encode("ascii")) self.telnet.write((SERVER_OWNER_CALLSIGN + "\n").encode("ascii")) connected = True except Exception as e: self.status = "Error" logging.exception("Exception while connecting to DX Cluster Provider (" + self.hostname + ").") sleep(5) self.status = "Waiting for Data" while connected and self.run: try: # Check new telnet info against regular expression telnet_output = self.telnet.read_until("\n".encode("ascii")) match = self.LINE_PATTERN.match(telnet_output.decode("ascii")) if match: spot_time = datetime.strptime(match.group(5), "%H%MZ") spot_datetime = datetime.combine(datetime.today(), spot_time.time()).replace(tzinfo=pytz.UTC) spot = Spot(source=self.name(), dx_call=match.group(3), de_call=match.group(1), freq=float(match.group(2)), comment=match.group(4).strip(), time=spot_datetime) # Fill in any blanks spot.infer_missing() # Add to our list self.submit([spot]) self.status = "OK" self.last_update_time = datetime.now(timezone.utc) except Exception as e: connected = False if self.run: self.status = "Error" logging.exception("Exception in DX Cluster Provider (" + self.hostname + ")") sleep(5) else: self.status = "Shutting down" self.status = "Disconnected"