#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
HY 在线 ADB —— WiFi 本地桥接
============================
浏览器无法直接建立裸 TCP 连接，本脚本在你电脑本地把网页的 WebSocket
转发到安卓设备的 ADB 网络端口（默认 5555），从而让网页端的在线 ADB
工具可以连接 WiFi 设备。

USB 连接走浏览器 WebUSB，不需要本脚本；仅 WiFi 连接需要运行它。

依赖：
    pip install websockets

运行：
    python adb-wifi-bridge.py
    （默认监听 127.0.0.1:8765）

使用：
    1. 安卓设备开启「无线调试 / ADB over network」，记下设备 IP。
       如设备此前用 USB 连接，可先执行  adb tcpip 5555  打开网络调试。
    2. 运行本脚本。
    3. 打开网页 https://www.e7e.cn/index/adb ，选择「WiFi」连接，
       桥接地址填 ws://127.0.0.1:8765 ，设备 IP 填你的设备地址，端口 5555。
"""

import asyncio
import json
import sys

try:
    import websockets
except ImportError:
    print("缺少依赖，请先运行:  pip install websockets")
    sys.exit(1)

WS_HOST = "127.0.0.1"
WS_PORT = 8765
DEFAULT_DEVICE_PORT = 5555


async def handle(ws, *args):
    """每个网页连接：先收一条 JSON {host, port}，再双向转发字节。"""
    peer = None
    try:
        first = await ws.recv()
        cfg = json.loads(first)
        host = cfg["host"]
        port = int(cfg.get("port", DEFAULT_DEVICE_PORT))
        peer = f"{host}:{port}"
    except Exception as e:
        try:
            await ws.send(json.dumps({"error": "握手失败: %s" % e}))
        except Exception:
            pass
        return

    print("[+] 网页请求连接设备 %s" % peer)
    try:
        reader, writer = await asyncio.open_connection(host, port)
    except Exception as e:
        msg = "连接 %s 失败: %s" % (peer, e)
        print("[!] " + msg)
        try:
            await ws.send(json.dumps({"error": msg}))
        except Exception:
            pass
        return

    # 告知网页 TCP 已就绪，之后全部为二进制 ADB 数据
    await ws.send(json.dumps({"ok": True}))

    async def ws_to_tcp():
        try:
            async for msg in ws:
                if isinstance(msg, (bytes, bytearray)):
                    writer.write(msg)
                    await writer.drain()
        except Exception:
            pass
        finally:
            try:
                writer.close()
            except Exception:
                pass

    async def tcp_to_ws():
        try:
            while True:
                data = await reader.read(65536)
                if not data:
                    break
                await ws.send(data)
        except Exception:
            pass
        finally:
            try:
                await ws.close()
            except Exception:
                pass

    await asyncio.gather(ws_to_tcp(), tcp_to_ws())
    print("[-] 设备 %s 连接关闭" % peer)


async def main():
    print("=" * 52)
    print(" HY 在线 ADB · WiFi 本地桥接")
    print(" 监听: ws://%s:%d" % (WS_HOST, WS_PORT))
    print(" 网页选择 WiFi 连接，桥接地址填 ws://%s:%d" % (WS_HOST, WS_PORT))
    print(" 按 Ctrl+C 退出")
    print("=" * 52)
    async with websockets.serve(handle, WS_HOST, WS_PORT, max_size=None):
        await asyncio.Future()


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n已退出。")
