Skip to content

Commit ed5fb14

Browse files
authored
Update gui.py
1 parent 8401712 commit ed5fb14

1 file changed

Lines changed: 178 additions & 33 deletions

File tree

gui.py

Lines changed: 178 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33
"""
4-
ECH Workers 客户端 - Mac 版本 (Python + PyQt5)
4+
ECH Workers 客户端 - 跨平台版本 (Python + PyQt5)
5+
支持 Windows 和 macOS
56
"""
67

78
import sys
@@ -34,7 +35,17 @@ class ConfigManager:
3435
"""配置管理器"""
3536

3637
def __init__(self):
37-
self.config_dir = Path.home() / "Library" / "Application Support" / "ECHWorkersClient"
38+
# 跨平台配置文件路径
39+
if sys.platform == 'win32':
40+
# Windows: %APPDATA%\ECHWorkersClient
41+
self.config_dir = Path(os.getenv('APPDATA', Path.home())) / "ECHWorkersClient"
42+
else:
43+
# macOS/Linux: ~/Library/Application Support/ECHWorkersClient 或 ~/.config/ECHWorkersClient
44+
if sys.platform == 'darwin':
45+
self.config_dir = Path.home() / "Library" / "Application Support" / "ECHWorkersClient"
46+
else:
47+
self.config_dir = Path.home() / ".config" / "ECHWorkersClient"
48+
3849
self.config_file = self.config_dir / "config.json"
3950
self.config_dir.mkdir(parents=True, exist_ok=True)
4051
self.servers = []
@@ -189,56 +200,75 @@ def stop(self):
189200
self.process.kill()
190201

191202
def _find_executable(self):
192-
"""查找可执行文件"""
203+
"""查找可执行文件(跨平台)"""
193204
# 脚本所在目录
194205
script_dir = Path(__file__).parent.absolute()
195206
# 当前工作目录
196207
current_dir = Path.cwd()
197208

209+
# Windows 和 Unix 的可执行文件扩展名
210+
exe_ext = '.exe' if sys.platform == 'win32' else ''
211+
198212
# 可能的可执行文件路径(按优先级)
199213
possible_paths = [
200-
script_dir / 'ech-workers',
201-
script_dir / 'ech-workers.exe',
202-
current_dir / 'ech-workers',
203-
current_dir / 'ech-workers.exe',
204-
# 尝试查找编译后的文件
205-
script_dir / 'ech-workers-gui.exe', # Windows 编译版本
206-
script_dir / 'build' / 'ech-workers', # 可能的构建目录
214+
script_dir / f'ech-workers{exe_ext}',
215+
current_dir / f'ech-workers{exe_ext}',
216+
# Windows 特定路径
217+
script_dir / 'ech-workers.exe' if sys.platform == 'win32' else None,
218+
current_dir / 'ech-workers.exe' if sys.platform == 'win32' else None,
219+
# Unix 路径(无扩展名)
220+
script_dir / 'ech-workers' if sys.platform != 'win32' else None,
221+
current_dir / 'ech-workers' if sys.platform != 'win32' else None,
207222
]
208223

224+
# 过滤掉 None 值
225+
possible_paths = [p for p in possible_paths if p is not None]
226+
209227
for path in possible_paths:
210228
if path.exists():
211-
# 检查是否是真正的可执行文件(不是文本文件)
212-
try:
213-
# 尝试读取文件头,检查是否是二进制文件
214-
with open(path, 'rb') as f:
215-
header = f.read(4)
216-
# 检查是否是 ELF、Mach-O 或 PE 可执行文件
217-
is_binary = header.startswith(b'\x7fELF') or \
218-
header.startswith(b'\xfe\xed\xfa') or \
219-
header.startswith(b'MZ') or \
220-
header.startswith(b'#!') # 脚本文件
221-
222-
if is_binary or os.access(path, os.X_OK):
223-
# 如果是脚本文件,尝试添加执行权限
224-
if not os.access(path, os.X_OK) and header.startswith(b'#!'):
225-
try:
226-
os.chmod(path, 0o755)
227-
except:
228-
pass
229+
# Windows: 检查文件是否存在即可(.exe 文件)
230+
# Unix: 检查文件权限
231+
if sys.platform == 'win32':
232+
# Windows 上,.exe 文件可以直接运行
233+
if path.suffix.lower() == '.exe':
229234
return str(path)
230-
except:
231-
# 如果读取失败,至少检查执行权限
235+
# 或者检查文件是否可执行
236+
try:
237+
with open(path, 'rb') as f:
238+
header = f.read(2)
239+
# PE 文件头
240+
if header == b'MZ':
241+
return str(path)
242+
except:
243+
pass
244+
else:
245+
# Unix/Linux/macOS: 检查执行权限
232246
if os.access(path, os.X_OK):
233247
return str(path)
248+
# 或者检查是否是二进制文件
249+
try:
250+
with open(path, 'rb') as f:
251+
header = f.read(4)
252+
# ELF 或 Mach-O
253+
if (header.startswith(b'\x7fELF') or
254+
header.startswith(b'\xfe\xed\xfa') or
255+
header.startswith(b'#!')):
256+
# 尝试添加执行权限
257+
try:
258+
os.chmod(path, 0o755)
259+
except:
260+
pass
261+
return str(path)
262+
except:
263+
pass
234264

235265
# 尝试从 PATH 中查找
236266
import shutil
237267
exe = shutil.which('ech-workers')
238268
if exe:
239269
return exe
240270

241-
# 如果都找不到,返回 None 并显示详细错误
271+
# 如果都找不到,返回 None
242272
return None
243273

244274

@@ -523,8 +553,119 @@ def on_process_finished(self):
523553

524554
def on_auto_start_changed(self):
525555
"""开机启动改变"""
526-
# 简化版本,不实现开机启动
527-
pass
556+
enabled = self.auto_start_check.isChecked()
557+
if self._set_auto_start(enabled):
558+
self.append_log(f"[系统] {'已设置' if enabled else '已取消'}开机启动\n")
559+
else:
560+
self.auto_start_check.setChecked(not enabled)
561+
QMessageBox.warning(self, "错误", "设置开机启动失败")
562+
563+
def _set_auto_start(self, enabled):
564+
"""设置开机启动(跨平台)"""
565+
try:
566+
if sys.platform == 'win32':
567+
# Windows: 使用注册表
568+
import winreg
569+
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
570+
app_name = "ECHWorkersClient"
571+
572+
if enabled:
573+
# 获取当前脚本路径
574+
script_path = Path(__file__).absolute()
575+
python_path = sys.executable
576+
# 创建启动命令
577+
cmd = f'"{python_path}" "{script_path}"'
578+
579+
try:
580+
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_SET_VALUE)
581+
winreg.SetValueEx(key, app_name, 0, winreg.REG_SZ, cmd)
582+
winreg.CloseKey(key)
583+
return True
584+
except Exception as e:
585+
print(f"设置开机启动失败: {e}")
586+
return False
587+
else:
588+
try:
589+
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_SET_VALUE)
590+
winreg.DeleteValue(key, app_name)
591+
winreg.CloseKey(key)
592+
return True
593+
except FileNotFoundError:
594+
# 如果值不存在,也算成功
595+
return True
596+
except Exception as e:
597+
print(f"删除开机启动失败: {e}")
598+
return False
599+
else:
600+
# macOS/Linux: 使用 LaunchAgents 或 systemd
601+
if sys.platform == 'darwin':
602+
# macOS
603+
plist_path = Path.home() / "Library" / "LaunchAgents" / "com.echworkers.client.plist"
604+
if enabled:
605+
script_path = Path(__file__).absolute()
606+
python_path = sys.executable
607+
plist_content = f"""<?xml version="1.0" encoding="UTF-8"?>
608+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
609+
<plist version="1.0">
610+
<dict>
611+
<key>Label</key>
612+
<string>com.echworkers.client</string>
613+
<key>ProgramArguments</key>
614+
<array>
615+
<string>{python_path}</string>
616+
<string>{script_path}</string>
617+
<string>-autostart</string>
618+
</array>
619+
<key>RunAtLoad</key>
620+
<true/>
621+
<key>KeepAlive</key>
622+
<false/>
623+
</dict>
624+
</plist>"""
625+
try:
626+
plist_path.parent.mkdir(parents=True, exist_ok=True)
627+
with open(plist_path, 'w') as f:
628+
f.write(plist_content)
629+
return True
630+
except Exception as e:
631+
print(f"创建启动项失败: {e}")
632+
return False
633+
else:
634+
try:
635+
if plist_path.exists():
636+
plist_path.unlink()
637+
return True
638+
except Exception as e:
639+
print(f"删除启动项失败: {e}")
640+
return False
641+
else:
642+
# Linux: 使用 systemd user service(简化实现)
643+
return False # Linux 暂不支持
644+
except Exception as e:
645+
print(f"设置开机启动失败: {e}")
646+
return False
647+
648+
def _is_auto_start_enabled(self):
649+
"""检查是否已启用开机启动"""
650+
try:
651+
if sys.platform == 'win32':
652+
import winreg
653+
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
654+
app_name = "ECHWorkersClient"
655+
try:
656+
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
657+
winreg.QueryValueEx(key, app_name)
658+
winreg.CloseKey(key)
659+
return True
660+
except FileNotFoundError:
661+
return False
662+
elif sys.platform == 'darwin':
663+
plist_path = Path.home() / "Library" / "LaunchAgents" / "com.echworkers.client.plist"
664+
return plist_path.exists()
665+
else:
666+
return False
667+
except:
668+
return False
528669

529670
def clear_log(self):
530671
"""清空日志"""
@@ -541,6 +682,10 @@ def append_log(self, text):
541682
cursor.movePosition(cursor.Start, cursor.KeepAnchor)
542683
cursor.removeSelectedText()
543684

685+
def update_auto_start_checkbox(self):
686+
"""更新开机启动复选框状态"""
687+
self.auto_start_check.setChecked(self._is_auto_start_enabled())
688+
544689
def auto_start(self):
545690
"""自动启动"""
546691
if not (self.process_thread and self.process_thread.is_running):

0 commit comments

Comments
 (0)