wangzhibo
2025-07-30 c076385d8e3569f49e5be9fd50becf18042476c8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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("程序被中断,退出")