1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2026-06-20 09:19:27 +02:00
Files
OpenIntegrations/AGENTS.md
T
2026-06-03 10:32:54 +03:00

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_funccatch_panic Паника в тонкой обёртке addin (JSON/Janx, маршрутизация)
Backend common-backend: поток worker + catch_panic на цикл handler Паника в драйвере; после фатала — health, следующие call/sendErr

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, не отдельное поле на AddInlib.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-backendBackendThread / SyncBackendThread.
  • common-logsLogger, log!, SetLogger / GetLogs на FFI.
  • common-janxJanxValue, 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только до установления соединения.
  • connectensure_thread()thread.call(WorkerCommand::Connect { … }).
  • close / Dropshutdown(Some(WorkerCommand::Shutdown)).
  • get_logs — читать из Logger на стороне addin/backend (не из worker), если logger хранится в backend.

Паттерн worker.rs

  • enum WorkerCommand — одна варианта на операцию; ответы через mpsc::Sender<Result<…>> или Sender<String> для готового JSON.
  • struct Sessionclient/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);
  • GetLogscount, ответ { 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