# -*- coding: utf-8 -*- """让中转服务在局域网里也能访问,并公布当前隧道地址。 解决的实际问题: 匿名隧道每次重启都换地址。用户怎么知道新地址是什么? 现在只能 SSH 上去 cat public_url.txt —— 太麻烦。 做法: 1. 中转改绑 0.0.0.0:8080(局域网可达) 2. 加 GET /url —— 纯文本返回当前公网地址,不需要登录 3. 管理页顶部大字显示当前地址 于是用户只要记住一个**局域网**地址: http://192.168.2.156:8080/url 打开就能看到当前隧道地址,永远不用问人。 安全说明: /url 只暴露"隧道地址"这一个信息,不含配对码、设备、流量。 地址本来就是要给手表填的,不算秘密。 设备列表、配对码这些仍然要登录(密码 <改从环境变量读>)。 """ from __future__ import annotations import sys from pathlib import Path RELAY = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\relay\relay.py") # ---------------- 1. public_url() 读取地址 ---------------- ANCHOR = "def log(message: str) -> None:" NEW = '''def public_url() -> str: """当前隧道的公网地址。 隧道换地址时会写进 public_url.txt(tunnel-run.sh 负责维护)。 这里几个可能的位置都找一下,找到第一个像地址的就返回。 """ candidates = [ DATA_DIR.parent / "public_url.txt", DATA_DIR / "public_url.txt", Path("/root/lanremote-relay/public_url.txt"), ] for path in candidates: try: if not path.is_file(): continue text = path.read_text(encoding="utf-8").strip() if text.startswith("http"): return text except OSError: continue return "" ''' + ANCHOR # ---------------- 2. GET /url ---------------- GET_OLD = ''' if path in ("/v1/health", "/health"):''' GET_NEW = ''' # 当前公网地址。故意不需要登录 —— # 地址本来就要填到手表里,不是秘密;而且隧道换地址时 # 用户就是靠这个页面知道新地址的。 if path in ("/url", "/v1/url"): url = public_url() body = (url or "(还没有地址,隧道可能没起来)") + "\\n" self._send(200, body.encode("utf-8"), "text/plain; charset=utf-8") return if path in ("/v1/health", "/health"):''' # ---------------- 3. 管理页显示地址 ---------------- ADMIN_OLD = '''
版本 {snap['version']} · 已运行 {_uptime(snap['uptimeSeconds'])} · 本进程内存 {snap['memoryKB'] // 1024} MB
''' ADMIN_NEW = '''
版本 {snap['version']} · 已运行 {_uptime(snap['uptimeSeconds'])} · 本进程内存 {snap['memoryKB'] // 1024} MB
当前公网地址(手表「中转设置」里填这个)
{_esc(public_url() or "(还没有地址,隧道可能没起来)")}
''' def main() -> int: text = RELAY.read_text(encoding="utf-8") ok = True if "def public_url(" in text: print(" 已经加过 /url") return 0 for old, new, tag in ((ANCHOR, NEW, "public_url() 读取地址"), (GET_OLD, GET_NEW, "GET /url 接口"), (ADMIN_OLD, ADMIN_NEW, "管理页显示地址")): if old not in text: print(f" [失败] {tag} —— 锚点没找到") ok = False continue text = text.replace(old, new, 1) print(f" {tag}") RELAY.write_text(text, encoding="utf-8", newline="\n") import ast try: ast.parse(text) print(" 语法 OK") except SyntaxError as exc: print(f" 语法错误: {exc}") ok = False # 模块级函数齐不齐 tree = ast.parse(text) defined = {n.name for n in tree.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))} if "public_url" not in defined: print(" [失败] public_url 没定义成功") ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())