feat: settings password change, migrate desktop client with hub activation/report

This commit is contained in:
dekun
2026-10-17 17:50:42 +08:00
parent fb35968a1f
commit 1d4d5b06df
14 changed files with 1933 additions and 26 deletions
+123
View File
@@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
"""与 gold_monitor 中控通信:激活、成交上报、K 线上报。"""
from __future__ import annotations
import json
import urllib.error
import urllib.request
from typing import Any, Optional
from device_store import load_device, save_device
class HubError(Exception):
pass
def _url(server: str, path: str) -> str:
base = (server or "").rstrip("/")
if not base:
raise HubError("未配置服务器地址")
if not path.startswith("/"):
path = "/" + path
return base + path
def _request(
method: str,
server: str,
path: str,
body: Optional[dict] = None,
token: str = "",
timeout: float = 15.0,
) -> dict[str, Any]:
data = None
headers = {"Accept": "application/json"}
if body is not None:
raw = json.dumps(body, ensure_ascii=False).encode("utf-8")
data = raw
headers["Content-Type"] = "application/json"
if token:
headers["X-Device-Token"] = token
req = urllib.request.Request(_url(server, path), data=data, headers=headers, method=method)
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
text = resp.read().decode("utf-8", errors="replace")
return json.loads(text) if text else {}
except urllib.error.HTTPError as exc:
try:
detail = exc.read().decode("utf-8", errors="replace")
payload = json.loads(detail) if detail else {}
raise HubError(payload.get("error") or detail or str(exc)) from exc
except HubError:
raise
except Exception:
raise HubError(f"HTTP {exc.code}") from exc
except urllib.error.URLError as exc:
raise HubError(f"无法连接服务器:{exc.reason}") from exc
def activate(server: str, code: str, fingerprint: str, machine_name: str) -> dict[str, Any]:
result = _request(
"POST",
server,
"/api/v1/activate",
{
"code": code.strip(),
"fingerprint": fingerprint,
"machine_name": machine_name,
},
)
if not result.get("ok"):
raise HubError(result.get("error") or "激活失败")
device = load_device()
device["server"] = server.rstrip("/")
device["token"] = result["token"]
device["account_id"] = result.get("account_id")
device["machine_id"] = result.get("machine_id")
device["fingerprint"] = fingerprint
device["machine_name"] = machine_name
save_device(device)
return result
def ping() -> bool:
d = load_device()
if not d.get("token") or not d.get("server"):
return False
try:
r = _request("GET", d["server"], "/api/v1/ping", token=d["token"], timeout=8)
return bool(r.get("ok"))
except HubError:
return False
def report_trade(payload: dict[str, Any]) -> Optional[int]:
d = load_device()
if not d.get("token") or not d.get("server"):
return None
try:
r = _request("POST", d["server"], "/api/v1/trades", body=payload, token=d["token"])
if r.get("ok"):
return int(r.get("id") or 0)
except HubError:
return None
return None
def report_bars(symbol: str, timeframe: str, bars: list[dict]) -> int:
d = load_device()
if not d.get("token") or not d.get("server") or not bars:
return 0
try:
r = _request(
"POST",
d["server"],
"/api/v1/bars",
body={"symbol": symbol, "timeframe": timeframe, "bars": bars},
token=d["token"],
timeout=30,
)
return int(r.get("count") or 0)
except HubError:
return 0