44右键菜单:
55
66 - 打开管理界面 → 浏览器打开 http://localhost:<port>(.port 文件)
7+ - 启动 Gateway → 停止后重新拉起 gateway(若已在跑则打开浏览器)
78 - 重启 Gateway → 杀掉旧 PID,等端口空闲,再启动新的 gateway
8- - 停止 Gateway → 杀掉 gateway 进程(托盘自身保留,可手动重启 )
9+ - 停止 Gateway → 杀掉 gateway 进程(托盘自身保留,可手动启动/重启 )
910 - 退出托盘 → 关闭托盘(gateway 继续运行)
1011
1112入口由 ``__main__`` 在 lifespan startup 阶段以独立子进程拉起,确保
@@ -234,10 +235,21 @@ def _open_browser(icon: pystray.Icon, item: pystray.MenuItem) -> None:
234235
235236
236237def _restart_gateway (icon : pystray .Icon , item : pystray .MenuItem ) -> None :
237- port = _read_port ()
238238 logger .info ("用户触发重启" )
239239 # 先清过期锁(gateway 已被外部 kill -9 / 任务管理器结束的场景)
240240 _clear_stale_lock ()
241+ # "停止"之后 gateway 已死、.lock 已被 atexit 删掉,_read_pid() 返回 None。
242+ # 此时 _kill_gateway() 返回 False,旧实现会短路掉 _spawn_gateway()——
243+ # 结果用户点"重启"什么也没发生。这里改成:没有正在跑的进程就直接拉起。
244+ # 注意不调 _wait_for_port_free:停止后 .port 已被删,_read_port() 退回
245+ # 8130,但 8130 可能被别的应用占用——此时等它空闲会误判为"端口占用"。
246+ # gateway 内部的 find_available_port 会自己探测可用端口,托盘不需要干预。
247+ pid = _read_pid ()
248+ if pid is None :
249+ logger .info ("未发现正在运行的 gateway,直接启动新实例" )
250+ _spawn_gateway ()
251+ return
252+ port = _read_port ()
241253 if _kill_gateway () and _wait_for_port_free (port , timeout = 10.0 ):
242254 _spawn_gateway ()
243255 else :
@@ -255,9 +267,29 @@ def _quit_tray(icon: pystray.Icon, item: pystray.MenuItem) -> None:
255267 icon .stop ()
256268
257269
270+ def _start_gateway (icon : pystray .Icon , item : pystray .MenuItem ) -> None :
271+ """启动 gateway(停止后用来重新拉起服务)。
272+
273+ 与 _restart_gateway 的区别:这里假定当前没有正在运行的 gateway,
274+ 不做 kill,直接 spawn。gateway 内部的 find_available_port 会自己
275+ 探测可用端口,托盘不需要预先等端口空闲(否则 8130 被别的应用占用时
276+ 会误判为"无法启动")。
277+ """
278+ logger .info ("用户触发启动" )
279+ _clear_stale_lock ()
280+ pid = _read_pid ()
281+ if pid is not None and _is_pid_alive_windows (pid ):
282+ # 已经在跑——直接打开浏览器,不重复拉起
283+ logger .info ("gateway 已在运行,打开浏览器" )
284+ _open_browser (icon , item )
285+ return
286+ _spawn_gateway ()
287+
288+
258289def _build_menu () -> pystray .Menu :
259290 return pystray .Menu (
260291 pystray .MenuItem ("打开管理界面" , _open_browser , default = True ),
292+ pystray .MenuItem ("启动 QMT Gateway" , _start_gateway ),
261293 pystray .MenuItem ("重启 QMT Gateway" , _restart_gateway ),
262294 pystray .MenuItem ("停止 QMT Gateway" , _stop_gateway ),
263295 pystray .Menu .SEPARATOR ,
0 commit comments