feat(clawbot): add native WeChat ClawBot protocol engine (clawbot.py) and WechatClawModal UI

Browse Source
This commit is contained in:
Yin Kou committed 2026-11-07 00:51:38 +08:00
1 parent 07d2050c5f
commit 8fa46a2b8d
14 files changed
+1551 -201

No files matched your search

+31
View File
@@ -23,6 +23,7 @@ from concurrent.futures import ThreadPoolExecutor
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path from pathlib import Path
from clawbot import ClawBotManager
PORT = int(os.environ.get("PORT", "3004")) PORT = int(os.environ.get("PORT", "3004"))
BASE_DIR = Path(__file__).resolve().parent BASE_DIR = Path(__file__).resolve().parent
@@ -298,7 +299,9 @@ def collect_telemetry() -> dict:
"clash": net["router_online"], "clash": net["router_online"],
"router": net["router_online"], "router": net["router_online"],
"uptime": net["azure_online"], "uptime": net["azure_online"],
"clawbot": clawbot_mgr.is_connected(),
}, },
"clawbot": clawbot_mgr.get_public_status(),
} }
with _cache_lock: with _cache_lock:
_cache["data"] = data _cache["data"] = data
@@ -306,6 +309,9 @@ def collect_telemetry() -> dict:
return data return data
clawbot_mgr = ClawBotManager(telemetry_fn=collect_telemetry)
class PortalHandler(BaseHTTPRequestHandler): class PortalHandler(BaseHTTPRequestHandler):
def log_message(self, fmt, *args): def log_message(self, fmt, *args):
pass pass
@@ -383,6 +389,11 @@ class PortalHandler(BaseHTTPRequestHandler):
self._send_json(collect_telemetry()) self._send_json(collect_telemetry())
return return
# 3b. WeChat ClawBot status endpoint (/api/clawbot/status)
if self.path.startswith("/api/clawbot/status"):
self._send_json(clawbot_mgr.get_public_status())
return
# 4. Serve static assets from Vite build output (dist/) if available # 4. Serve static assets from Vite build output (dist/) if available
clean_path = self.path.split("?", 1)[0].lstrip("/") clean_path = self.path.split("?", 1)[0].lstrip("/")
if clean_path and DIST_DIR.exists(): if clean_path and DIST_DIR.exists():
@@ -456,6 +467,26 @@ class PortalHandler(BaseHTTPRequestHandler):
self._send_json({"ok": True}, status=200, extra_headers=headers) self._send_json({"ok": True}, status=200, extra_headers=headers)
return return
# 2b. WeChat ClawBot Endpoints (/api/clawbot/*)
if self.path == "/api/clawbot/qrcode":
res = clawbot_mgr.start_qr_login()
self._send_json(res, status=200 if res.get("ok") else 500)
return
if self.path == "/api/clawbot/verify":
length = int(self.headers.get("Content-Length", "0"))
raw = self.rfile.read(length).decode("utf-8") if length > 0 else "{}"
try:
body = json.loads(raw)
except Exception:
body = {}
res = clawbot_mgr.submit_verify_code(str(body.get("code", "")))
self._send_json(res)
return
if self.path == "/api/clawbot/disconnect":
res = clawbot_mgr.disconnect()
self._send_json(res)
return
# 3. Operations Actions # 3. Operations Actions
if self.path == "/api/action/backup_nas": if self.path == "/api/action/backup_nas":
out = run_cmd("/Users/ixvii0iv/homelab/scripts/backup-to-nas.sh", timeout=15.0) out = run_cmd("/Users/ixvii0iv/homelab/scripts/backup-to-nas.sh", timeout=15.0)