bifurcado de antekov/mt5-manager
# Устройство приложения и API
| |
| |
[Документация](README.md) · [Конфигурация](configuration.md) · [Эксплуатация](maintenance.md)
| |
| |
## Компоненты
| |
| |
```text
| |
Браузер → FastAPI → TerminalManager → процессы MT5 (/portable)
| |
→ ConfigStore → личный JSON
| |
→ MT5_Control → psutil + чтение SQLite
| |
Каждый MT5 → ServiceStateWriter → общая SQLite в Common/Files
| |
```
| |
| |
| Файл | Ответственность |
| |
|---|---|
| |
| `run.py` | Параметры запуска Uvicorn; `--reload` включается только явно |
| |
| `main.py` | Страницы, проверка входных данных, HTTP API и время жизни менеджера |
| |
| `config.py` | Проверка JSON, разрешение путей и атомарное сохранение |
| |
| `terminal_manager.py` | Создание, подключение счетов, запуск, остановка и очередь задач |
| |
| `mt5_control.py` | Поиск процессов по пути EXE и чтение последних данных сервиса |
| |
| `project_updates.py` | Проверка upstream, fast-forward, сборка и копирование сервиса |
| |
| `ServiceStateWriter.mq5` | Регистрация терминала и запись текущего состояния |
| |
| `deploy_service.py` | Первоначальный сценарий развёртывания; общая функция компиляции |
| |
| `templates/`, `static/` | Jinja2, локальные CSS/SVG и JavaScript без Bootstrap/jQuery |
| |
| |
SQLite содержит `terminals` с уникальным именем папки и сведениями об установке
| |
и `states` с последним снимком счёта/соединения. Сервис работает независимо от
| |
графиков, использует WAL, тайм-аут блокировки и UPSERT. История ещё не записывается.
| |
Временные метки — Unix-секунды UTC (`TimeGMT()` на стороне MQL5).
| |
| |
Python определяет наличие процесса через `psutil`. Если процесс есть и данные
| |
не старее 30 секунд, внутренний статус — `running`; иначе при живом процессе
| |
`starting`, при отсутствии — `stopped`. Интерфейс дополнительно различает
| |
подключённый счёт и отсутствие торгового соединения.
| |
| |
## Фоновые операции
| |
| |
Длительная команда возвращает HTTP 202 и объект задачи. Это подтверждает постановку
| |
в очередь, а не успех. Клиент запрашивает `GET /api/jobs/{id}` до `done` или `error`.
| |
Задачи выполняются одним рабочим потоком; повторная команда для того же экземпляра
| |
пока его задача не завершена отклоняется. Глобальные операции проекта не принимаются
| |
при других незавершённых задачах и на время своей работы блокируют новые команды
| |
терминалам.
| |
| |
```json
| |
{
| |
"id": "идентификатор",
| |
"folder": "MetaTrader5.5",
| |
"action": "create",
| |
"status": "queued",
| |
"stage": "Ожидание",
| |
"warnings": []
| |
}
| |
```
| |
| |
Состояния: `queued`, `running`, `done`, `error`. При ошибке добавляется `error`,
| |
у операций проекта — также `result` при наличии результата. В глобальных задачах
| |
`folder` — пустая строка. Задачи находятся в памяти; старые завершённые записи
| |
постепенно удаляются (сохраняется примерно 50 последних). Они не переживают
| |
перезапуск менеджера и не являются постоянным журналом.
| |
| |
## Маршруты
| |
| |
| Метод и путь | Назначение |
| |
|---|---|
| |
| `GET /` | Главная страница |
| |
| `GET /settings` | Настройки |
| |
| `POST /instances/{name}` | Текущее состояние указанного экземпляра |
| |
| `POST /start/{name}` | Запуск и проверка, 202 |
| |
| `POST /stop/{name}` | Остановка, 202 |
| |
| `POST /create/{name}` | Создание с именем в пути, 202; тело `AccountInput` необязательно |
| |
| `POST /api/terminals` | Создание, 202; имя можно предложить автоматически |
| |
| `DELETE /api/terminals/{name}` | Удаление остановленного экземпляра и его папки, 202 |
| |
| `PUT /api/terminals/{name}/account` | Сохранение настроек без запуска и авторизации, 202 |
| |
| `POST /api/terminals/{name}/test-connection` | Явная проверка реквизитов из тела запроса, без их сохранения, 202; без тела — проверка сохранённых |
| |
| `GET /api/jobs/{id}` | Состояние задачи; неизвестный id — 404 |
| |
| `GET /api/settings` | Общие параметры, записи счетов без паролей, файлы и предлагаемое имя |
| |
| `POST /api/settings/plan` | Предварительная проверка переноса, список папок/процессов и токен подтверждения |
| |
| `PUT /api/settings` | Сохранение общих настроек; перенос папок выполняется фоновой задачей с ответом 202 |
| |
| `PUT /api/files/{kind}` | Загрузка исходного файла как необработанного тела запроса |
| |
| `GET /api/project` | Локальные сведения Git, сборки, различий EX5 и автозапуска без сетевого fetch |
| |
| `POST /api/project/check` | Проверка удалённой ветки, 202 |
| |
| `POST /api/project/update` | Загрузка через fast-forward, 202 |
| |
| `POST /api/project/deploy` | Принудительная сборка/копирование сервиса, 202 |
| |
| |
`AccountInput` содержит `name`, `login`, `server`, `password`, `clear_account`.
| |
Для создания через `/api/terminals` к нему добавляются `folder` и `servers_dat`;
| |
пустое имя выбирается автоматически. Пример структуры запроса без счёта
| |
(Base64 в `servers_dat` нужно заменить содержимым своего файла):
| |
| |
```json
| |
{"folder": "MetaTrader5.5", "name": "Новый экземпляр", "servers_dat": "..."}
| |
```
| |
| |
`PUT /api/settings` принимает полный набор редактируемых общих полей:
| |
`mt5_folder`, `terminal_template`; `startup_timeout_sec` и `disk_warning_mb` могут
| |
передаваться дополнительно. Пропущенные дополнительные параметры не сбрасываются.
| |
Остальная конфигурация сохраняется. Это не универсальный PATCH произвольного JSON.
| |
| |
Перед изменением базовой папки интерфейс запрашивает `/api/settings/plan`.
| |
Если найдены папки экземпляров, сохранение требует `move_token` из плана;
| |
остановка запущенных терминалов дополнительно разрешается флагом `stop_running`.
| |
Перенос — глобальная задача: другие операции временно не принимаются, чтение
| |
состояния задачи остаётся доступным. JSON заменяется после перемещения всех папок.
| |
При переносе между дисками исходные данные сохраняются в резервных папках до
| |
записи JSON. При ошибке выполняется откат, при неполном откате сообщаются пути.
| |
Ответ настроек содержит `base_folder_lock` с причиной блокировки поля или пустой строкой.
| |
| |
Пути экземпляров вычисляются как `mt5_folder / ключ в terminals` общей функцией
| |
`instance_directory()`. В JSON у экземпляров нет собственного `path`; старое поле
| |
игнорируется при чтении. В ответах API поле `path` остаётся вычисляемым значением
| |
для отображения, а не настройкой расположения.
| |
| |
Загрузки EXE: `kind` равен `terminal` или `editor`. Используется бинарное тело
| |
с пределом 256 МиБ. Загрузка разрешена только для отсутствующего файла.
| |
При создании `POST /api/terminals` получает `servers_dat` в Base64 внутри JSON
| |
вместе с полями экземпляра. После декодирования предел — 16 МиБ; файл обязателен.
| |
Содержимое передаётся только фоновой задаче, не сохраняется в конфигурацию
| |
и не возвращается в ответах. Пустые файлы отклоняются, у EXE проверяется сигнатура MZ.
| |
Это не полная проверка содержимого исполняемого файла.
| |
| |
Ошибки входных типов возвращают 422 без исходного объекта и пароля; известные
| |
ошибки запуска задач/настроек — обычно 400. Ошибка уже принятой операции видна
| |
в объекте задачи при HTTP 200 на запрос её состояния. Интерактивная схема FastAPI
| |
доступна по `/docs`, OpenAPI — `/openapi.json`.
| |
| |
## Создание и авторизация
| |
| |
Новый экземпляр получает два EXE, `config/servers.dat`, сервис и `config/services.ini`
| |
с именем общей базы. В JSON он регистрируется до запуска. Ожидание сервиса проверяет
| |
свежесть, полный путь установки и при заданном счёте — логин, сервер и подключение.
| |
При неудаче удаляется только новая папка, принадлежащая этой операции, и её запись.
| |
| |
Для первого входа используются временный INI и `KeepPrivate=1` в основной
| |
конфигурации терминала. После успешного подключения главное окно закрывается
| |
через `WM_CLOSE`, временный файл удаляется, затем проверяется обычный запуск.
| |
Обновление существующего счёта не удаляет папку терминала при ошибке.
| |
| |
## Проверки разработки
| |
| |
```powershell
| |
python -m unittest discover -s tests -v
| |
```
| |
| |
`test_provisioning.py` использует временные папки и имитирует границу с MT5,
| |
проверяя выбор файлов, учётные записи, сохранение и откат. `test_http.py` поднимает
| |
изолированный сервер на свободном порту и проверяет маршруты и отсутствие паролей
| |
в ответах. `test_project_updates.py` работает с временным локальным Git-remote:
| |
проверяет fetch, fast-forward, защиту правок и распространение EX5 с имитацией ME.
| |
Сетевой репозиторий и рабочие терминалы пользователя тесты не меняют.
| |
| |
Для ручной проверки реального MT5 есть `tools/smoke_create_terminal.py`.
| |
Он создаёт отдельную тестовую копию и базу, затем удаляет собственные файлы.
| |
Инструмент привязан к локальной установке `C:\MT5\MetaTrader5.1` и пути общей базы
| |
из `config.json`; перед использованием проверьте эти значения. Вариант
| |
`--with-account` запрашивает реквизиты при запуске; логин и сервер можно передать
| |
через `--login` и `--server`, пароль вводится скрыто через `getpass` и не передаётся
| |
аргументом командной строки. Файл `tools/test_first_login.py` не используется.
| |
Это инструмент разработчика, а не шаг установки.
|