zapret-kvn/docs/sing-box/routing-gui.md
loop-uh dd0ccadaff
Some checks failed
Windows project source guards / test (push) Failing after 41s
Правила: простое правило в духе v2rayN и «Проверить сайт»
«Добавить правило» → «Сайты, IP, программы (просто)»: куда (через VPN /
напрямую / блок) и списки по строке в синтаксисе v2rayN. 2ip.ru — сайт с
поддоменами (domain_suffix), geosite:/geoip: — существующие наборы,
сайты и программы — логическое ИЛИ. Документ не меняется до «Добавить»,
правило встаёт сразу после sniff/hijack-dns, «Добавить и применить» —
тем же путём, что «Применить».

«Проверить сайт» над списком проходит правила в порядке ядра и
показывает сработавшее правило и выход; условия по программе — «может
перехватить». Наборы проверяет само ядро (sing-box rule-set match -f),
вне GUI-потока, с номером поколения.
2026-09-27 13:07:02 +03:00

11 KiB
Raw Permalink Blame History

Маршрутизация: структурный редактор sing-box

Раздел «Маршрутизация» в боковом меню редактирует активный native JSON sing-box (data/configs/sing-box/*.json). Своей модели маршрутизации у приложения нет: формы меняют разобранный JSON на месте и записывают его обратно, страница «JSON» показывает тот же документ.

Страницы

Подпункт Что редактирует
Обзор выбор конфига и шаблона, сравнение со стоком, сброс всего конфига или одного раздела, статус
Правила route.rules (сверху вниз, первое совпадение) и route.final
Наборы правил route.rule_set: local / remote / inline
DNS параметры dns, dns.servers, dns.rules
Исходящие outbounds и endpoints; proxy — слот выбранного сервера, только просмотр
Система inbounds (TUN), остальные route.*, log, experimental, прочие секции
JSON весь документ текстом

Правки живые: «Готово» закрывает подстраницу, «Отменить правки» возвращает объект к состоянию на момент открытия. На диск пишут только «Сохранить»/«Применить» в верхней панели; «Проверить» запускает sing-box check бандл-ядром по редактируемому JSON в фоне (служебные подстановки запуска в эту проверку не входят).

Простое правило и «Проверить сайт»

  • «Добавить правило» → «Сайты, IP, программы (просто)» (ui/singbox/simple_rule_page.py, разбор — singbox_config/simple_rule.py): куда (через VPN / напрямую / блок) и списки по одному в строке в синтаксисе v2rayN. 2ip.ru — domain_suffix (сайт и поддомены), full:/keyword:/regexp:, geosite:/geoip: — существующие наборы, geoip:private — ip_is_private, программа с путём — process_path. Сайты/IP и программы собираются в logical or: в ядре разные виды условий идут через И. Документ не меняется до «Добавить»; правило встаёт сразу после sniff/hijack-dns. «Добавить и применить» идёт тем же путём, что «Применить».
  • «Проверить сайт» над списком (singbox_config/route_explain.py, application/route_check.py): порядок ядра — сверху вниз до первого совпадения, sniff/resolve/route-options не останавливают, иначе route.final. Запрос — браузер: TCP/443/TLS, программа неизвестна; условия вроде процесса дают «может перехватить», перебор идёт дальше. IP-условия — только в TUN или после resolve. Наборы проверяет само ядро: sing-box rule-set match -f <format> (без -f ядро не читает .srs), наборы по URL — «не узнать». Проверяется редактируемый документ, включая несохранённые правки.

Откуда берутся поля

assets/sing-box-schema/schema.json — JSON Schema, которую генерирует само закреплённое ядро (sing-box schema) из своих Go-структур: python3 scripts/generate_singbox_schema.py после смены пина sing-box в scripts/core-lock.windows-x64.json. Форк не умеет описать несколько своих типов (amnezia-диапазоны endpoints, byte-размеры, providers); генератор ослабляет только их и пишет пути в loose-paths.txt. Тест гарантирует, что их нет в route, dns, inbounds, outbounds, log и experimental; такие поля endpoints редактируются как JSON.

sing-box check по исходному JSON не видит служебных подстановок запуска. Поэтому outbound direct и DNS-сервер bootstrap-dns, на которые запуск ссылается сам, помечены как нужные приложению, а их удаление требует подтверждения.

  • xray_fluent/singbox_config/schema.py — чтение схемы: поля объекта с учётом дискриминатора (type, action), Listable-поля, ссылки на теги (x-tag-reference).
  • xray_fluent/singbox_config/catalog.py — только подписи, закреплённые поля и сводки строк. Поле без подписи всё равно доступно под своим native-ключом.
  • xray_fluent/ui/singbox/form.py — форма показывает заданные, обязательные и закреплённые поля; всё остальное, что знает ядро, — в «Добавить параметр». Смена type/action убирает поля, которые новый вариант не принимает.

Инварианты

  • Открытие страниц и объектов не меняет JSON (пустые секции создаются только при первой настоящей правке).
  • Неизвестные ядру ключи сохраняются и показываются как «неизвестное поле».
  • Одиночное значение Listable-поля остаётся скаляром, пока в нём один элемент.
  • При ошибке JSON разделы только читают и предлагают исправить текст на странице «JSON».
  • Обновление приложения сливает стоковый шаблон посекционно (template_sync.merge_stock_sections): нетронутые разделы следуют за стоком, изменённые остаются вашими. Принудительной синхронизации DNS больше нет.
  • Виджеты редактора удаляются только через qt_lifecycle.dispose_later: скрытие сразу, разрушение на следующем такте при выключенном циклическом GC (у ScrollArea/PlainTextEdit/RoundMenu qfluentwidgets есть SmoothScrollDelegate, гонка GC с деструкторами роняет процесс, на Windows — особенно). Меню «Добавить…» строятся по клику и удаляются после закрытия.
  • qfluentwidgets 1.11 не освобождает Python-обёртки удалённых стилизованных виджетов (лямбды на destroyed и qconfig.themeChanged). Глобально это не патчится: освобождённые обёртки попадают под ту же гонку GC во всём приложении. Поэтому редактор бережёт виджеты: строки списков обновляются на месте, невидимые разделы пересобираются только при показе, повторная загрузка того же текста ничего не пересобирает, схема ядра грузится при первой сборке раздела.
  • Смена type/action пересобирает форму на следующем такте: выбор приходит из всплывающего меню самого комбобокса.
  • Незафиксированный ввод (списки и JSON применяются с задержкой) сбрасывается в документ по потере фокуса, «Готово», переключению раздела и перед «Сохранить/Применить/Проверить».

Графика и анимация

  • Строки списков несут значок-плитку (ui/singbox/visuals.py): тон по смыслу — прокси = акцент, напрямую = зелёный (success), блок = error, DNS = info, служебные действия = warning. Цвета берутся из ui/theme.py в момент отрисовки, так что следуют теме и акценту; hex-литералов вне theme.py нет.
  • На странице раздела только заголовок и данные. Пояснения для новичков и живая иллюстрация открываются ссылкой «Как это б#&^ь работает?» в стоковом окне MessageBoxBase поверх приложения (ui/singbox/guide.py: тексты GUIDES, окно удаляется через dispose_later). Иллюстрация (ui/singbox/art.py, QPainter) рисует конфиг пользователя: «Обзор» — карта, где пакеты уходят в прокси, напрямую или в блок пропорционально числу правил (visuals.rule_outcomes); «Правила» — зонд идёт сверху вниз и останавливается на первом совпадении; «DNS» — вращающийся глобус и запрос/ответ; «Исходящие» — хаб с импульсами; «Система» — туннель TUN; «JSON» — набор текста.
  • Анимации работают на motion.FrameGate: кадры (25 fps, у JSON 12 fps) идут только пока виджет виден и в Windows не выключена анимация интерфейса; иначе рисуется неподвижный кадр. Фаза берётся из реального времени.
  • Иконки Fluent рисуются из кэша растров по (иконка, цвет, размер, DPR): FluentIcon.render(fill=…) разбирает SVG на каждом вызове.
  • Микроанимации: вспышка строки при добавлении/дублировании/перемещении, пульсирующая точка несохранённых правок, подстраницы въезжают справа, возврат — слева, разделы появляются снизу (PopUpAniStackedWidget qfluentwidgets; текущая страница переключается сразу, анимируется только положение).