[+!] all but small

some small modifications, tests added
This commit is contained in:
2026-10-07 22:42:46 +03:00
parent fac12b2ea8
commit c16ed7915a
21 changed files with 1190 additions and 100 deletions

135
README.md
View File

@@ -1,51 +1,122 @@
# core
# SIRMENT/core
New, better iteration of ARTEX
SIRMENT — сервер системы обмена данными Artex. Узлами могут быть роботы,
операторские приложения и сервисы. Сервер управляет соединениями и сессиями
и передаёт данные по заданным маршрутам.
## Requirements
## Реализовано
Required Python version is specified in `.py-version` (currently Python 3.11).
- **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()` запускает отправку фоновой задачей; маршрутизатор не ждёт
завершения сетевой отправки.
Install application dependencies:
Текущие сроки:
```bash
| Условие | Срок |
| --- | --- |
| От создания сессии до первого 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
```
Install development dependencies:
```bash
python -m pip install -r req-dev.txt
```
Run the application:
```bash
python src/main.py
```
`src/main.py` is initially empty. Add application logic before using the image as a service.
Общий клиент находится в отслеживаемом `examples/client.py`:
## Tests
Run all tests:
```bash
python -m pytest
```sh
python examples/client.py rover --count 10 --interval 1
python examples/client.py rover --old-token 123 --old-upf 456
```
Tests are also executed automatically for Pull Requests targeting `main`.
На Windows можно использовать `src/start_server.bat` и
`examples/start_client.bat`; они берут Python из
`D:\_Programs\anaconda\envs\sites`.
## Docker
## Тесты
Docker images are built automatically:
```sh
python -m pip install -r req-dev.txt
python -m pytest -q --cov=src --cov-branch --cov-report=term-missing --cov-report=xml
```
- when changes are pushed to the `deploy` branch;
- when a version tag matching `v*.*.*` is created.
Тесты используют общий клиент из `examples/`, поэтому не зависят от локальной
игнорируемой папки `src/.test`. Интеграционные сценарии работают с настоящим
TCP-сервером. Отдельно выполняется настоящий `src/main.py` в дочернем процессе.
Подробности и команды запуска — в [tests/README.md](tests/README.md).
Новые регрессии остаются обычными падающими тестами до исправления реализации.
## Project structure
## Docker и CI
Тесты выполняются для Pull Requests в `main` и при ручном запуске workflow.
Docker-образы собираются при push в `deploy` и создании тегов `v*.*.*`.
Образ запускает `python src/main.py`.
## Структура
```text
src/ Application source code
tests/ Add automated tests here
src/ TCP, сессии, маршрутизатор и точка входа
examples/ Общий клиент и батник ручного запуска
tests/ Модульные, TCP-интеграционные и процессные тесты
```