wangzhibo
2025-07-27 a6662268312eb645cc7b5bf9f2ad6f5635d3cb28
network/sening_vdp.py
@@ -0,0 +1,139 @@
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("程序被中断,退出")