feat: 优化硬件ID生成方案,增加计算机名作为备选方案,确保ID生成的稳定性 v3.5.2
This commit is contained in:
@@ -13,7 +13,12 @@ from pathlib import Path
|
|||||||
from utils.config import Config
|
from utils.config import Config
|
||||||
from utils.cursor_registry import CursorRegistry
|
from utils.cursor_registry import CursorRegistry
|
||||||
from cursor_auth_manager import CursorAuthManager
|
from cursor_auth_manager import CursorAuthManager
|
||||||
from utils.cursor_resetter import CursorResetter # 添加导入
|
from utils.cursor_resetter import CursorResetter
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 添加缓存文件路径常量
|
||||||
|
CACHE_DIR = Path(os.path.expanduser("~")) / ".cursor_cache"
|
||||||
|
HARDWARE_ID_CACHE = CACHE_DIR / "hardware_id.json"
|
||||||
|
|
||||||
def is_admin() -> bool:
|
def is_admin() -> bool:
|
||||||
"""检查是否具有管理员权限
|
"""检查是否具有管理员权限
|
||||||
@@ -56,7 +61,11 @@ def run_as_admin():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_hardware_id() -> str:
|
def get_hardware_id() -> str:
|
||||||
"""获取硬件唯一标识"""
|
"""获取硬件唯一标识
|
||||||
|
方案1: CPU ID + 主板序列号 + BIOS序列号
|
||||||
|
方案2: 系统盘序列号 + Windows安装时间
|
||||||
|
方案3: 计算机名(最后的备选方案)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# 创建startupinfo对象来隐藏命令行窗口
|
# 创建startupinfo对象来隐藏命令行窗口
|
||||||
startupinfo = None
|
startupinfo = None
|
||||||
@@ -64,26 +73,70 @@ def get_hardware_id() -> str:
|
|||||||
startupinfo = subprocess.STARTUPINFO()
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||||
|
|
||||||
# 获取CPU信息
|
# 方案1: 尝试获取硬件信息
|
||||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
try:
|
||||||
cpu_id = cpu_info.split('\n')[1].strip()
|
# 获取CPU ID
|
||||||
|
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||||
# 获取主板序列号
|
cpu_id = cpu_info.split('\n')[1].strip()
|
||||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
|
||||||
board_id = board_info.split('\n')[1].strip()
|
# 获取主板序列号
|
||||||
|
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||||
# 获取BIOS序列号
|
board_id = board_info.split('\n')[1].strip()
|
||||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
|
||||||
bios_id = bios_info.split('\n')[1].strip()
|
# 获取BIOS序列号
|
||||||
|
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||||
# 组合信息并生成哈希
|
bios_id = bios_info.split('\n')[1].strip()
|
||||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
|
||||||
return hashlib.md5(combined.encode()).hexdigest()
|
# 如果所有信息都获取成功且有效
|
||||||
|
if all([cpu_id, board_id, bios_id]) and not all(x in ['', '0', 'None', 'To be filled by O.E.M.'] for x in [cpu_id, board_id, bios_id]):
|
||||||
|
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||||
|
hardware_id = hashlib.md5(combined.encode()).hexdigest()
|
||||||
|
logging.info("使用硬件信息生成ID成功")
|
||||||
|
return hardware_id
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f"方案1失败: {str(e)}")
|
||||||
|
|
||||||
|
# 方案2: 系统盘序列号 + Windows安装时间
|
||||||
|
try:
|
||||||
|
backup_info = []
|
||||||
|
|
||||||
|
# 获取系统盘序列号
|
||||||
|
volume_info = subprocess.check_output('wmic logicaldisk where "DeviceID=\'C:\'" get VolumeSerialNumber', startupinfo=startupinfo).decode()
|
||||||
|
volume_serial = volume_info.split('\n')[1].strip()
|
||||||
|
if volume_serial and volume_serial not in ['', '0']:
|
||||||
|
backup_info.append(("volume", volume_serial))
|
||||||
|
|
||||||
|
# 获取Windows安装时间
|
||||||
|
os_info = subprocess.check_output('wmic os get InstallDate', startupinfo=startupinfo).decode()
|
||||||
|
install_date = os_info.split('\n')[1].strip()
|
||||||
|
if install_date:
|
||||||
|
backup_info.append(("install", install_date))
|
||||||
|
|
||||||
|
if backup_info:
|
||||||
|
combined = "|".join(f"{k}:{v}" for k, v in sorted(backup_info))
|
||||||
|
hardware_id = hashlib.md5(combined.encode()).hexdigest()
|
||||||
|
logging.info("使用系统信息生成ID成功")
|
||||||
|
return hardware_id
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f"方案2失败: {str(e)}")
|
||||||
|
|
||||||
|
# 方案3: 使用计算机名(最后的备选方案)
|
||||||
|
import platform
|
||||||
|
computer_name = platform.node()
|
||||||
|
if computer_name:
|
||||||
|
hardware_id = hashlib.md5(computer_name.encode()).hexdigest()
|
||||||
|
logging.info("使用计算机名生成ID成功")
|
||||||
|
return hardware_id
|
||||||
|
|
||||||
|
raise ValueError("无法获取任何可用信息来生成硬件ID")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"获取硬件ID失败: {str(e)}")
|
error_msg = f"生成硬件ID失败: {str(e)}"
|
||||||
# 如果获取失败,使用UUID作为备选方案
|
logging.error(error_msg)
|
||||||
return str(uuid.uuid4())
|
raise RuntimeError(error_msg)
|
||||||
|
|
||||||
class AccountSwitcher:
|
class AccountSwitcher:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -101,9 +154,9 @@ class AccountSwitcher:
|
|||||||
self.package_json = self.app_path / "package.json"
|
self.package_json = self.app_path / "package.json"
|
||||||
self.auth_manager = CursorAuthManager()
|
self.auth_manager = CursorAuthManager()
|
||||||
self.config = Config()
|
self.config = Config()
|
||||||
self.hardware_id = self.get_hardware_id() # 先获取硬件ID
|
self.hardware_id = get_hardware_id() # 使用新的硬件ID获取函数
|
||||||
self.registry = CursorRegistry() # 添加注册表操作工具类
|
self.registry = CursorRegistry()
|
||||||
self.resetter = CursorResetter() # 添加重置工具类
|
self.resetter = CursorResetter()
|
||||||
self.max_retries = 5
|
self.max_retries = 5
|
||||||
self.wait_time = 1
|
self.wait_time = 1
|
||||||
|
|
||||||
@@ -111,33 +164,7 @@ class AccountSwitcher:
|
|||||||
|
|
||||||
def get_hardware_id(self) -> str:
|
def get_hardware_id(self) -> str:
|
||||||
"""获取硬件唯一标识"""
|
"""获取硬件唯一标识"""
|
||||||
try:
|
return get_hardware_id() # 使用全局函数
|
||||||
# 创建startupinfo对象来隐藏命令行窗口
|
|
||||||
startupinfo = None
|
|
||||||
if sys.platform == "win32":
|
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
|
||||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
||||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
|
||||||
|
|
||||||
# 获取CPU信息
|
|
||||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
|
||||||
cpu_id = cpu_info.split('\n')[1].strip()
|
|
||||||
|
|
||||||
# 获取主板序列号
|
|
||||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
|
||||||
board_id = board_info.split('\n')[1].strip()
|
|
||||||
|
|
||||||
# 获取BIOS序列号
|
|
||||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
|
||||||
bios_id = bios_info.split('\n')[1].strip()
|
|
||||||
|
|
||||||
# 组合信息并生成哈希
|
|
||||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
|
||||||
return hashlib.md5(combined.encode()).hexdigest()
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"获取硬件ID失败: {str(e)}")
|
|
||||||
# 如果获取失败,使用UUID作为备选方案
|
|
||||||
return str(uuid.uuid4())
|
|
||||||
|
|
||||||
def get_cursor_version(self) -> str:
|
def get_cursor_version(self) -> str:
|
||||||
"""获取Cursor版本号"""
|
"""获取Cursor版本号"""
|
||||||
@@ -387,24 +414,40 @@ class AccountSwitcher:
|
|||||||
shell=True
|
shell=True
|
||||||
)
|
)
|
||||||
|
|
||||||
# 等待进程关闭
|
# 等待进程关闭,增加重试次数和等待时间
|
||||||
retry_count = 0
|
retry_count = 0
|
||||||
while retry_count < self.max_retries:
|
max_retries = 10 # 增加最大重试次数
|
||||||
if not self.get_process_details("Cursor.exe"):
|
wait_time = 2 # 增加每次等待时间
|
||||||
|
|
||||||
|
while retry_count < max_retries:
|
||||||
|
remaining_processes = self.get_process_details("Cursor.exe")
|
||||||
|
if not remaining_processes:
|
||||||
logging.info("所有Cursor进程已关闭")
|
logging.info("所有Cursor进程已关闭")
|
||||||
|
# 额外等待一段时间确保系统资源完全释放
|
||||||
|
time.sleep(2)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
retry_count += 1
|
retry_count += 1
|
||||||
if retry_count >= self.max_retries:
|
if retry_count >= max_retries:
|
||||||
processes = self.get_process_details("Cursor.exe")
|
processes = self.get_process_details("Cursor.exe")
|
||||||
if processes:
|
if processes:
|
||||||
logging.error(f"无法关闭以下进程:")
|
logging.error(f"无法关闭以下进程:")
|
||||||
for p in processes:
|
for p in processes:
|
||||||
logging.error(f"PID={p['pid']}, 路径={p['name']}")
|
logging.error(f"PID={p['pid']}, 路径={p['name']}")
|
||||||
|
# 最后一次尝试强制结束
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
"taskkill /f /im Cursor.exe /t >nul 2>&1",
|
||||||
|
startupinfo=startupinfo,
|
||||||
|
shell=True
|
||||||
|
)
|
||||||
|
time.sleep(2)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logging.warning(f"等待进程关闭, 尝试 {retry_count}/{self.max_retries}...")
|
logging.warning(f"等待进程关闭, 尝试 {retry_count}/{max_retries}...")
|
||||||
time.sleep(self.wait_time)
|
time.sleep(wait_time)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -456,61 +499,74 @@ class AccountSwitcher:
|
|||||||
logging.error("无法关闭Cursor进程")
|
logging.error("无法关闭Cursor进程")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 等待进程完全关闭
|
# 等待系统资源释放
|
||||||
time.sleep(2)
|
time.sleep(3)
|
||||||
|
|
||||||
# 启动Cursor
|
# 启动Cursor
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||||
if cursor_exe.exists():
|
if cursor_exe.exists():
|
||||||
try:
|
max_retries = 3
|
||||||
# 使用subprocess启动
|
for attempt in range(max_retries):
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
try:
|
||||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
# 使用subprocess启动
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
subprocess.Popen(
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
str(cursor_exe),
|
|
||||||
startupinfo=startupinfo,
|
subprocess.Popen(
|
||||||
creationflags=subprocess.CREATE_NEW_CONSOLE
|
str(cursor_exe),
|
||||||
)
|
startupinfo=startupinfo,
|
||||||
|
creationflags=subprocess.CREATE_NEW_CONSOLE
|
||||||
# 等待进程启动
|
)
|
||||||
time.sleep(3)
|
|
||||||
|
# 等待进程启动
|
||||||
# 验证进程是否启动
|
time.sleep(5) # 增加等待时间
|
||||||
processes = self.get_process_details("Cursor.exe")
|
|
||||||
if processes:
|
# 验证进程是否启动
|
||||||
logging.info("Cursor启动成功")
|
processes = self.get_process_details("Cursor.exe")
|
||||||
return True
|
if processes:
|
||||||
else:
|
logging.info("Cursor启动成功")
|
||||||
logging.error("Cursor进程未找到")
|
return True
|
||||||
# 尝试使用 os.startfile 作为备选方案
|
else:
|
||||||
|
if attempt < max_retries - 1:
|
||||||
|
logging.warning(f"启动尝试 {attempt + 1} 失败,准备重试...")
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
|
||||||
|
logging.error("Cursor进程未找到")
|
||||||
|
# 尝试使用 os.startfile 作为备选方案
|
||||||
|
try:
|
||||||
|
os.startfile(str(cursor_exe))
|
||||||
|
time.sleep(5)
|
||||||
|
logging.info("使用备选方案启动Cursor")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"备选启动方案失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if attempt < max_retries - 1:
|
||||||
|
logging.warning(f"启动尝试 {attempt + 1} 失败: {str(e)},准备重试...")
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
|
||||||
|
logging.error(f"启动Cursor失败: {str(e)}")
|
||||||
|
# 尝试使用 os.startfile 作为最后的备选方案
|
||||||
try:
|
try:
|
||||||
os.startfile(str(cursor_exe))
|
os.startfile(str(cursor_exe))
|
||||||
time.sleep(3)
|
time.sleep(5)
|
||||||
logging.info("使用备选方案启动Cursor")
|
logging.info("使用备选方案启动Cursor")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"备选启动方案失败: {str(e)}")
|
logging.error(f"备选启动方案失败: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"启动Cursor失败: {str(e)}")
|
|
||||||
# 尝试使用 os.startfile 作为备选方案
|
|
||||||
try:
|
|
||||||
os.startfile(str(cursor_exe))
|
|
||||||
time.sleep(3)
|
|
||||||
logging.info("使用备选方案启动Cursor")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"备选启动方案失败: {str(e)}")
|
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
logging.error(f"未找到Cursor程序: {cursor_exe}")
|
logging.error(f"未找到Cursor程序: {cursor_exe}")
|
||||||
return False
|
return False
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
try:
|
try:
|
||||||
subprocess.run("open -a Cursor", shell=True, check=True)
|
subprocess.run("open -a Cursor", shell=True, check=True)
|
||||||
|
time.sleep(5)
|
||||||
logging.info("Cursor启动成功")
|
logging.info("Cursor启动成功")
|
||||||
return True
|
return True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
@@ -519,6 +575,7 @@ class AccountSwitcher:
|
|||||||
elif sys.platform == "linux":
|
elif sys.platform == "linux":
|
||||||
try:
|
try:
|
||||||
subprocess.run("cursor &", shell=True, check=True)
|
subprocess.run("cursor &", shell=True, check=True)
|
||||||
|
time.sleep(5)
|
||||||
logging.info("Cursor启动成功")
|
logging.info("Cursor启动成功")
|
||||||
return True
|
return True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
@@ -529,16 +586,6 @@ class AccountSwitcher:
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"重启Cursor失败: {str(e)}")
|
logging.error(f"重启Cursor失败: {str(e)}")
|
||||||
# 尝试使用 os.startfile 作为最后的备选方案
|
|
||||||
try:
|
|
||||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
|
||||||
if cursor_exe.exists():
|
|
||||||
os.startfile(str(cursor_exe))
|
|
||||||
time.sleep(3)
|
|
||||||
logging.info("使用最终备选方案启动Cursor")
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def activate_and_switch(self, activation_code: str) -> Tuple[bool, str]:
|
def activate_and_switch(self, activation_code: str) -> Tuple[bool, str]:
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
from PIL import Image
|
|
||||||
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
||||||
QLabel, QLineEdit, QPushButton, QFrame, QTextEdit,
|
|
||||||
QMessageBox, QApplication, QSystemTrayIcon, QMenu,
|
|
||||||
QDialog, QProgressBar, QStyle)
|
|
||||||
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
|
|
||||||
from PyQt5.QtGui import QIcon, QPixmap
|
|
||||||
import time
|
|
||||||
import requests
|
|
||||||
from urllib.parse import quote
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
sys.path.append(str(Path(__file__).parent.parent))
|
|
||||||
|
|
||||||
from utils.config import Config
|
|
||||||
from utils.version_manager import VersionManager
|
|
||||||
from account_switcher import AccountSwitcher
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.config = Config()
|
|
||||||
self.switcher = AccountSwitcher()
|
|
||||||
self.version_manager = VersionManager()
|
|
||||||
|
|
||||||
# 添加激活状态缓存
|
|
||||||
self._activation_status = None # 缓存的激活状态
|
|
||||||
self._status_timer = None # 状态更新定时器
|
|
||||||
|
|
||||||
# 添加心跳定时器
|
|
||||||
self._heartbeat_timer = QTimer()
|
|
||||||
self._heartbeat_timer.timeout.connect(self.send_heartbeat)
|
|
||||||
self._heartbeat_timer.start(5 * 60 * 1000) # 每5分钟发送一次心跳
|
|
||||||
|
|
||||||
# 添加请求锁,防止重复提交
|
|
||||||
self._is_requesting = False
|
|
||||||
self._last_request_time = 0
|
|
||||||
self._request_cooldown = 2 # 请求冷却时间(秒)
|
|
||||||
|
|
||||||
version = get_version()
|
|
||||||
cursor_version = self.switcher.get_cursor_version()
|
|
||||||
self.setWindowTitle(f"听泉Cursor助手 v{version} (本机Cursor版本: {cursor_version})")
|
|
||||||
self.setMinimumSize(600, 680) # 增加最小宽度到600
|
|
||||||
|
|
||||||
# 设置窗口图标
|
|
||||||
icon_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "icon", "two.ico")
|
|
||||||
if os.path.exists(icon_path):
|
|
||||||
self.window_icon = QIcon(icon_path)
|
|
||||||
if not self.window_icon.isNull():
|
|
||||||
self.setWindowIcon(self.window_icon)
|
|
||||||
logging.info(f"成功设置窗口图标: {icon_path}")
|
|
||||||
else:
|
|
||||||
logging.warning("图标文件加载失败")
|
|
||||||
|
|
||||||
# 创建系统托盘图标
|
|
||||||
self.create_tray_icon()
|
|
||||||
|
|
||||||
# 创建主窗口部件
|
|
||||||
central_widget = QWidget()
|
|
||||||
self.setCentralWidget(central_widget)
|
|
||||||
|
|
||||||
# 设置主窗口样式
|
|
||||||
central_widget.setStyleSheet("""
|
|
||||||
QWidget {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
|
||||||
stop:0 #f8f9fa,
|
|
||||||
stop:0.5 #ffffff,
|
|
||||||
stop:1 #f8f9fa);
|
|
||||||
}
|
|
||||||
QFrame {
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
|
|
||||||
# 创建主布局
|
|
||||||
main_layout = QVBoxLayout(central_widget)
|
|
||||||
main_layout.setSpacing(12) # 减小区域间距
|
|
||||||
main_layout.setContentsMargins(20, 15, 20, 15) # 调整外边距
|
|
||||||
|
|
||||||
# 启动时检查一次状态
|
|
||||||
QTimer.singleShot(0, self.check_status)
|
|
||||||
|
|
||||||
# 启动时自动检查更新
|
|
||||||
QTimer.singleShot(1000, self.check_for_updates)
|
|
||||||
|
|
||||||
def send_heartbeat(self):
|
|
||||||
"""发送心跳请求"""
|
|
||||||
if not self._check_request_throttle():
|
|
||||||
return
|
|
||||||
|
|
||||||
def heartbeat_func():
|
|
||||||
return self.switcher.send_heartbeat()
|
|
||||||
|
|
||||||
# 创建工作线程
|
|
||||||
self.heartbeat_worker = ApiWorker(heartbeat_func)
|
|
||||||
self.heartbeat_worker.finished.connect(self.on_heartbeat_complete)
|
|
||||||
self.heartbeat_worker.start()
|
|
||||||
|
|
||||||
def on_heartbeat_complete(self, result):
|
|
||||||
"""心跳完成回调"""
|
|
||||||
success, message = result
|
|
||||||
self._request_complete()
|
|
||||||
|
|
||||||
if success:
|
|
||||||
logging.info(f"心跳发送成功: {message}")
|
|
||||||
# 更新状态显示
|
|
||||||
self.check_status()
|
|
||||||
else:
|
|
||||||
logging.error(f"心跳发送失败: {message}")
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
"""窗口关闭事件"""
|
|
||||||
try:
|
|
||||||
if hasattr(self, 'tray_icon') and self.tray_icon.isVisible():
|
|
||||||
event.ignore()
|
|
||||||
self.hide()
|
|
||||||
# 确保托盘图标显示
|
|
||||||
self.tray_icon.show()
|
|
||||||
self.tray_icon.showMessage(
|
|
||||||
"听泉Cursor助手",
|
|
||||||
"程序已最小化到系统托盘",
|
|
||||||
QSystemTrayIcon.Information,
|
|
||||||
2000
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# 如果托盘图标不可用,则正常退出
|
|
||||||
if self._status_timer:
|
|
||||||
self._status_timer.stop()
|
|
||||||
if hasattr(self, '_heartbeat_timer'):
|
|
||||||
self._heartbeat_timer.stop()
|
|
||||||
event.accept()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"处理关闭事件时发生错误: {str(e)}")
|
|
||||||
# 发生错误时,接受关闭事件
|
|
||||||
if self._status_timer:
|
|
||||||
self._status_timer.stop()
|
|
||||||
if hasattr(self, '_heartbeat_timer'):
|
|
||||||
self._heartbeat_timer.stop()
|
|
||||||
event.accept()
|
|
||||||
54
test_computer_name.py
Normal file
54
test_computer_name.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import platform
|
||||||
|
import hashlib
|
||||||
|
import time
|
||||||
|
|
||||||
|
def get_computer_name_id():
|
||||||
|
"""使用计算机名生成ID(方案三)"""
|
||||||
|
try:
|
||||||
|
computer_name = platform.node()
|
||||||
|
if computer_name:
|
||||||
|
print(f"\n计算机名: {computer_name}")
|
||||||
|
hardware_id = hashlib.md5(computer_name.encode()).hexdigest()
|
||||||
|
return hardware_id
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"获取计算机名失败: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def test_stability():
|
||||||
|
"""测试ID的稳定性"""
|
||||||
|
print("开始测试计算机名生成ID的稳定性...")
|
||||||
|
print("将进行10次测试,每次间隔1秒")
|
||||||
|
|
||||||
|
# 存储每次生成的ID
|
||||||
|
computer_ids = []
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
print(f"\n第 {i+1} 次测试:")
|
||||||
|
|
||||||
|
# 测试计算机名方案
|
||||||
|
comp_id = get_computer_name_id()
|
||||||
|
if comp_id:
|
||||||
|
print(f"使用计算机名生成的ID: {comp_id}")
|
||||||
|
computer_ids.append(comp_id)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# 分析结果
|
||||||
|
print("\n测试结果分析:")
|
||||||
|
|
||||||
|
if computer_ids:
|
||||||
|
unique_ids = set(computer_ids)
|
||||||
|
print(f"\n计算机名方案:")
|
||||||
|
print(f"生成次数: {len(computer_ids)}")
|
||||||
|
print(f"唯一ID数: {len(unique_ids)}")
|
||||||
|
print("是否稳定: " + ("是" if len(unique_ids) == 1 else "否"))
|
||||||
|
if len(unique_ids) > 1:
|
||||||
|
print("出现的不同ID:")
|
||||||
|
for idx, id in enumerate(unique_ids):
|
||||||
|
print(f"{idx+1}. {id}")
|
||||||
|
else:
|
||||||
|
print("\n计算机名方案: 获取失败")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_stability()
|
||||||
131
test_hardware_id.py
Normal file
131
test_hardware_id.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import subprocess
|
||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
def get_hardware_info():
|
||||||
|
"""获取硬件信息(方案一)"""
|
||||||
|
startupinfo = None
|
||||||
|
if sys.platform == "win32":
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取CPU ID
|
||||||
|
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||||
|
cpu_id = cpu_info.split('\n')[1].strip()
|
||||||
|
|
||||||
|
# 获取主板序列号
|
||||||
|
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||||
|
board_id = board_info.split('\n')[1].strip()
|
||||||
|
|
||||||
|
# 获取BIOS序列号
|
||||||
|
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||||
|
bios_id = bios_info.split('\n')[1].strip()
|
||||||
|
|
||||||
|
if all([cpu_id, board_id, bios_id]):
|
||||||
|
print(f"\n方案一硬件信息:")
|
||||||
|
print(f"CPU ID: {cpu_id}")
|
||||||
|
print(f"主板序列号: {board_id}")
|
||||||
|
print(f"BIOS序列号: {bios_id}")
|
||||||
|
|
||||||
|
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||||
|
return hashlib.md5(combined.encode()).hexdigest()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"方案一获取失败: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_system_info():
|
||||||
|
"""获取系统信息(方案二)"""
|
||||||
|
startupinfo = None
|
||||||
|
if sys.platform == "win32":
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||||
|
|
||||||
|
backup_info = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取系统盘序列号
|
||||||
|
volume_info = subprocess.check_output('wmic logicaldisk where "DeviceID=\'C:\'" get VolumeSerialNumber', startupinfo=startupinfo).decode()
|
||||||
|
volume_serial = volume_info.split('\n')[1].strip()
|
||||||
|
if volume_serial:
|
||||||
|
backup_info.append(("volume", volume_serial))
|
||||||
|
print(f"\n系统盘序列号: {volume_serial}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"获取系统盘序列号失败: {str(e)}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取Windows安装时间
|
||||||
|
os_info = subprocess.check_output('wmic os get InstallDate', startupinfo=startupinfo).decode()
|
||||||
|
install_date = os_info.split('\n')[1].strip()
|
||||||
|
if install_date:
|
||||||
|
backup_info.append(("install", install_date))
|
||||||
|
print(f"Windows安装时间: {install_date}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"获取系统安装时间失败: {str(e)}")
|
||||||
|
|
||||||
|
if backup_info:
|
||||||
|
combined = "|".join(f"{k}:{v}" for k, v in sorted(backup_info))
|
||||||
|
return hashlib.md5(combined.encode()).hexdigest()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def test_stability():
|
||||||
|
"""测试ID的稳定性"""
|
||||||
|
print("开始测试硬件ID稳定性...")
|
||||||
|
print("将进行10次测试,每次间隔1秒")
|
||||||
|
|
||||||
|
# 存储每次生成的ID
|
||||||
|
hardware_ids = []
|
||||||
|
system_ids = []
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
print(f"\n第 {i+1} 次测试:")
|
||||||
|
|
||||||
|
# 测试方案一
|
||||||
|
hw_id = get_hardware_info()
|
||||||
|
if hw_id:
|
||||||
|
print(f"方案一(硬件信息)生成的ID: {hw_id}")
|
||||||
|
hardware_ids.append(hw_id)
|
||||||
|
|
||||||
|
# 测试方案二
|
||||||
|
sys_id = get_system_info()
|
||||||
|
if sys_id:
|
||||||
|
print(f"方案二(系统信息)生成的ID: {sys_id}")
|
||||||
|
system_ids.append(sys_id)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# 分析结果
|
||||||
|
print("\n测试结果分析:")
|
||||||
|
|
||||||
|
if hardware_ids:
|
||||||
|
unique_hw_ids = set(hardware_ids)
|
||||||
|
print(f"\n方案一(硬件信息):")
|
||||||
|
print(f"生成次数: {len(hardware_ids)}")
|
||||||
|
print(f"唯一ID数: {len(unique_hw_ids)}")
|
||||||
|
print("是否稳定: " + ("是" if len(unique_hw_ids) == 1 else "否"))
|
||||||
|
if len(unique_hw_ids) > 1:
|
||||||
|
print("出现的不同ID:")
|
||||||
|
for idx, id in enumerate(unique_hw_ids):
|
||||||
|
print(f"{idx+1}. {id}")
|
||||||
|
else:
|
||||||
|
print("\n方案一(硬件信息): 获取失败")
|
||||||
|
|
||||||
|
if system_ids:
|
||||||
|
unique_sys_ids = set(system_ids)
|
||||||
|
print(f"\n方案二(系统信息):")
|
||||||
|
print(f"生成次数: {len(system_ids)}")
|
||||||
|
print(f"唯一ID数: {len(unique_sys_ids)}")
|
||||||
|
print("是否稳定: " + ("是" if len(unique_sys_ids) == 1 else "否"))
|
||||||
|
if len(unique_sys_ids) > 1:
|
||||||
|
print("出现的不同ID:")
|
||||||
|
for idx, id in enumerate(unique_sys_ids):
|
||||||
|
print(f"{idx+1}. {id}")
|
||||||
|
else:
|
||||||
|
print("\n方案二(系统信息): 获取失败")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_stability()
|
||||||
@@ -1 +1 @@
|
|||||||
3.5.0
|
3.5.2
|
||||||
Reference in New Issue
Block a user