Source code for discovery_client_django.management.commands.discover_servers

"""
Django management command to discover django-udp-discovery servers.

Usage:
    python manage.py discover_servers
    python manage.py discover_servers --timeout 10.0
    python manage.py discover_servers --port 9999
"""
from django.core.management.base import BaseCommand
from django.core.management import CommandError
from discovery_client import discover, ClientConfig, DiscoveryResult
from discovery_client.network.socket import (
    detect_segmented_network,
    format_segmented_network_warning,
)
from discovery_client.network.interfaces import select_interfaces
from typing import List


[docs] class Command(BaseCommand): """Management command to discover django-udp-discovery servers.""" help = 'Discover django-udp-discovery servers on the local network'
[docs] def add_arguments(self, parser): """Add command-line arguments.""" parser.add_argument( '--timeout', type=float, default=5.0, help='Discovery timeout in seconds (default: 5.0)', ) parser.add_argument( '--port', type=int, default=9999, help='Discovery port (default: 9999)', ) parser.add_argument( '--message', type=str, default='DISCOVER_SERVER', help='Discovery message (default: DISCOVER_SERVER)', ) parser.add_argument( '--response-prefix', type=str, default='SERVER_IP:', help='Expected response prefix (default: SERVER_IP:)', ) parser.add_argument( '--interfaces-whitelist', type=str, help='Comma-separated list of interface names to whitelist', ) parser.add_argument( '--interfaces-blacklist', type=str, help='Comma-separated list of interface names to blacklist', ) parser.add_argument( '--verbose', action='store_true', help='Enable verbose output', )
[docs] def handle(self, *args, **options): """Execute the discovery command.""" # Build configuration from command-line arguments config_kwargs = { 'timeout': options['timeout'], 'discovery_port': options['port'], 'discovery_message': options['message'].encode('utf-8'), 'response_prefix': options['response_prefix'].encode('utf-8'), } # Handle interface filters if options['interfaces_whitelist']: config_kwargs['interfaces_whitelist'] = [ name.strip() for name in options['interfaces_whitelist'].split(',') ] if options['interfaces_blacklist']: config_kwargs['interfaces_blacklist'] = [ name.strip() for name in options['interfaces_blacklist'].split(',') ] # Create configuration try: config = ClientConfig(**config_kwargs) except ValueError as e: raise CommandError(f"Invalid configuration: {e}") # Perform discovery if options['verbose']: self.stdout.write( self.style.SUCCESS(f'Starting discovery (timeout: {config.timeout}s, port: {config.discovery_port})...') ) try: servers = discover(config=config) except Exception as e: raise CommandError(f"Discovery failed: {e}") # Display results if not servers: self.stdout.write( self.style.WARNING('No servers found on the network.') ) self.stdout.write( 'Make sure django-udp-discovery servers are running and accessible.' ) # Print segmented network diagnostic exactly once, after all interfaces scanned try: interfaces = select_interfaces(config) segmented_info = detect_segmented_network(interfaces) if interfaces else None if segmented_info: self.stdout.write( format_segmented_network_warning(segmented_info, width=40) ) except ImportError: pass return # Print table of discovered servers self._print_results_table(servers, verbose=options['verbose'])
def _print_results_table(self, servers: List[DiscoveryResult], verbose: bool = False): """ Print a formatted table of discovered servers. Args: servers: List of DiscoveryResult objects verbose: If True, include raw response in output """ self.stdout.write('') self.stdout.write(self.style.SUCCESS(f'Found {len(servers)} server(s):')) self.stdout.write('') # Table header if verbose: header = f"{'IP Address':<18} {'Port':<8} {'Raw Response':<50}" else: header = f"{'IP Address':<18} {'Port':<8} {'URL':<30}" self.stdout.write(self.style.SUCCESS(header)) self.stdout.write(self.style.SUCCESS('-' * len(header))) # Table rows for server in servers: ip = server.ip port = str(server.port) if verbose: raw_response = server.raw_response.decode('utf-8', errors='replace')[:50] row = f"{ip:<18} {port:<8} {raw_response:<50}" else: url = f"http://{ip}:{port}" row = f"{ip:<18} {port:<8} {url:<30}" self.stdout.write(row) # Show extra metadata if available if verbose and server.extra: for key, value in server.extra.items(): self.stdout.write(f" {key}: {value}") self.stdout.write('')