connect/disconnect/reconnect/смена прокси/полная замена runtime стали генераторами (connect_selected_steps, disconnect_current_steps, reconnect_steps, _replace_runtime_steps, _start_singbox_runtime_plan_steps, _apply_proxy_runtime_change_steps) и выполняются TransitionRunner'ом. Устаревание поколения генераторы проверяют сами после каждого шага и сами прибирают недостартовавшее; раннер их не закрывает. Координатор: - клик во время перехода только фиксирует желаемое состояние и поколение; подготовка выбранного сервера (DNS/Zapret) повторяется после завершения идущего перехода (_kick_transition), клики сливаются в последнее состояние; - синхронные disconnect_current() из обработчиков убраны: остановка перед DNS/Zapret — шаг координатора (_run_prestop), отказ профиля Zapret и потеря winws2 — тихий disconnect через очередь (_request_stop), lock() — через очередь; - устаревший переход не блокирует сигнатуру и не сбрасывает desired; процессы прерванного перехода (включая запущенные, но не готовые — process_alive) гасит отдельный шаг cleanup; - горячий свитч во время полного перехода уходит в очередь. Системный прокси: все записи WinAPI — в отдельном FIFO-потоке (PROXY_EXECUTOR): шагами в переходах, без ожидания из обработчиков сигналов, с дренажом очереди перед финальным восстановлением при выходе. Аварийное отключение из обработчиков (unexpected disconnect, отказ Hysteria) закрывает допуск kill'ом без ожидания; внутри перехода — шагами. Повторный PUT выбора сервера после connect удалён: тот же тег (plan.selected_outbound_tag == selector_tags[node.id]) уже закреплён при старте runtime; инварианты пула/тегов не затронуты. Сигнатуры переходов больше не строят полный план 7–10 раз за клик: поля плана (теги селектора, провайдер, used_selected_node) кэшируются по документу, режиму, ноде и составу пула; сброс по nodes_changed. Приёмка: tests/test_app_transition_gui_stalls.py — настоящий контроллер и QProcess с заглушкой ядра, блокирующие примитивы с реалистичными задержками; connect, горячий и полный свитч, смена прокси, TUN туда-обратно и disconnect дают max_stall < 50 мс, ноль processEvents, клик во время перехода не вкладывается.
60 lines
1.5 KiB
Python
60 lines
1.5 KiB
Python
"""sing-box engine helpers."""
|
|
|
|
from .config_builder import build_singbox_outbound
|
|
from .manager import SingBoxManager, get_singbox_version
|
|
from .operations import (
|
|
restart_proxy_runtime,
|
|
restart_proxy_runtime_steps,
|
|
restart_runtime,
|
|
restart_runtime_steps,
|
|
start_proxy,
|
|
start_proxy_steps,
|
|
start_tun,
|
|
start_tun_steps,
|
|
)
|
|
from .runtime_planner import (
|
|
ParsedSingboxDocument,
|
|
SingboxDocumentState,
|
|
SingboxHysteriaSidecarPlan,
|
|
SingboxRuntimePlan,
|
|
SingboxXraySidecarPlan,
|
|
classify_node_for_singbox,
|
|
inspect_singbox_document_text,
|
|
parse_singbox_document,
|
|
plan_singbox_proxy_runtime,
|
|
plan_singbox_runtime,
|
|
)
|
|
from .selector_api import (
|
|
build_selector_url,
|
|
select_outbound,
|
|
select_outbound_when_ready,
|
|
select_outbound_when_ready_steps,
|
|
)
|
|
|
|
__all__ = [
|
|
"build_singbox_outbound",
|
|
"SingBoxManager",
|
|
"get_singbox_version",
|
|
"restart_runtime",
|
|
"restart_runtime_steps",
|
|
"restart_proxy_runtime",
|
|
"restart_proxy_runtime_steps",
|
|
"start_proxy",
|
|
"start_proxy_steps",
|
|
"start_tun",
|
|
"start_tun_steps",
|
|
"ParsedSingboxDocument",
|
|
"SingboxDocumentState",
|
|
"SingboxHysteriaSidecarPlan",
|
|
"SingboxRuntimePlan",
|
|
"SingboxXraySidecarPlan",
|
|
"classify_node_for_singbox",
|
|
"inspect_singbox_document_text",
|
|
"parse_singbox_document",
|
|
"plan_singbox_proxy_runtime",
|
|
"plan_singbox_runtime",
|
|
"build_selector_url",
|
|
"select_outbound",
|
|
"select_outbound_when_ready",
|
|
"select_outbound_when_ready_steps",
|
|
]
|