60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""
|
||
设备端 SDK 自动发现 — 监听 UDP beacon(8898),无线主控免手填 IP。
|
||
|
||
与 sdk/app/services/discovery_service.py BEACON 协议对齐。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import socket
|
||
import time
|
||
from typing import Optional
|
||
|
||
BEACON_PORT = 8898
|
||
BEACON_MAGIC = "WORKPHONE_SDK"
|
||
|
||
|
||
def _pick_best_ip(ips: list) -> str:
|
||
"""优先工作手机常用网段,其次任一私网 IP。"""
|
||
for ip in ips:
|
||
if str(ip).startswith("192.168.110."):
|
||
return ip
|
||
for ip in ips:
|
||
if str(ip).startswith(("192.168.", "10.", "172.")):
|
||
return ip
|
||
return str(ips[0])
|
||
|
||
|
||
def discover_sdk_ws_base(timeout: float = 20.0) -> Optional[str]:
|
||
"""
|
||
监听局域网 UDP beacon,返回 WebSocket 基础地址。
|
||
例: ws://192.168.110.251:8899/ws/device
|
||
"""
|
||
deadline = time.time() + timeout
|
||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||
try:
|
||
sock.bind(("", BEACON_PORT))
|
||
except OSError:
|
||
# Termux 可能无权限绑 8898,改绑任意端口并只 recv
|
||
sock.bind(("", 0))
|
||
sock.settimeout(1.0)
|
||
|
||
while time.time() < deadline:
|
||
try:
|
||
data, _addr = sock.recvfrom(4096)
|
||
payload = json.loads(data.decode("utf-8"))
|
||
if payload.get("magic") != BEACON_MAGIC:
|
||
continue
|
||
port = int(payload.get("port") or 8899)
|
||
ws_path = (payload.get("ws_path") or "/ws/device").rstrip("/")
|
||
ips = payload.get("ips") or []
|
||
host = _pick_best_ip(ips) if ips else "127.0.0.1"
|
||
return f"ws://{host}:{port}{ws_path}"
|
||
except socket.timeout:
|
||
continue
|
||
except Exception:
|
||
continue
|
||
return None
|