mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2026-06-20 09:19:27 +02:00
196 lines
17 KiB
Markdown
196 lines
17 KiB
Markdown
# Руководство для AGENTS
|
|
|
|
## Каноничный исходный код
|
|
|
|
- Основная реализация библиотеки находится в `src/ru/BSL/OpenIntegrations`.
|
|
- Если поведение кода и тестов расходится, в первую очередь считать этот каталог источником истины.
|
|
- Английская версия кода, находящаяся в `src/en` не требует доработки и синхронизируется с русской версией автоматическими пайплайнами
|
|
|
|
## Каноничные тесты
|
|
|
|
- Основные BSL-тесты находятся в `src/ru/BSL/Tests`.
|
|
- При разборе бизнес-логики анализировать эти тесты
|
|
|
|
## Зеркало OneScript
|
|
|
|
- Зеркальные файлы OneScript находятся в `src/ru/OInt` (включая `src/ru/OInt/tests`).
|
|
- Использовать этот каталог для проверки CLI/runtime-паритета, но не как первый источник при разборе BSL-регрессий.
|
|
- Эти зеркала не требуют доработки. Все внесенные изменения будут затерты автоматическими процессами синхронизации 1С и OneScript версии (в пользу 1С версии из `src/ru/BSL`)
|
|
|
|
## Соглашения по тестовым модулям
|
|
|
|
- У каждого функционального модуля есть два связанных тестовых модуля с тем же базовым именем:
|
|
- основные тесты с префиксом `OPIt_`
|
|
- тесты CLI с префиксом `OPItc_`
|
|
- функциональные модули используют префикс `OPI_`
|
|
- Не редактировать модули `OPItc_` вручную: CLI-тесты генерируются автоматически в CI-пайплайне из модулей `OPIt_`.
|
|
- Каждый тестовый модуль должен содержать:
|
|
- область `ЗапускаемыеТесты` с процедурами-обертками
|
|
- область `АтомарныеТесты` с атомарными проверками
|
|
- Запускаемые тесты вызывают несколько атомарных.
|
|
- Количество атомарных тестов должно соответствовать количеству методов функционального модуля.
|
|
- Количество запускаемых тестов должно соответствовать количеству областей функционального модуля.
|
|
- Текст тестовых модулей используется для формирования примеров кода в документации
|
|
- Служебные комментарии `//SKIP` и `//END` используются для исключения частей кода теста при формировании примера для документации. `// SKIP` позволяет исключить конкретную строку внутри теста, `//END` - завершает запись примера. Весь служебный код, который идет после `//END` не попадает в пример кода для документации
|
|
- В каждом атомарном тесте должен быть **хотя бы один** вызов `OPI_ПолучениеДанныхТестов.Обработать` с **незаполненным** параметром `Вариант` (основной сценарий). Это **первый** такой вызов в процедуре, он размещается **до** `//END`; его результат попадает в онлайн-документацию как пример результата метода. Дополнительные варианты проверяются последующими вызовами `Обработать` с заполненным `Вариант` — они идут **после** `//END` и в пример документации не включаются
|
|
- При формировании атомарных тестов нельзя выносить повторяющийся код в служебные функции, так как это может привести к недопониманию при их использовании в качестве примеров для документации
|
|
- В спорных/неочевидных ситуациях ориентироваться на существующие тесты как на каноничные примеры.
|
|
|
|
## Реестр и функции проверок
|
|
|
|
- Каждый запускаемый тест должен быть указан в `ПолучитьТаблицуТестов` в модуле `OPI_ПолучениеДанныхТестов`.
|
|
- В `OPI_ПолучениеДанныхТестов` также находятся функции-проверки:
|
|
- по одной функции-проверке на каждый атомарный тест
|
|
- с возможным ветвлением внутри по параметру `Вариант`
|
|
- В `OPI_ПолучениеДанныхТестов` **нельзя** вызывать методы функциональных модулей библиотеки (`OPI_MessagePack`, `OPI_Lua`, `OPI_Telegram` и т.п.). Модуль проверок должен оставаться независимым от тестируемых API. Если для проверки нужны подготовленные данные (десериализация, round-trip, повторный вызов метода), это делается в атомарном тесте `OPIt_*` и передаётся в `Обработать` / `ОбработатьCLI` через дополнительные параметры (`Восстановленное`, `Исходное` и т.д.).
|
|
|
|
## Правила именования
|
|
|
|
- Формат имени атомарного теста:
|
|
- `<ИмяМодуляБезПрефикса>_<ИмяМетодаФункциональногоМодуля>`
|
|
- Формат имени запускаемого теста:
|
|
- `<ЛюбоеСокращениеИмениМодуляБезПрефикса><ИмяОбласти>`
|
|
- Формат имени функции-проверки:
|
|
- `Проверка_<ИмяАтомарногоТеста>`
|
|
|
|
## Схема нативных компонент (Rust add-in)
|
|
|
|
**Обязательный шаблон** для любой новой нативной компоненты и для переработки существующих. Не создавать add-in «с нуля» в монолитном `lib.rs` с `Arc<Mutex<…>>` — сразу закладывать структуру ниже.
|
|
|
|
Каноничные примеры: `src/addins/postgres`, `mysql`, `sqlite`, `mssql`, `mongodb`, `ftp`, `zeromq`; серверы — `tcp_server`, `http_server`, `ws_server`.
|
|
|
|
### Два уровня защиты (не путать)
|
|
|
|
| Уровень | Где | Что ловит |
|
|
|--------|-----|-----------|
|
|
| **FFI** | `common-core`: `call_as_func` → `catch_panic` | Паника в тонкой обёртке addin (JSON/Janx, маршрутизация) |
|
|
| **Backend** | `common-backend`: поток worker + `catch_panic` на цикл handler | Паника в драйвере; после фатала — `health`, следующие `call`/`send` → `Err` |
|
|
|
|
`catch_unwind` только на FFI **не заменяет** worker-поток: не решает `!Send` соединений (SQLite), гонки при параллельных вызовах из 1С, poisoned `Mutex` вокруг драйвера.
|
|
|
|
**Не защищает** ни один уровень: segfault/abort в C-библиотеке драйвера — падает весь процесс 1С. Изоляция только отдельным процессом (вне этой схемы).
|
|
|
|
### Синхронизация FFI-оболочки
|
|
|
|
Worker-поток сериализует работу с драйвером, но **не** защищает поля и флаги на стороне `AddIn`: `started`, `logger`, `datasets`, вызовы делегата в `backend`/`common-server`. Если платформа держит один экземпляр компоненты и вызывает методы **из разных потоков** (параллельные задания, внешний хостинг, общий кэш объекта), без mutex на оболочке возможны гонки — даже при корректном worker.
|
|
|
|
**Обязательно** в `addin.rs` (и в server-`wrapper.rs`, где есть обёртка):
|
|
|
|
- `Arc<Mutex<State>>` — backend-делегат, служебное состояние, logger; все FFI-методы через `common_utils::lock_unpoisoned`;
|
|
- для SQL с dataset — `datasets` внутри того же `State`, не отдельное поле на `AddIn` (в `lib.rs` — тонкие `datasets_*` на `AddIn`).
|
|
|
|
Свойства getset (`connection_string`, `server_address`, `address` и т.п.) допустимо оставить на `AddIn` **вне** mutex; методы, которые читают их вместе с `State`, берут lock и при необходимости клонируют строку до обращения к backend (см. `grpc` `connect`).
|
|
|
|
Это **не** отменяет запрет ниже: `Arc<Mutex<соединение/драйвер>>` на addin по-прежнему нельзя — драйвер только в worker/`Session`.
|
|
|
|
### Структура крейта (клиенты: БД, FTP, ZeroMQ и т.п.)
|
|
|
|
```
|
|
src/addins/<name>/src/
|
|
lib.rs — METHODS, get_params_amount, cal_func, impl_addin_exports
|
|
addin.rs — тонкий AddIn: FFI-методы, `Arc<Mutex<State>>` на оболочке, без Mutex вокруг драйвера
|
|
backend.rs — *Backend: настройки до connect, ленивый поток, SetLogger
|
|
worker.rs — WorkerCommand, Session, spawn_thread, вся работа с драйвером
|
|
query.rs — только если есть отдельная логика SQL/запросов (MSSQL, Postgres, …)
|
|
```
|
|
|
|
**Не использовать** в новом коде:
|
|
|
|
- `Arc<Mutex<Драйвер>>` на стороне addin;
|
|
- создание backend-потока в `new()` (только **лениво** при первом connect/операции — `ensure_thread`);
|
|
- дублирование логики connect/execute в `lib.rs`.
|
|
|
|
### Выбор транспорта backend
|
|
|
|
| Тип драйвера | Крейт | Поток | Примеры |
|
|
|--------------|-------|-------|---------|
|
|
| Синхронный API | `SyncBackendThread` | Обычный `std::thread`, без tokio | `postgres`, `mysql`, `sqlite`, `ftp` |
|
|
| Async / tokio внутри драйвера | `BackendThread` | Поток + `Runtime::new()` в worker | `mssql`, `mongodb`, `zeromq` |
|
|
| Долгоживущий сервер (listen/accept) | `common-server::Backend` | Внутри — `BackendThread` | `tcp_server`, `http_server`, `ws_server` |
|
|
|
|
`common-server` — тот же канал команд, но свой API (`send_command`, `handle_async_command`); не смешивать с паттерном `addin/backend/worker` без необходимости.
|
|
|
|
### Общие зависимости (`Cargo.toml`)
|
|
|
|
- `common-core` — макросы FFI, `catch_panic` на границе.
|
|
- `common-backend` — `BackendThread` / `SyncBackendThread`.
|
|
- `common-logs` — `Logger`, `log!`, `SetLogger` / `GetLogs` на FFI.
|
|
- `common-janx` — `JanxValue`, `janx!`, `FromJanx` / `IntoJanx` для бинарных полей и составных ответов.
|
|
- `common-tcp` — TLS, proxy, `create_tcp_connection` (FTP, БД с TLS).
|
|
- `common-dataset` — только где есть пакетные SQL/dataset (MSSQL).
|
|
|
|
### Паттерн `backend.rs`
|
|
|
|
- Поля: `thread: Option<…>`, настройки до connect (`tls`, `proxy`, строка подключения), `logger: Option<Arc<Logger>>`.
|
|
- `set_logger` / `set_tls` — **только до** установления соединения.
|
|
- `connect` → `ensure_thread()` → `thread.call(WorkerCommand::Connect { … })`.
|
|
- `close` / `Drop` → `shutdown(Some(WorkerCommand::Shutdown))`.
|
|
- `get_logs` — читать из `Logger` на стороне addin/backend (не из worker), если logger хранится в backend.
|
|
|
|
### Паттерн `worker.rs`
|
|
|
|
- `enum WorkerCommand` — одна варианта на операцию; ответы через `mpsc::Sender<Result<…>>` или `Sender<String>` для готового JSON.
|
|
- `struct Session` — `client`/`connection`, `logger`.
|
|
- `fn log(&self, …)` — `common_logs::log!(logger, …)`.
|
|
- `spawn_thread` — единственное место цикла `while let Ok(cmd) = rx.recv()`.
|
|
- Вся работа с `FtpStream` / `Client` / `Connection` — **только** внутри этого потока.
|
|
|
|
### FFI: логирование
|
|
|
|
Добавить в `METHODS` (перед `Version`):
|
|
|
|
- `SetLogger` — JSON-конфиг (`Logger::from_json`);
|
|
- `GetLogs` — `count`, ответ `{ result, logs, total, returned }`.
|
|
|
|
Порядок на стороне BSL (`OPI_*`): настройки → `SetLogger` (если передано `Логирование`) → connect/open.
|
|
|
|
### BSL (`OPI_<Имя>`)
|
|
|
|
В области основных методов:
|
|
|
|
- `ПолучитьНастройкиЛогирования` → делегат в `OPI_Компоненты.ПолучитьНастройкиЛогирования`;
|
|
- `ПолучитьЛог` → `OPI_Компоненты.ПолучитьЛог`;
|
|
- в `ОткрытьСоединение` (или аналог) — необязательный параметр `Логирование`, вызов `Коннектор.SetLogger` до `Connect`.
|
|
|
|
### Тесты (новая и существующая компонента)
|
|
|
|
1. `OPIt_<Имя>`: области `ЗапускаемыеТесты` / `АтомарныеТесты` по правилам выше.
|
|
2. В запускаемый тест основных методов — `<Модуль>_ПолучитьНастройкиЛогирования`, `<Модуль>_ПолучитьЛог` (по образцу `OPIt_MSSQL`).
|
|
3. Атомарные тесты с `//END` для документации; без выноса повторов в служебные процедуры.
|
|
4. `OPI_ПолучениеДанныхТестов`: регистрация в `ПолучитьТаблицуТестов`, `Проверка_*` (для логирования — ветки `Файл`, `Память`, `КакСтрока`).
|
|
5. Не править `OPItc_*` вручную.
|
|
6. Количество атомарных тестов = количеству экспортных методов `OPI_*`.
|
|
|
|
### Серверы (отличие от клиентов)
|
|
|
|
- Логирование часто включается **третьим аргументом `Start`**, а не отдельным `SetLogger` до connect (см. `tcp_server`, `http_server`, `ws_server`).
|
|
- Состояние — accept/handle в `common-server`, не `Session { sql client }`.
|
|
- BSL-тесты логирования — по тому же принципу, но вызов через `Запустить` / параметры старта.
|
|
|
|
### Чеклист: новая компонента
|
|
|
|
1. Создать `src/addins/<name>/` с `Cargo.toml` (зависимости из таблицы выше).
|
|
2. Сразу завести `lib.rs`, `addin.rs`, `backend.rs`, `worker.rs` (+ `query.rs` для SQL).
|
|
3. Выбрать `SyncBackendThread` или `BackendThread` (или `common-server` для listen-сервера).
|
|
4. Заложить `SetLogger` / `GetLogs` и `log!` в connect/операциях.
|
|
5. Параллельно: `OPI_<Имя>`, `OPIt_<Имя>`, проверки, шаблон в `CommonTemplates`, при необходимости — зеркало `OInt`.
|
|
6. `cargo check` в каталоге add-in.
|
|
|
|
### Чеклист: переработка старой компоненты
|
|
|
|
Те же шаги, что для новой, плюс:
|
|
|
|
1. Разнести монолитный `lib.rs`; убрать `Arc<Mutex<драйвер>>`, заложить `Arc<Mutex<State>>` на FFI-оболочку (см. «Синхронизация FFI-оболочки»).
|
|
2. Перенести клиент в `Session` worker-потока; поток — только ленивый `ensure_thread`.
|
|
3. **Сохранить** совместимость FFI: номера/имена методов, JSON-поля, намеренные побочные эффекты (например задержки в `cal_func`).
|
|
|
|
### Эталоны для копирования
|
|
|
|
| Задача | Смотреть |
|
|
|--------|----------|
|
|
| Новая sync-клиент + SQL | `src/addins/postgres` |
|
|
| Новая sync-клиент без SQL | `src/addins/ftp` |
|
|
| Новая async-клиент | `src/addins/mssql`, `mongodb` |
|
|
| BSL + тесты с нуля | `OPI_PostgreSQL`, `OPIt_MSSQL` |
|
|
| Новый сервер | `src/addins/tcp_server` + `commons/common-server` |
|