Просмотр исходного кода

Remove mDNS implementation and zeroconf dependency

- Remove zeroconf from requirements.txt
- Remove mdns module import and startup/shutdown code
- Remove /api/discover-tables endpoint
- Delete modules/core/mdns.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris 3 недель назад
Родитель
Сommit
f0ea6c4f2b
3 измененных файлов с 0 добавлено и 300 удалено
  1. 0 54
      main.py
  2. 0 245
      modules/core/mdns.py
  3. 0 1
      requirements.txt

+ 0 - 54
main.py

@@ -34,7 +34,6 @@ import argparse
 import subprocess
 import platform
 from modules.core import process_pool as pool_module
-from modules.core import mdns
 
 # Get log level from environment variable, default to INFO
 log_level_str = os.getenv('LOG_LEVEL', 'INFO').upper()
@@ -277,23 +276,11 @@ async def lifespan(app: FastAPI):
 
     asyncio.create_task(idle_timeout_monitor())
 
-    # Start mDNS advertisement for multi-table discovery
-    try:
-        await mdns.start_mdns_advertisement()
-    except Exception as e:
-        logger.warning(f"Failed to start mDNS advertisement: {e}")
-
     yield  # This separates startup from shutdown code
 
     # Shutdown
     logger.info("Shutting down Dune Weaver application...")
 
-    # Stop mDNS advertisement
-    try:
-        await mdns.stop_mdns_advertisement()
-    except Exception as e:
-        logger.warning(f"Error stopping mDNS: {e}")
-
     # Shutdown process pool
     pool_module.shutdown_pool(wait=True)
 
@@ -957,47 +944,6 @@ async def update_table_info(update: TableInfoUpdate):
         "name": state.table_name
     }
 
-@app.get("/api/discover-tables", tags=["multi-table"])
-async def discover_tables(timeout: float = 3.0):
-    """
-    Discover other Dune Weaver tables on the local network.
-
-    Uses mDNS/Bonjour to find tables advertising the _duneweaver._tcp service.
-
-    Args:
-        timeout: Discovery timeout in seconds (default 3.0, max 10.0)
-
-    Returns:
-        List of discovered tables with their id, name, host, port, and url
-    """
-    # Clamp timeout to reasonable range
-    timeout = min(max(timeout, 0.5), 10.0)
-
-    tables = await mdns.discover_tables(timeout=timeout)
-
-    # Also include this table in the list
-    local_table = {
-        "id": state.table_id,
-        "name": state.table_name,
-        "host": "localhost",
-        "port": state.server_port or 8080,
-        "version": await version_manager.get_current_version(),
-        "url": f"http://localhost:{state.server_port or 8080}",
-        "is_current": True
-    }
-
-    # Mark discovered tables as not current
-    for table in tables:
-        table["is_current"] = False
-
-    # Filter out self if discovered via mDNS
-    tables = [t for t in tables if t.get("id") != state.table_id]
-
-    return {
-        "tables": [local_table] + tables,
-        "count": len(tables) + 1
-    }
-
 # ============================================================================
 # Individual Settings Endpoints (Deprecated - use /api/settings instead)
 # ============================================================================

+ 0 - 245
modules/core/mdns.py

@@ -1,245 +0,0 @@
-"""mDNS advertisement and discovery for multi-table support.
-
-This module provides:
-- Service advertisement: Allows this table to be discovered by other frontends
-- Service discovery: Finds other Dune Weaver tables on the local network
-"""
-
-import asyncio
-import logging
-import socket
-from typing import List, Dict, Optional
-from zeroconf import ServiceInfo, Zeroconf, ServiceBrowser, ServiceListener
-from zeroconf.asyncio import AsyncZeroconf, AsyncServiceBrowser
-
-logger = logging.getLogger(__name__)
-
-# Service type for Dune Weaver tables
-SERVICE_TYPE = "_duneweaver._tcp.local."
-
-
-class DuneWeaverServiceListener(ServiceListener):
-    """Listener for discovered Dune Weaver services."""
-
-    def __init__(self):
-        self.discovered_tables: Dict[str, Dict] = {}
-
-    def add_service(self, zc: Zeroconf, type_: str, name: str) -> None:
-        """Called when a new service is discovered."""
-        info = zc.get_service_info(type_, name)
-        if info:
-            self._process_service_info(name, info)
-
-    def update_service(self, zc: Zeroconf, type_: str, name: str) -> None:
-        """Called when an existing service is updated."""
-        info = zc.get_service_info(type_, name)
-        if info:
-            self._process_service_info(name, info)
-
-    def remove_service(self, zc: Zeroconf, type_: str, name: str) -> None:
-        """Called when a service is removed."""
-        if name in self.discovered_tables:
-            del self.discovered_tables[name]
-            logger.debug(f"Table removed: {name}")
-
-    def _process_service_info(self, name: str, info: ServiceInfo) -> None:
-        """Extract table information from service info."""
-        try:
-            # Get properties
-            properties = {}
-            if info.properties:
-                for key, value in info.properties.items():
-                    if isinstance(value, bytes):
-                        properties[key.decode() if isinstance(key, bytes) else key] = value.decode()
-                    else:
-                        properties[key if isinstance(key, str) else key.decode()] = str(value)
-
-            # Get addresses
-            addresses = info.parsed_addresses()
-            host = addresses[0] if addresses else None
-            port = info.port
-
-            if host and port:
-                self.discovered_tables[name] = {
-                    "id": properties.get("id", ""),
-                    "name": properties.get("name", name.replace(f".{SERVICE_TYPE}", "")),
-                    "host": host,
-                    "port": port,
-                    "version": properties.get("version", "unknown"),
-                    "url": f"http://{host}:{port}"
-                }
-                logger.debug(f"Discovered table: {self.discovered_tables[name]}")
-        except Exception as e:
-            logger.warning(f"Error processing service info for {name}: {e}")
-
-
-class MDNSManager:
-    """Manages mDNS advertisement and discovery for Dune Weaver."""
-
-    def __init__(self):
-        self._zeroconf: Optional[AsyncZeroconf] = None
-        self._service_info: Optional[ServiceInfo] = None
-        self._browser: Optional[AsyncServiceBrowser] = None
-        self._listener: Optional[DuneWeaverServiceListener] = None
-        self._advertised = False
-
-    def _get_local_ip(self) -> str:
-        """Get the local IP address of this machine."""
-        try:
-            # Create a socket to determine our IP
-            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-            try:
-                # Doesn't need to be reachable
-                s.connect(("10.255.255.255", 1))
-                ip = s.getsockname()[0]
-            except Exception:
-                ip = "127.0.0.1"
-            finally:
-                s.close()
-            return ip
-        except Exception:
-            return "127.0.0.1"
-
-    async def start_advertisement(self, table_id: str, table_name: str, version: str, port: int = 8080) -> bool:
-        """
-        Start advertising this table on the network.
-
-        Args:
-            table_id: Unique identifier for this table
-            table_name: Human-readable name for this table
-            version: Software version
-            port: HTTP port the server is running on
-
-        Returns:
-            True if advertisement started successfully
-        """
-        try:
-            if self._advertised:
-                await self.stop_advertisement()
-
-            local_ip = self._get_local_ip()
-            hostname = socket.gethostname()
-
-            # Create service info
-            # Service name must be unique on the network
-            service_name = f"{table_name.replace(' ', '_')}_{table_id[:8]}.{SERVICE_TYPE}"
-
-            self._service_info = ServiceInfo(
-                SERVICE_TYPE,
-                service_name,
-                addresses=[socket.inet_aton(local_ip)],
-                port=port,
-                properties={
-                    "id": table_id,
-                    "name": table_name,
-                    "version": version,
-                    "hostname": hostname
-                },
-                server=f"{hostname}.local."
-            )
-
-            # Start zeroconf and register service
-            self._zeroconf = AsyncZeroconf()
-            await self._zeroconf.async_register_service(self._service_info)
-            self._advertised = True
-
-            logger.info(f"mDNS: Advertising table '{table_name}' at {local_ip}:{port}")
-            return True
-
-        except Exception as e:
-            logger.error(f"Failed to start mDNS advertisement: {e}")
-            return False
-
-    async def stop_advertisement(self) -> None:
-        """Stop advertising this table."""
-        try:
-            if self._service_info and self._zeroconf:
-                await self._zeroconf.async_unregister_service(self._service_info)
-            if self._zeroconf:
-                await self._zeroconf.async_close()
-            self._advertised = False
-            self._service_info = None
-            self._zeroconf = None
-            logger.info("mDNS: Stopped advertising")
-        except Exception as e:
-            logger.warning(f"Error stopping mDNS advertisement: {e}")
-
-    async def discover_tables(self, timeout: float = 3.0) -> List[Dict]:
-        """
-        Discover Dune Weaver tables on the local network.
-
-        Args:
-            timeout: How long to wait for discovery (seconds)
-
-        Returns:
-            List of discovered tables with their info
-        """
-        discovered = []
-
-        try:
-            # Create an async zeroconf instance for discovery
-            async_zc = AsyncZeroconf()
-            listener = DuneWeaverServiceListener()
-
-            # Start browsing for services using async browser
-            browser = AsyncServiceBrowser(async_zc.zeroconf, SERVICE_TYPE, listener)
-
-            # Wait for discovery
-            await asyncio.sleep(timeout)
-
-            # Collect results
-            discovered = list(listener.discovered_tables.values())
-
-            # Cleanup using async methods
-            browser.cancel()
-            await async_zc.async_close()
-
-            logger.info(f"mDNS: Discovered {len(discovered)} table(s)")
-
-        except Exception as e:
-            logger.error(f"Error during mDNS discovery: {e}")
-
-        return discovered
-
-    async def update_advertisement(self, table_name: str) -> None:
-        """Update the advertised table name."""
-        if self._advertised and self._service_info:
-            # Get current info
-            from modules.core.state import state
-            from modules.core.version_manager import version_manager
-
-            # Restart advertisement with new name
-            await self.stop_advertisement()
-            await self.start_advertisement(
-                table_id=state.table_id,
-                table_name=table_name,
-                version=await version_manager.get_current_version(),
-                port=state.server_port or 8080
-            )
-
-
-# Singleton instance
-mdns_manager = MDNSManager()
-
-
-async def start_mdns_advertisement():
-    """Start mDNS advertisement using current state."""
-    from modules.core.state import state
-    from modules.core.version_manager import version_manager
-
-    await mdns_manager.start_advertisement(
-        table_id=state.table_id,
-        table_name=state.table_name,
-        version=await version_manager.get_current_version(),
-        port=state.server_port or 8080
-    )
-
-
-async def stop_mdns_advertisement():
-    """Stop mDNS advertisement."""
-    await mdns_manager.stop_advertisement()
-
-
-async def discover_tables(timeout: float = 3.0) -> List[Dict]:
-    """Discover Dune Weaver tables on the network."""
-    return await mdns_manager.discover_tables(timeout)

+ 0 - 1
requirements.txt

@@ -13,7 +13,6 @@ websockets>=11.0.3  # Required for FastAPI WebSocket support
 requests>=2.31.0
 Pillow
 aiohttp
-zeroconf>=0.131.0  # mDNS/Bonjour for multi-table discovery
 # GPIO/NeoPixel support for DW LEDs and Desert Compass
 # Note: rpi-lgpio is a drop-in replacement for RPi.GPIO that works on Pi 5
 # Do NOT install both RPi.GPIO and rpi-lgpio - they conflict