| | |
| | | import os |
| | | import subprocess |
| | | import time |
| | | import logging |
| | | import sys |
| | | import getpass |
| | | |
| | | APP_NAME = "sening_vdp" |
| | | LOG_FILE = "sening_vdp.log" |
| | | |
| | | BASE_DIR = os.path.abspath(os.path.dirname(sys.executable)) |
| | | |
| | | logging.basicConfig( |
| | | filename=os.path.join(BASE_DIR, LOG_FILE), |
| | | level=logging.INFO, |
| | | format='%(asctime)s - %(levelname)s - %(message)s' |
| | | ) |
| | | |
| | | def start_process(name, exe_path, args, log_file): |
| | | try: |
| | | full_path = os.path.abspath(exe_path) |
| | | logging.info(f"Starting {name}: {full_path} {' '.join(args)}") |
| | | |
| | | # 打开日志文件,追加写入 |
| | | log_fh = open(log_file, "a", encoding="utf-8") |
| | | |
| | | # CREATE_NO_WINDOW 隐藏窗口 |
| | | CREATE_NO_WINDOW = 0x08000000 |
| | | |
| | | process = subprocess.Popen( |
| | | [full_path] + args, |
| | | cwd=os.path.dirname(full_path), |
| | | stdout=log_fh, |
| | | stderr=subprocess.STDOUT, |
| | | creationflags=CREATE_NO_WINDOW, |
| | | universal_newlines=True |
| | | ) |
| | | return process |
| | | except Exception as e: |
| | | logging.error(f"Failed to start {name}: {e}") |
| | | return None |
| | | |
| | | |
| | | |
| | | def start_process_with_retry(name, exe_path, args, log_file, retry_interval=120): |
| | | full_path = os.path.abspath(exe_path) |
| | | CREATE_NO_WINDOW = 0x08000000 |
| | | |
| | | while True: |
| | | try: |
| | | logging.info(f"[{name}] 尝试启动:{full_path} {' '.join(args)}") |
| | | |
| | | process = subprocess.Popen( |
| | | [full_path] + args, |
| | | cwd=os.path.dirname(full_path), |
| | | stdout=subprocess.PIPE, |
| | | stderr=subprocess.STDOUT, |
| | | creationflags=CREATE_NO_WINDOW, |
| | | universal_newlines=True, |
| | | encoding="utf-8", |
| | | ) |
| | | |
| | | success = False |
| | | while True: |
| | | line = process.stdout.readline() |
| | | print(line) |
| | | if not line: |
| | | break |
| | | logging.info(f"[{name}] {line.strip()}") |
| | | |
| | | if "connect to server error" in line or "login to the server failed" in line: |
| | | logging.warning(f"[{name}] 连接失败,{retry_interval} 秒后重试...") |
| | | process.kill() |
| | | time.sleep(retry_interval) |
| | | break |
| | | |
| | | if "start proxy success" in line : |
| | | success = True |
| | | |
| | | if success: |
| | | logging.info(f"[{name}] 成功启动并连接") |
| | | return process |
| | | |
| | | except Exception as e: |
| | | logging.error(f"[{name}] 启动异常:{e}") |
| | | time.sleep(retry_interval) |
| | | |
| | | def add_to_startup(): |
| | | try: |
| | | # 获取当前用户名和路径 |
| | | user = getpass.getuser() |
| | | startup_folder = fr"C:\Users\{user}\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" |
| | | |
| | | # 当前可执行文件路径 |
| | | exe_path = os.path.join(BASE_DIR,"sening_vdp.exe") |
| | | |
| | | shortcut_path = os.path.join(startup_folder, "sening_vdp.lnk") |
| | | |
| | | # 创建快捷方式 |
| | | import pythoncom |
| | | from win32com.shell import shell, shellcon |
| | | from win32com.client import Dispatch |
| | | |
| | | shell = Dispatch('WScript.Shell') |
| | | shortcut = shell.CreateShortcut(shortcut_path) |
| | | shortcut.TargetPath = exe_path |
| | | shortcut.WorkingDirectory = os.path.dirname(exe_path) |
| | | shortcut.IconLocation = exe_path |
| | | shortcut.Save() |
| | | except Exception as e: |
| | | print(f"e") |
| | | pass |
| | | |
| | | if __name__ == "__main__": |
| | | logging.info("程序启动") |
| | | add_to_startup() |
| | | import sys |
| | | import win32event |
| | | import win32api |
| | | import winerror |
| | | mutex = win32event.CreateMutex(None, False, "Global\\SeningVDPOnlyOne") |
| | | last_error = win32api.GetLastError() |
| | | if last_error == winerror.ERROR_ALREADY_EXISTS: |
| | | # 已经运行过了,退出 |
| | | sys.exit(0) |
| | | # 启动 Clash(当前目录下 clash.exe,配置文件 clash.yaml) |
| | | clash_process = start_process("sening_vdp1", "sening_vdp1.exe", ["-f", "sening_vdp1.yaml"], LOG_FILE) |
| | | time.sleep(2) |
| | | |
| | | # 启动 frpc(当前目录下 frpc.exe,配置文件 frpc.toml) |
| | | frpc_process = start_process_with_retry("sening_vdp2", "sening_vdp2.exe", ["-c", "sening_vdp2.toml"], LOG_FILE) |
| | | |
| | | try: |
| | | if clash_process: |
| | | clash_process.wait() |
| | | if frpc_process: |
| | | frpc_process.wait() |
| | | except KeyboardInterrupt: |
| | | logging.info("程序被中断,退出") |