# checks.py import socket import threading import urllib.request import urllib.error class SystemChecks: def __init__(self, network_targets, ziti_target): self.network_targets = network_targets self.ziti_target = ziti_target self.network_online = None self.ziti_online = None self._stop_event = threading.Event() self._thread = None @property def ready(self): """Return True when network & ziti are both available""" return ( self.network_online is True and self.ziti_online is True ) def start(self): """Start background status polling""" if self._thread is not None: return self._thread = threading.Thread( target=self._poll, daemon=True ) self._thread.start() def stop(self): """Stop background status polling""" self._stop_event.set() def _poll(self): """Continuously check system status""" while not self._stop_event.is_set(): self.network_online = self.check_network_status() self.ziti_online = self.check_ziti_status() # print( # f"System status => " # f"Network: {self.network_online}, " # f"Ziti: {self.ziti_online}" # ) if self.ready: interval = 30 else: interval = 3 self._stop_event.wait(interval) def check_network_status(self): """Loops through configured network targets and return True if any respond""" for host, port in self.network_targets: if self._tcp_ping(host, int(port), timeout=1.5): return True return False def check_ziti_status(self): """Makes HTTP request to Ziti endpoint""" if not self.ziti_target: return False try: request = urllib.request.Request( self.ziti_target, method="GET", ) with urllib.request.urlopen(request, timeout=2.0) as response: return 200 <= response.status < 300 except (urllib.error.URLError, TimeoutError, OSError): return False def _tcp_ping(self, host, port, timeout=1): try: with socket.create_connection((host, port), timeout=timeout): return True except OSError: return False