""" Android NsdManager API — NsdManager, NsdServiceInfo, DiscoveryListener, RegistrationListener, ResolveListener 方法签名完全对齐 Android SDK """ from __future__ import annotations import os import sys import socket import uuid import threading from typing import Any, Dict, List, Optional, Set, Tuple, Callable from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) # ═══════════════════════════════════════════════════════════════ # 常量 # ═══════════════════════════════════════════════════════════════ # PROTOCOL_* 常量 PROTOCOL_DNS_SD = 0 # FAILURE_* 常量 FAILURE_ALREADY_ACTIVE = 3 FAILURE_INTERNAL_ERROR = 0 FAILURE_MAX_LIMIT = 4 FAILURE_SERVICE_NOT_FOUND = 1 FAILURE_SERVICE_NOT_RUNNING = 2 # DNS_* 常量 DNS_A = 1 DNS_AAAA = 28 DNS_CNAME = 5 DNS_HINFO = 13 DNS_MX = 15 DNS_NS = 2 DNS_PTR = 12 DNS_SOA = 6 DNS_SRV = 33 DNS_TXT = 16 DNS_WKS = 11 DNS_ANY = 255 # SERVICE_TYPE 常量 SERVICE_TYPE_HTTP = "_http._tcp" SERVICE_TYPE_HTTPS = "_https._tcp" SERVICE_TYPE_FTP = "_ftp._tcp" SERVICE_TYPE_SSH = "_ssh._tcp" SERVICE_TYPE_SMTP = "_smtp._tcp" SERVICE_TYPE_IMAP = "_imap._tcp" SERVICE_TYPE_AIRPLAY = "_airplay._tcp" SERVICE_TYPE_GOOGLECAST = "_googlecast._tcp" SERVICE_TYPE_DEVICE_INFO = "_device-info._tcp" SERVICE_TYPE_PRINTER = "_printer._tcp" SERVICE_TYPE_SCANNER = "_scanner._tcp" # ═══════════════════════════════════════════════════════════════ # NsdServiceInfo # ═══════════════════════════════════════════════════════════════ class NsdServiceInfo(Stub): """NsdServiceInfo — NSD 服务信息""" def __init__(self): super().__init__() self._service_name: Optional[str] = None self._service_type: Optional[str] = None self._host: Optional[str] = None self._port: int = 0 self._txt_records: Dict[str, bytes] = {} self._attributes: Dict[str, str] = {} self._network: Optional[Any] = None self._interface_index = 0 self._service_id = str(uuid.uuid4()) self._ttl = 120 self._priority = 0 self._weight = 0 self._is_resolved = False self._addresses: List[str] = [] def getServiceName(self) -> Optional[str]: return self._service_name def setServiceName(self, serviceName: str) -> None: self._service_name = serviceName def getServiceType(self) -> Optional[str]: return self._service_type def setServiceType(self, serviceType: str) -> None: self._service_type = serviceType def getHost(self) -> Optional[str]: return self._host def setHost(self, host: str) -> None: self._host = host def getPort(self) -> int: return self._port def setPort(self, port: int) -> None: self._port = port def getTxtRecords(self) -> Dict[str, bytes]: return dict(self._txt_records) def setTxtRecords(self, txtRecords: Dict[str, bytes]) -> None: self._txt_records = dict(txtRecords) def getAttributes(self) -> Dict[str, str]: return dict(self._attributes) def setAttribute(self, key: str, value: str) -> None: self._attributes[key] = value def removeAttribute(self, key: str) -> None: self._attributes.pop(key, None) def getNetwork(self) -> Optional[Any]: return self._network def setNetwork(self, network: Any) -> None: self._network = network def getInterfaceIndex(self) -> int: return self._interface_index def setInterfaceIndex(self, index: int) -> None: self._interface_index = index def getHostAddresses(self) -> List[str]: return list(self._addresses) def addHostAddress(self, address: str) -> None: if address not in self._addresses: self._addresses.append(address) def getServiceId(self) -> str: return self._service_id def getTtl(self) -> int: return self._ttl def setTtl(self, ttl: int) -> None: self._ttl = ttl def getPriority(self) -> int: return self._priority def setPriority(self, priority: int) -> None: self._priority = priority def getWeight(self) -> int: return self._weight def setWeight(self, weight: int) -> None: self._weight = weight def isResolved(self) -> bool: return self._is_resolved def setResolved(self, resolved: bool) -> None: self._is_resolved = resolved def getHostAddress(self) -> Optional[str]: if self._addresses: return self._addresses[0] return self._host def toString(self) -> str: return ( f"NsdServiceInfo(name={self._service_name}, " f"type={self._service_type}, " f"host={self._host}, " f"port={self._port})" ) # ═══════════════════════════════════════════════════════════════ # NsdManager 内部 Listener 类 # ═══════════════════════════════════════════════════════════════ class NsdManagerDiscoveryListener(Stub): """NsdManager.DiscoveryListener — 服务发现监听器""" def __init__(self): super().__init__() def onDiscoveryStarted(self, serviceType: str) -> None: pass def onDiscoveryStopped(self, serviceType: str) -> None: pass def onServiceFound(self, serviceInfo: "NsdServiceInfo") -> None: pass def onServiceLost(self, serviceInfo: "NsdServiceInfo") -> None: pass def onStartDiscoveryFailed(self, serviceType: str, errorCode: int) -> None: pass def onStopDiscoveryFailed(self, serviceType: str, errorCode: int) -> None: pass def onDiscoveryStopped(self, serviceType: str) -> None: pass def toString(self) -> str: return "NsdManager.DiscoveryListener" class NsdManagerRegistrationListener(Stub): """NsdManager.RegistrationListener — 服务注册监听器""" def __init__(self): super().__init__() def onRegistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None: pass def onUnregistrationFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None: pass def onServiceRegistered(self, serviceInfo: "NsdServiceInfo") -> None: pass def onServiceUnregistered(self, serviceInfo: "NsdServiceInfo") -> None: pass def toString(self) -> str: return "NsdManager.RegistrationListener" class NsdManagerResolveListener(Stub): """NsdManager.ResolveListener — 服务解析监听器""" def __init__(self): super().__init__() def onResolveFailed(self, serviceInfo: "NsdServiceInfo", errorCode: int) -> None: pass def onServiceResolved(self, serviceInfo: "NsdServiceInfo") -> None: pass def toString(self) -> str: return "NsdManager.ResolveListener" # ═══════════════════════════════════════════════════════════════ # NsdManager # ═══════════════════════════════════════════════════════════════ class NsdManager(Stub): """NsdManager — 网络服务发现管理器 (桌面存根)""" PROTOCOL_DNS_SD = PROTOCOL_DNS_SD FAILURE_ALREADY_ACTIVE = FAILURE_ALREADY_ACTIVE FAILURE_INTERNAL_ERROR = FAILURE_INTERNAL_ERROR FAILURE_MAX_LIMIT = FAILURE_MAX_LIMIT FAILURE_SERVICE_NOT_FOUND = FAILURE_SERVICE_NOT_FOUND FAILURE_SERVICE_NOT_RUNNING = FAILURE_SERVICE_NOT_RUNNING DiscoveryListener = NsdManagerDiscoveryListener RegistrationListener = NsdManagerRegistrationListener ResolveListener = NsdManagerResolveListener def __init__(self, context: Any = None): super().__init__() self._context = context self._lock = threading.Lock() self._registered_services: Dict[str, NsdServiceInfo] = {} self._discovery_listeners: Dict[str, NsdManagerDiscoveryListener] = {} self._discovery_active: Set[str] = set() self._resolved_services: Dict[str, NsdServiceInfo] = {} self._discovered_services: Dict[str, List[NsdServiceInfo]] = {} self._network_interface: Optional[str] = None self._socket_family = socket.AF_INET self._discovery_timeout = 5000 self._is_available = True def discoverServices( self, serviceType: str, protocolType: int, listener: NsdManagerDiscoveryListener ) -> None: """发现指定类型的服务""" with self._lock: if serviceType in self._discovery_active: listener.onStartDiscoveryFailed(serviceType, FAILURE_ALREADY_ACTIVE) return self._discovery_active.add(serviceType) self._discovery_listeners[serviceType] = listener listener.onDiscoveryStarted(serviceType) # 模拟发现 for srv_id, info in self._registered_services.items(): if info.getServiceType() == serviceType: listener.onServiceFound(info) def stopServiceDiscovery(self, listener: NsdManagerDiscoveryListener) -> None: """停止服务发现""" with self._lock: to_remove = [] for stype, lst in self._discovery_listeners.items(): if lst is listener: to_remove.append(stype) for stype in to_remove: self._discovery_active.discard(stype) del self._discovery_listeners[stype] listener.onDiscoveryStopped(stype) def registerService( self, serviceInfo: NsdServiceInfo, protocolType: int, listener: NsdManagerRegistrationListener ) -> None: """注册本地服务""" with self._lock: srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}" if srv_id in self._registered_services: listener.onRegistrationFailed(serviceInfo, FAILURE_ALREADY_ACTIVE) return self._registered_services[srv_id] = serviceInfo listener.onServiceRegistered(serviceInfo) def unregisterService(self, listener: NsdManagerRegistrationListener) -> None: """注销本地服务""" with self._lock: to_remove = [] for srv_id, info in self._registered_services.items(): to_remove.append(srv_id) for srv_id in to_remove: info = self._registered_services.pop(srv_id) listener.onServiceUnregistered(info) def resolveService( self, serviceInfo: NsdServiceInfo, listener: NsdManagerResolveListener ) -> None: """解析服务(获取主机和端口)""" with self._lock: srv_id = f"{serviceInfo.getServiceName()}:{serviceInfo.getServiceType()}" if srv_id in self._registered_services: resolved = self._registered_services[srv_id] resolved.setResolved(True) if not resolved.getHost(): resolved.setHost("127.0.0.1") if resolved.getPort() == 0: resolved.setPort(8080) self._resolved_services[srv_id] = resolved listener.onServiceResolved(resolved) else: listener.onResolveFailed(serviceInfo, FAILURE_SERVICE_NOT_FOUND) def getDiscoveredServices(self, serviceType: str) -> List[NsdServiceInfo]: """获取已发现的服务列表""" with self._lock: return [ info for info in self._registered_services.values() if info.getServiceType() == serviceType ] def getRegisteredServices(self) -> List[NsdServiceInfo]: """获取所有已注册的服务""" with self._lock: return list(self._registered_services.values()) def isDiscoveryActive(self, serviceType: str) -> bool: """检查指定类型的发现是否活跃""" with self._lock: return serviceType in self._discovery_active def setNetworkInterface(self, iface: str) -> None: """设置网络接口""" self._network_interface = iface def getNetworkInterface(self) -> Optional[str]: return self._network_interface def setDiscoveryTimeout(self, timeoutMs: int) -> None: self._discovery_timeout = timeoutMs def getDiscoveryTimeout(self) -> int: return self._discovery_timeout def isAvailable(self) -> bool: return self._is_available def destroy(self) -> None: with self._lock: self._discovery_active.clear() self._discovery_listeners.clear() self._registered_services.clear() self._resolved_services.clear() self._is_available = False def toString(self) -> str: with self._lock: return ( f"NsdManager(registered={len(self._registered_services)}, " f"active_discoveries={len(self._discovery_active)})" ) # ═══════════════════════════════════════════════════════════ # NsdManager 补充功能 # ═══════════════════════════════════════════════════════════ def getServiceInfo(self, serviceName: str) -> Optional[NsdServiceInfo]: """通过名称获取已注册的服务信息""" with self._lock: for srv_id, info in self._registered_services.items(): if info.getServiceName() == serviceName: return info return None def removeService(self, serviceName: str) -> bool: """移除已注册的服务""" with self._lock: to_remove = [ srv_id for srv_id, info in self._registered_services.items() if info.getServiceName() == serviceName ] for srv_id in to_remove: del self._registered_services[srv_id] return len(to_remove) > 0 def getResolvedService(self, serviceName: str) -> Optional[NsdServiceInfo]: """获取已解析的服务""" with self._lock: for srv_id, info in self._resolved_services.items(): if info.getServiceName() == serviceName: return info return None def getResolvedServices(self) -> List[NsdServiceInfo]: """获取所有已解析的服务""" with self._lock: return list(self._resolved_services.values()) def getAllDiscoveredServices(self) -> List[NsdServiceInfo]: """获取所有已发现的服务""" with self._lock: return [ info for info in self._registered_services.values() if info.isResolved() ] def getActiveDiscoveryCount(self) -> int: """获取活跃发现数量""" with self._lock: return len(self._discovery_active) def getActiveDiscoveryTypes(self) -> List[str]: """获取正在发现的服务类型列表""" with self._lock: return list(self._discovery_active) def createServiceInfo( self, serviceName: str, serviceType: str, port: int = 0 ) -> NsdServiceInfo: """创建服务信息对象""" info = NsdServiceInfo() info.setServiceName(serviceName) info.setServiceType(serviceType) info.setPort(port) info.setHost("127.0.0.1") return info class NsdServiceInfoBuilder(Stub): """NsdServiceInfo.Builder — 服务信息构建器""" def __init__(self): super().__init__() self._info = NsdServiceInfo() def setServiceName(self, name: str) -> "NsdServiceInfoBuilder": self._info.setServiceName(name) return self def setServiceType(self, serviceType: str) -> "NsdServiceInfoBuilder": self._info.setServiceType(serviceType) return self def setHost(self, host: str) -> "NsdServiceInfoBuilder": self._info.setHost(host) return self def setPort(self, port: int) -> "NsdServiceInfoBuilder": self._info.setPort(port) return self def setTxtRecords(self, records: Dict[str, bytes]) -> "NsdServiceInfoBuilder": self._info.setTxtRecords(records) return self def addAttribute(self, key: str, value: str) -> "NsdServiceInfoBuilder": self._info.setAttribute(key, value) return self def setNetwork(self, network: Any) -> "NsdServiceInfoBuilder": self._info.setNetwork(network) return self def build(self) -> NsdServiceInfo: return self._info def toString(self) -> str: return f"NsdServiceInfoBuilder(name={self._info.getServiceName()})"