from datetime import datetime, timezone from threading import Thread import pytz from core.constants import SERVER_OWNER_CALLSIGN from data.spot import Spot from providers.provider import Provider import telnetlib3 import re callsign_pattern = "([a-z|0-9|/]+)" frequency_pattern = "([0-9|.]+)" pattern = re.compile("^DX de "+callsign_pattern+":\\s+"+frequency_pattern+"\\s+"+callsign_pattern+"\\s+(.*)\\s+(\\d{4}Z)", re.IGNORECASE) class DXCluster(Provider): # 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 + " " + str(self.port) 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): 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")) self.status = "Waiting for Data" while self.run: # Check new telnet info against regular expression telnet_output = self.telnet.read_until("\n".encode("ascii")) match = 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)