Files
core/README.md
FoxVoland c16ed7915a [+!] all but small
some small modifications, tests added
2026-10-07 22:42:46 +03:00

123 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SIRMENT/core
SIRMENT — сервер системы обмена данными Artex. Узлами могут быть роботы,
операторские приложения и сервисы. Сервер управляет соединениями и сессиями
и передаёт данные по заданным маршрутам.
## Реализовано
- **Transport/TCP** принимает соединения и читает JSON-пакеты, разделённые LF.
`TCP.run()` запускает настоящий asyncio-сервер; `src/main.py` собирает Router
и SessionManager и запускает TCP на `0.0.0.0:9000`.
- **Session** хранит состояние подключения, версию протокола, метаданные и
последние данные по командам. Handshake проходит последовательность
`connection → token_ask → token_answer → handshake_ask → handshake_answer`.
После успешного ответа сессия переходит в `air`.
- **Heartbeat**: клиент отправляет `heartbeat_ask` с `payload`, сервер
отвечает `heartbeat_answer` и обновляет дедлайн.
- **Watcher**: у каждой сессии есть собственная asyncio-задача, проверяющая
дедлайн раз в секунду и передающая менеджеру событие `disconnect`.
- **Отключение** закрывает транспорт и переводит сессию в `stop`. Менеджер
сохраняет запись на время восстановления, затем удаляет её и маршруты.
- **Реконект** создаёт новый UID и собственный handshake. В `token_answer`
можно передать старые `token` и `upf`. Сессия в `stop` с совпадающим `upf`
отдаёт динамические метаданные и последние данные; Router переносит
исходящие маршруты и все входящие ссылки на новый UID. Старая сессия
получает состояние `migrated`, поэтому перенос нельзя повторить.
- **Router** передаёт полезную нагрузку отправителя каждому получателю.
`Session.send()` запускает отправку фоновой задачей; маршрутизатор не ждёт
завершения сетевой отправки.
Текущие сроки:
| Условие | Срок |
| --- | --- |
| От создания сессии до первого heartbeat, включая handshake | 60 секунд |
| После каждого heartbeat | 5 секунд |
| Сохранение отключённой сессии для восстановления | 60 секунд |
Проверка watcher выполняется раз в секунду: фактическое обнаружение таймаута
может произойти позже дедлайна на период проверки. Сам event loop продолжает
обслуживать остальные соединения во время `asyncio.sleep()`.
`in`/`out` описывают типы портов будущего редактора узлов. `active_in` и
`active_out` хранят динамическое состояние. Эти поля сами по себе не создают
маршруты. Значение `com` и общее правило объединения метаданных при реконекте
ещё не зафиксированы.
`connection.payload.token` — токен робота, сохраняемый в метаданных `auth`;
его будущая проверка по whitelist роутера пока не реализована. UID/upf в
`token_answer` служат отдельно для восстановления сессии.
По согласованному протоколу отказ handshake означает только буквальный JSON
`false`; остальные значения `status` означают успех. Текущий `if not status`
ещё использует ложность Python и расходится с этим правилом.
Payload данных сохраняется и пересылается как JSON-значение без автокаста
в словарь. Ошибка разбора входного пакета может завершить обработчик клиента;
TCP-finally закрывает его сессию, остальные соединения продолжают обслуживаться.
## Незавершённое и ограничения
- GUI/API редактирования маршрутов; автоматическое создание маршрутов и
правила подписок.
- Авторизация. Совпадение UID/upf сейчас используется для восстановления и
не заменяет полноценную авторизацию.
- Полноценное переключение диалектов: используется `v1`; `v2` и `short`
содержат только черновые имена полей и не имеют полного набора команд.
- WebSocket/Socket.IO (`sio`).
- Сохранение сессий, данных и маршрутов после перезапуска процесса.
- Отдельный ответ клиенту с результатом восстановления. Heartbeat подтверждает
новый handshake, но не доказывает успешный перенос старой сессии.
- Настройка адреса и порта через CLI/окружение: сейчас они заданы в `main.py`.
Актуальные результаты, ошибки реализации и ограничения проверки приведены
в [отчёте тестов](tests/REPORT.md). Изменения исходников сервера выполняет автор
проекта; доработка тестов и документации не редактирует `src`.
## Запуск
Версия Python указана в `.py-version` — Python 3.11. Из корня репозитория:
```sh
python -m pip install -r req.txt
python src/main.py
```
Общий клиент находится в отслеживаемом `examples/client.py`:
```sh
python examples/client.py rover --count 10 --interval 1
python examples/client.py rover --old-token 123 --old-upf 456
```
На Windows можно использовать `src/start_server.bat` и
`examples/start_client.bat`; они берут Python из
`D:\_Programs\anaconda\envs\sites`.
## Тесты
```sh
python -m pip install -r req-dev.txt
python -m pytest -q --cov=src --cov-branch --cov-report=term-missing --cov-report=xml
```
Тесты используют общий клиент из `examples/`, поэтому не зависят от локальной
игнорируемой папки `src/.test`. Интеграционные сценарии работают с настоящим
TCP-сервером. Отдельно выполняется настоящий `src/main.py` в дочернем процессе.
Подробности и команды запуска — в [tests/README.md](tests/README.md).
Новые регрессии остаются обычными падающими тестами до исправления реализации.
## Docker и CI
Тесты выполняются для Pull Requests в `main` и при ручном запуске workflow.
Docker-образы собираются при push в `deploy` и создании тегов `v*.*.*`.
Образ запускает `python src/main.py`.
## Структура
```text
src/ TCP, сессии, маршрутизатор и точка входа
examples/ Общий клиент и батник ручного запуска
tests/ Модульные, TCP-интеграционные и процессные тесты
```