16 KiB
Руководство для 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_ПолучениеДанныхТестов. - В
OPI_ПолучениеДанныхТестовтакже находятся функции-проверки:- по одной функции-проверке на каждый атомарный тест
- с возможным ветвлением внутри по параметру
Вариант
Правила именования
- Формат имени атомарного теста:
<ИмяМодуляБезПрефикса>_<ИмяМетодаФункциональногоМодуля>
- Формат имени запускаемого теста:
<ЛюбоеСокращениеИмениМодуляБезПрефикса><ИмяОбласти>
- Формат имени функции-проверки:
Проверка_<ИмяАтомарногоТеста>
Схема нативных компонент (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.
Тесты (новая и существующая компонента)
OPIt_<Имя>: областиЗапускаемыеТесты/АтомарныеТестыпо правилам выше.- В запускаемый тест основных методов —
<Модуль>_ПолучитьНастройкиЛогирования,<Модуль>_ПолучитьЛог(по образцуOPIt_MSSQL). - Атомарные тесты с
//ENDдля документации; без выноса повторов в служебные процедуры. OPI_ПолучениеДанныхТестов: регистрация вПолучитьТаблицуТестов,Проверка_*(для логирования — веткиФайл,Память,КакСтрока).- Не править
OPItc_*вручную. - Количество атомарных тестов = количеству экспортных методов
OPI_*.
Серверы (отличие от клиентов)
- Логирование часто включается третьим аргументом
Start, а не отдельнымSetLoggerдо connect (см.tcp_server,http_server,ws_server). - Состояние — accept/handle в
common-server, неSession { sql client }. - BSL-тесты логирования — по тому же принципу, но вызов через
Запустить/ параметры старта.
Чеклист: новая компонента
- Создать
src/addins/<name>/сCargo.toml(зависимости из таблицы выше). - Сразу завести
lib.rs,addin.rs,backend.rs,worker.rs(+query.rsдля SQL). - Выбрать
SyncBackendThreadилиBackendThread(илиcommon-serverдля listen-сервера). - Заложить
SetLogger/GetLogsиlog!в connect/операциях. - Параллельно:
OPI_<Имя>,OPIt_<Имя>, проверки, шаблон вCommonTemplates, при необходимости — зеркалоOInt. cargo checkв каталоге add-in.
Чеклист: переработка старой компоненты
Те же шаги, что для новой, плюс:
- Разнести монолитный
lib.rs; убратьArc<Mutex<драйвер>>, заложитьArc<Mutex<State>>на FFI-оболочку (см. «Синхронизация FFI-оболочки»). - Перенести клиент в
Sessionworker-потока; поток — только ленивыйensure_thread. - Сохранить совместимость 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 |