generated from mononoki/pyproj
[+!] all but small
some small modifications, tests added
This commit is contained in:
135
README.md
135
README.md
@@ -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-интеграционные и процессные тесты
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user