20 KiB
Архитектура
Модули
| Каталог | Назначение |
|---|---|
hockey_data/ |
Stat2TV, PostgreSQL, матч, статистика, роли, mapping и Agent bridge |
ui_builder/ |
Действующий runtime/редактор UI и активные статические ресурсы |
broadcast_settings/ |
Переносимые настройки команд и vMix JSON |
khl_site/ |
Карточки КХЛ, карьера, обновления и локальные данные |
agent/ |
Windows Agent и исходники Go |
settings/local/ |
Активная конфигурация UI, таймеров, обновлений и восстановление |
tests/ |
Регрессии серверной логики и браузерных функций |
logs/ |
Закрытый постоянный журнал программы в месячных SQLite-файлах |
Поток данных
BUILD202 разделяет обработку гола на снятие, ожидание, скрытую подготовку и фиксацию.
На затронутых физических Input сначала завершаются уже отправленные записи, затем
отправляется отдельный OUT. До его подтверждения и окончания настроенного интервала
новые DATA/Mapping, native-команды и IN этих Input удерживаются. Сервер использует
goal_hide_settle_seconds, клиент получает признак hide_settled; настройка цели
goal_hide_delay_seconds задаёт 0–60 с, по умолчанию 1 с. Для нескольких привязок
одного физического Input используется наибольшее значение. ACK не является событием
завершения GT TransitionOut: длительность задаёт оператор по своему титру.
После ожидания время готовится скрыто и подтверждается перед фиксацией карточки. У первой половины 2+2 остаётся 2:00; актуальный Mapping не перезаписывает native-поля, после его подтверждения восстанавливаются ранее занятые слои. Общий Input нескольких известных удалений снимается целиком; оставшиеся часы подготавливаются по текущему состоянию без завершения соседних карточек. Основной счёт, чужой титр и неоднозначное владение полем не снимаются этим путём. Ошибка или неизвестный исход сохраняет карточку и блокировку затронутого Input до явной ручной проверки; OUT не повторяется автоматически. Независимые Input могут продолжать целевое обновление данных.
Сервер сопоставляет ключ, GUID, имя и номер Input с единственным физическим Input текущей inventory. Во время снятия/неподтверждённого результата команды без Input или с неразрешимой привязкой отклоняются, чтобы не обойти защиту. Входящий кадр регистрируется атомарно на всех его Input; перед OUT дожидаются подтверждений уже отправленных записей. Разделение кадров сохраняет порядок команд одного Overlay, даже если он переключается между разными Input.
После неуспешного отправленного OUT сервер освобождает временные блокировки,
но оставляет Input в карантине: отдельный DATA/native/IN-запрос получает
409 goal_hide_unconfirmed. Составной пакет может вернуть 200 с ok: false
и позиционной причиной, сохранив ACK успешных независимых Input.
Карантин снимает успешный явно запрошенный OUT с подтверждением и интервалом
снятия; затем клиент выполняет исходную ручную команду управления удалением.
Инвалидация поколения доставки устройства делает старое ожидание и карантин
неактуальными: это смена соединения, подтверждённое отключение vMix, новое
назначение, принятая inventory проекта или передача контроля. Простое сохранение
конфига/сессии карантин не снимает. Прежний ответ Agent не может подтвердить
новое назначение.
Автоматического повтора OUT для восстановления нет.
Расчёт численного состава исключает дисциплинарные 10/20, явно отмеченные
queued/awaitingStart и компенсированные записи (offsetting/affectsStrength: false).
Эти признаки сохраняются вместе с карточкой. Сам coincidental не исключает
штраф из состава, но запрещает автоматическое завершение голом; модель не
заменяет решение судьи о взаимозачёте, очереди и возвращении состава в овертайме.
После последнего влияющего на состав штрафа цикл плашки завершается, даже если
в панели осталась дисциплинарная запись; новый цикл не наследует старого владельца.
BUILD201 удаляет ручной переключатель «ШБ» и исключает устаревший флаг
score_penalty_shot из определения обычного гола. Явно переданный тип текущего
гола penalty_shot сохраняет своё отдельное значение.
BUILD200 сохраняет владельца плашки удаления вместе с её циклом показа, чтобы переход 4on4 → PP не переносил текущий титр на другую сторону. Подтверждение нужных команд vMix предшествует фиксации завершения штрафа в панели; ошибка доставки сохраняет карточку для проверки, неизвестный исход не воспроизводится.
BUILD199 хранит разрешение связанных плашек в флаге матча
scoreboard_auxiliaries_enabled. Checkbox и F2 используют один контролируемый
запрос; на отправке заново проверяются матч, роль, версия намерения и конкретные
Input/Overlay. Gate отделён от часов и подготовки данных. Снятие не отменяет
native Countdown, а повторное включение сохраняет исходный срок задержки счёта.
Обработка гола выполняется у действующего оператора по новой команде +1 или одиночному приросту уже наблюдаемого SQL/API-счёта. Первый снимок и изменение источника задают базу. История хранит идентификатор обработанного перехода и снимок изменения штрафа для защиты от повторов и осторожной отмены гола. Для подтверждаемого изменения штрафа native-команды формируются перед самой отправкой по текущему состоянию конкретного Input/SelectedName, чтобы поздний Start не возобновил уже приостановленные часы и не затронул соседнее поле.
Stat2TV XML/JSON разбираются сервисом и сохраняются в нормализованных таблицах PostgreSQL: турниры, команды, игроки, составы, события и статистика. Карточки/карьера КХЛ имеют отдельный локальный импорт и синхронизацию. Рабочее состояние матча и права доступа относятся к матчу; персональный канал, назначение устройства и mapping определяют получателя данных vMix.
SQL Mapping получает контекст матча/выбора, формирует SetText/SetImage и передаёт их нужному Agent. Отправка команды и её подтверждение — разные этапы. Команды действий (например, Toggle/Cut) нельзя повторять без проверки результата. Восстановление связи должно заново синхронизировать данные, не воспроизводя эфирные действия.
Mapping имеет раздельное ожидаемое и подтверждённое состояние. На Agent ожидается
ACK не более одного пакета Mapping. Agent с явной capability mapping_title_batch_v1
получает команды, сгруппированные по Input, до 500 команд и 48 КиБ; прежние версии
получают до шести независимых установок. Новый Agent сохраняет порядок записей
одной цели, выполняет независимые цели ограниченным пулом и выделяет отдельный
обработчик для интерактивных команд. WebSocket reader продолжает читать назначения,
heartbeat и управление во время массовой отправки. Очереди и время обработки ограничены.
Ошибки отдельных полей не прерывают первый проход по остальным; безопасные повторы выполняются после него. Частичный результат отличается от полной обработки. SQL-каталог ограничен источниками действующих записей и правил, включая зависимости настроенного счёта. Поколение соединения/назначения отбрасывает устаревшие подтверждения. Новый WebSocket ждёт актуальную inventory перед восстановлением. После committed передачи управления обновляется поколение доставки устройств матча.
Шаблон Mapping и опубликованный снимок устройства разделены. Снимок использует существующие таблицы профилей/полей и хранится как технический профиль, связанный с устройством. Сериализация устройства внутри транзакции передаёт её же session в публикацию Mapping, без вложенного подключения с конкурирующей блокировкой. Сохранение шаблона атомарно проверяет ожидаемую версию. Общие SQL источники остаются общими; параметры контекста разрешаются для конкретного матча.
Эксплуатационный журнал независим от доступности PostgreSQL. Он получает структурированные события приложения, стандартный Python logging, Uvicorn, HTTP-аудит и браузерные замеры. Неблокирующая очередь ограничена, запись пакетная; чтение использует короткие подключения и курсорную пагинацию. Секреты маскируются до очереди записи. Запись startup/shutdown закрывается штатно и через atexit.
Сводка готовности к эфиру читает только назначение и опубликованный Mapping выбранного устройства, доступного текущему аккаунту. Она сопоставляет цели с inventory текущего WebSocket и использует подтверждения обработки Mapping текущего поколения. Просмотр не исполняет SQL источников, не создаёт публикации и не отправляет команды Agent. Эти подтверждения живут в памяти процесса; после смены контекста или разрыва связи прежний успех не доказывает готовность.
Stat2TV использует общий ограниченный HTTP-пул, а не новое соединение на каждый запрос. Авторизация и timeout передаются отдельно для каждого запроса; при завершении сервера HTTP-клиенты закрываются после фоновых задач.
Состояние WebSocket/Agent и часть кэшей находятся в памяти одного процесса. Поэтому запуск нескольких workers без общего хранилища назначения/очередей не является способом масштабирования этой версии.
Пользовательские данные и артефакты
UI хранится атомарно в settings/local/ либо внешнем HOCKEY_UI_DATA_DIR.
Одинаковые сохранения не создают копий. Миграция прежней истории backup выполняется
однократно; исходные root-настройки сохраняются как bootstrap.
hockey_data/snapshots/ — диагностические XML, а не база рабочего состояния.
Новые имена включают полный SHA-256 содержимого и тип ресурса. Повторные данные
используют прежний путь без перезаписи. История синхронизаций в БД может ссылаться
на эти файлы, поэтому возрастная очистка XML запрещена без сверки ссылок БД.
Автоматический retention относится только к самостоятельным JSON-отчётам discovery.
Флаги и их LICENSE, шаблоны vMix JSON, исходники Go/Agent.exe, SQL-примеры и проверки входят в проект по назначению. Совпадение имён или содержимого файлов default и локальной конфигурации не делает их взаимозаменяемыми.
Ответы браузерных запросов матча привязаны к поколению выбора и сессии. Загрузка общих данных провайдера сохраняет рабочий контекст выбранного матча. Эффективный SQL-счёт берётся из текущего Game либо проверенного результата настроенного ключа для каждой стороны; ручные значения хранятся отдельно.
В BUILD198 право просмотра матча, DATA/Mapping своему Agent и право управления разделены. Выбор роли завершается перед включением блокирующего loader; устаревший выбор и объединённые запросы проверяют поколение запроса. Операторские маршруты по-прежнему проверяют владельца управления. Заполнение по опубликованному Mapping не предоставляет права выполнять произвольные команды.
Показ использует барьер подтверждённых данных конкретного Input. Явные setters подтверждаются до IN/Preview; неполный Mapping не подтверждает готовность титра, требующего данных. Ошибка подготовки блокирует последующий показ этой цели, сохраняя обработку независимых титров. Все автоматические пути общей плашки используют одну задержку от показа основного счёта. Снятие фиксирует связанные цели, отменяет ожидающий IN и проверяет Input/владельца перед каждым OUT.
Agent 1.5.6 согласует vmix_priority_v1: bounded-очереди срочного управления,
обычных команд и Mapping. Общая HTTP-ёмкость равна 6, обычное управление и
Mapping совместно ограничены 5. Цепочки одной физической цели и Overlay сохраняют
причинный порядок между очередями. Новое явное обновление поля снимает право
устаревшего Mapping записывать это поле; пропуск не считается успешным ACK.
Корреляция trace_id связывает отдельные монотонные замеры браузера, сервера и
Agent. Часы разных компьютеров не вычитаются друг из друга.
В BUILD197 браузер связывает загрузку матча с поколением, аккаунтом, сессией, языком и выбранным устройством. Mapping ждёт полных составов обеих команд. Изменение упорядоченных данных игроков запускает полный apply выбранного Agent со свежим разрешением SQL; одинаковые снимки объединяются. Признаки счёта, времени, статистики и timestamps не входят в отпечаток состава. Ответ старой отправки не закрывает окно нового матча. Полный apply сохраняет существующую защиту native Countdown: поля таймеров исключаются до разрешения зависимостей.