# Устройство приложения и 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; имя можно предложить автоматически | | `PUT /api/terminals/{name}/account` | Сохранение/применение реквизитов, 202 | | `GET /api/jobs/{id}` | Состояние задачи; неизвестный id — 404 | | `GET /api/settings` | Общие параметры, записи счетов без паролей, файлы и предлагаемое имя | | `PUT /api/settings` | Сохранение общих настроек | | `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`; пустое значение выбирает свободное имя автоматически. Пример без счёта: ```json {"folder": "MetaTrader5.5", "name": "Новый экземпляр"} ``` `PUT /api/settings` принимает полный набор редактируемых общих полей: `mt5_folder`, `terminal_template`, `mt5_installation`, `service_ex5`, `startup_timeout_sec`, `disk_warning_mb`. Остальная конфигурация сохраняется. Это не универсальный PATCH произвольного JSON. Пути экземпляров вычисляются как `mt5_folder / ключ в terminals` общей функцией `instance_directory()`. В JSON у экземпляров нет собственного `path`; старое поле игнорируется при чтении. В ответах API поле `path` остаётся вычисляемым значением для отображения, а не настройкой расположения. Загрузки: `kind` равен `terminal`, `editor`, `servers` или `service`. Используется бинарное тело, не multipart; предел для `servers` — 16 МиБ, для остальных — 256 МиБ. Пустые файлы отклоняются, у 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` не используется. Это инструмент разработчика, а не шаг установки.