# -*- 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