44c54d6f80
Co-authored-by: Cursor <cursoragent@cursor.com>
149 lines
5.0 KiB
Python
149 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""首次激活:必须填写中控地址 + 激活码,不允许离线运行。"""
|
||
from __future__ import annotations
|
||
|
||
import tkinter as tk
|
||
from tkinter import messagebox, ttk
|
||
from typing import Optional
|
||
|
||
import hub_client
|
||
from device_store import is_activated, load_device, machine_fingerprint
|
||
|
||
|
||
def _bring_front(win: tk.Misc) -> None:
|
||
try:
|
||
win.update_idletasks()
|
||
win.deiconify()
|
||
win.lift()
|
||
win.focus_force()
|
||
win.attributes("-topmost", True)
|
||
win.after(250, lambda: win.attributes("-topmost", False))
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def ensure_activated(parent: Optional[tk.Misc] = None) -> bool:
|
||
"""
|
||
- 已激活:探测中控,成功则放行;失败则提示重试/退出(不允许离线)。
|
||
- 未激活:必须激活成功才能进入。
|
||
"""
|
||
if is_activated():
|
||
if hub_client.ping():
|
||
return True
|
||
return _ask_retry_or_exit(parent)
|
||
|
||
return _show_activation_form(parent)
|
||
|
||
|
||
def _ask_retry_or_exit(parent: Optional[tk.Misc]) -> bool:
|
||
owns = parent is None
|
||
root = parent or tk.Tk()
|
||
if owns:
|
||
root.withdraw()
|
||
try:
|
||
while True:
|
||
_bring_front(root)
|
||
retry = messagebox.askretrycancel(
|
||
"无法连接中控",
|
||
"客户端不允许离线运行。\n请确认中控已启动且本机网络正常后重试。\n\n点「重试」再次连接,点「取消」退出。",
|
||
parent=root,
|
||
)
|
||
if not retry:
|
||
return False
|
||
if hub_client.ping():
|
||
return True
|
||
finally:
|
||
if owns:
|
||
try:
|
||
root.destroy()
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def _show_activation_form(parent: Optional[tk.Misc]) -> bool:
|
||
owns_root = parent is None
|
||
root = parent or tk.Tk()
|
||
|
||
try:
|
||
win = root if owns_root else tk.Toplevel(root)
|
||
win.title("首次激活 · 黄金辅助")
|
||
win.minsize(520, 400)
|
||
win.geometry("520x400")
|
||
win.resizable(True, True)
|
||
result = {"ok": False}
|
||
device = load_device()
|
||
|
||
btn_bar = ttk.Frame(win, padding=(16, 10, 16, 16))
|
||
btn_bar.pack(side=tk.BOTTOM, fill=tk.X)
|
||
|
||
body = ttk.Frame(win, padding=16)
|
||
body.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
|
||
|
||
ttk.Label(
|
||
body,
|
||
text="必须激活后才能使用。填写中控地址与激活码,成功后本机保存,以后自动连接。",
|
||
wraplength=470,
|
||
).pack(anchor="w")
|
||
|
||
ttk.Label(body, text="中控地址(例:http://192.168.1.10:5800)").pack(
|
||
anchor="w", pady=(14, 4)
|
||
)
|
||
var_server = tk.StringVar(value=device.get("server") or "http://127.0.0.1:5800")
|
||
ttk.Entry(body, textvariable=var_server).pack(fill=tk.X, ipady=3)
|
||
|
||
ttk.Label(body, text="激活码(网页下载中心生成)").pack(anchor="w", pady=(12, 4))
|
||
var_code = tk.StringVar()
|
||
ttk.Entry(body, textvariable=var_code).pack(fill=tk.X, ipady=3)
|
||
|
||
ttk.Label(body, text="本机名称(可改)").pack(anchor="w", pady=(12, 4))
|
||
var_name = tk.StringVar(value=device.get("machine_name") or "")
|
||
ttk.Entry(body, textvariable=var_name).pack(fill=tk.X, ipady=3)
|
||
|
||
status = ttk.Label(body, text="", foreground="#888")
|
||
status.pack(anchor="w", pady=(14, 0))
|
||
|
||
def do_exit():
|
||
result["ok"] = False
|
||
win.destroy()
|
||
|
||
def do_ok():
|
||
server = var_server.get().strip().rstrip("/")
|
||
code = var_code.get().strip()
|
||
if not server or not code:
|
||
status.configure(text="请填写中控地址与激活码", foreground="#f6465d")
|
||
return
|
||
status.configure(text="正在激活…", foreground="#888")
|
||
win.update_idletasks()
|
||
try:
|
||
hub_client.activate(
|
||
server, code, machine_fingerprint(), var_name.get().strip() or "PC"
|
||
)
|
||
result["ok"] = True
|
||
messagebox.showinfo(
|
||
"激活成功",
|
||
f"已绑定中控:{server}\n以后打开将自动连接。",
|
||
parent=win,
|
||
)
|
||
win.destroy()
|
||
except hub_client.HubError as exc:
|
||
status.configure(text=str(exc), foreground="#f6465d")
|
||
|
||
ttk.Button(btn_bar, text="退出", command=do_exit).pack(side=tk.LEFT, ipadx=8, ipady=4)
|
||
ttk.Button(btn_bar, text="确认激活", command=do_ok).pack(side=tk.RIGHT, ipadx=12, ipady=4)
|
||
win.bind("<Return>", lambda _e: do_ok())
|
||
win.protocol("WM_DELETE_WINDOW", do_exit)
|
||
_bring_front(win)
|
||
try:
|
||
win.grab_set()
|
||
except Exception:
|
||
pass
|
||
win.wait_window()
|
||
return result["ok"]
|
||
finally:
|
||
if owns_root:
|
||
try:
|
||
if root.winfo_exists():
|
||
root.destroy()
|
||
except Exception:
|
||
pass
|