[+!] sio legacy

This commit is contained in:
2026-10-08 19:35:14 +03:00
parent c16ed7915a
commit 11f1bbdd12
9 changed files with 891 additions and 14 deletions

View File

@@ -0,0 +1,110 @@
# Socket.IO для старого Artex-robot
Адаптер подключает старый `core/com/Connector` из Artex-robot к текущим
`SessionManager`, `Session` и `Router`. Код ядра, TCP и `main.py` не изменяется.
Все файлы адаптера, его зависимости и тесты находятся в этой папке.
## Подключение
Из папки `server` установите зависимости:
```powershell
& 'D:\_Programs\anaconda\envs\sites\python.exe' -m pip install -r src/transport/sio_legacy/requirements.txt
```
Интерфейс совпадает с TCP:
```python
from transport.sio_legacy import SIO
# sessions — тот же менеджер, который используется TCP.
sio = SIO("0.0.0.0", 9001, sessions)
await sio.run()
```
TCP и Socket.IO могут работать одновременно с одним менеджером и роутером:
`await asyncio.gather(tcp.run(), sio.run())`. Им нужны разные порты.
Отмена задачи `run()` закрывает listener и активные соединения Socket.IO.
Для порта `0` выбранный порт доступен в `sio.bound_port` после
`await sio.started.wait()`.
Сервер использует [python-socketio с aiohttp](https://python-socketio.readthedocs.io/en/stable/server.html),
поддерживает polling и WebSocket, namespace `/robot` и обычный путь `/socket.io`.
Это Socket.IO, не отдельный WebSocket-протокол.
## Соответствие протоколов
| Старый робот | Пакет для ядра / действие адаптера |
| --- | --- |
| Метаданные в `auth` при соединении | `connection`, диалект `v1` |
| Ответ ACK на `token_ask` | `token_answer` без старого token/upf |
| ACK на `heartbeat(["Ready", "d_meta"])`, `Ready == "ok"` | Успешный `handshake_answer` |
| ACK на `heartbeat(["d_meta"])` | `heartbeat_ask`, обновление срока в ядре |
| `telem` / `video` / другой event с `{"payload": value}` | `{"command": event, "payload": value}` |
| Отправка ядром `command` | Event `command` с тем же `payload` |
| Отправка ядром `com` / `force_com` / `sys_com` | Event `command`, `payload` содержит выбранную категорию |
| Остальные отправки ядра | Event с именем `command` пакета и `{"payload": value}` |
`Ready` отправляется один раз при успешном handshake: старый клиент запускает
по этому запросу потоки телеметрии и видео. Последующие heartbeat запрашивают
только `d_meta`. Данные, отправленные этими потоками до ACK handshake, ждут
завершения handshake и затем поступают в ядро.
Первый `Ready` задерживается на `heartbeat_interval`, чтобы исходный Connector
успел завершить инициализацию после `socketio.Client.connect()`.
По умолчанию `heartbeat_interval=1.0`, `ack_timeout=3.0` секунды.
Интервал вместе с ожиданием ACK должен быть меньше пяти секунд.
У ядра остаются прежние сроки: 60 секунд до первого heartbeat, 5 секунд после
heartbeat, 60 секунд хранения отключённой сессии. Истечение ACK также
закрывает соединение; удаление сессии и маршрутов выполняет менеджер.
`video.payload`, включая JPEG `bytes`, сохраняется в `Session.last_data`
без преобразования. Отправка через Socket.IO передаёт тот же бинарный payload.
Текущий JSON-транспорт TCP не кодирует bytes; преобразование для других
транспортов здесь не добавлено.
Исходные `telem_can`, `video_can` и другие поля `auth` доступны в
`Connection.metadata`; последнее `d_meta` — в `Connection.dynamic_meta`.
Они не превращаются в `in/out`, активные порты или маршруты автоматически.
Маршруты задаются существующими средствами Router.
`legacy` пока нужен: у старого робота метаданные передаются через `auth`,
управляющие ответы приходят как Socket.IO ACK, а heartbeat инициирует сервер.
Это отличается от пакетов `v1`. Старый клиент возвращает только `sid`, без
`upf`, и в просмотренной реализации не сохраняет новый token.
Адаптер сохраняет ответ в `Connection.legacy_sid`, но каждое соединение
создаёт новую сессию. Маршруты и данные прежней сессии не восстанавливаются
по одному sid или имени робота.
Ошибки приёма, отправки и heartbeat записываются в лог с sid/uid и закрывают
только соответствующее соединение. `Session.send()` продолжает работать
через фоновые задачи. Отправки одному SID упорядочены, чтобы бинарные
вложения разных пакетов не перемешивались.
## Проверки
Из `server`, после установки зависимостей:
```powershell
$env:PYTHONDONTWRITEBYTECODE = '1'
& 'D:\_Programs\anaconda\envs\sites\python.exe' -B -m pytest -q -p no:cacheprovider tests src/transport/sio_legacy/tests
```
Тесты используют настоящий сервер, ядро и сетевые клиенты. Проверяются
polling/WebSocket, handshake, периодический heartbeat, ранние данные потоков,
bytes, команды, общая маршрутизация TCP/Socket.IO, ошибки фоновой отправки,
таймаут ACK, watcher ядра, повторное закрытие и остановка listener.
Серверные cleanup-таймеры отменяются только при завершении теста.
Дополнительный `test_original_robot_connector` загружает исходные Connector,
handlers, parsers и метаданные из `E:/robot_src`, запускает его настоящие
сетевые обработчики и потоки. Только оборудование заменено источником
тестовых кадров и приёмником команд. Другой путь задаётся через
`$env:ARTEX_ROBOT_SRC = 'путь/к/artex-robot'`. При отсутствии исходников этот
дополнительный тест пропускается; остальные тесты воспроизводимы без них.
Ключ `-B` предотвращает запись pyc в каталог внешнего проекта.
Не проверяются физическое оборудование робота, восстановление сессии без
upf, авторизация и доставка бинарных данных через TCP. API/GUI маршрутов,
автоматическое создание маршрутов и сохранение состояния после перезапуска
не реализуются этим адаптером.