feat: живой цикл M2M с НРД + мастер установки ключа на флешку
Инфраструктура M2M (живой обмен с НРД через ИШ): - обработка M2MTransferResponse: ERROR(M2Mxx) → заявка Отклонена, сохранение ответа; INFO → ждём Decision; идемпотентность поллера - fallback-корреляция ответов с нулевым GUID (M2M14/M2M17) по FIFO - сырой XML ответа НРД в карточке заявки (для пересылки в ТП) - тестовый пакет роботу приведён к эталону m2m_robot_samples (CostInfo=Yes, 4 бумаги, IsolationStatus, DocumentSeries=сценарий); override паспорта - редирект из теста сразу в карточку заявки Мастер установки ключа Валидаты на флешку (admin/setup/keywizard): - пошаговый: загрузка .7z+пароль → выбор флешки → запись → справочник сертификатов (CRL) → перезапуск+проверка ИШ → готово - привилегированный воркер (bj-keymedia) в host-namespace через файл-обмен, bj-server остаётся в песочнице - сохранение структуры профиля архива (spr<N>), перечисление съёмных USB Прочее: - пакет-доказательство для ТП НРД + форма регистрации участника M2M - эталонные образцы робота (DOC/m2m_robot_samples) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@@ -15,6 +17,9 @@ type Status struct {
|
||||
OK bool `json:"ok"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
// Optional — компонент не обязателен для работы с НРД. Его «не-OK»
|
||||
// не делает систему «не готовой» (напр. callback в ЛК).
|
||||
Optional bool `json:"optional,omitempty"`
|
||||
}
|
||||
|
||||
// SystemStatus — все проверки.
|
||||
@@ -55,17 +60,30 @@ func CheckAll(ctx context.Context, o CheckOptions) SystemStatus {
|
||||
return out
|
||||
}
|
||||
|
||||
func checkPostgres(_ context.Context, o CheckOptions) Status {
|
||||
s := Status{Name: "postgres"}
|
||||
func checkPostgres(ctx context.Context, o CheckOptions) Status {
|
||||
s := Status{Name: "База данных PostgreSQL"}
|
||||
if o.PostgresDSN == "" {
|
||||
s.OK = true
|
||||
s.Message = "in-memory (PostgresDSN не задан, репозиторий — m2mcore.MemoryRepository)"
|
||||
s.Optional = true
|
||||
s.Message = "in-memory — данные не сохраняются между перезапусками"
|
||||
return s
|
||||
}
|
||||
// На M2 здесь будет sql.Open + Ping. На текущем шаге — заглушка.
|
||||
s.OK = false
|
||||
s.Message = "PostgreSQL Repository не подключён (требуется pgx, M2-шаг-3)"
|
||||
s.Detail = "DSN: " + o.PostgresDSN
|
||||
pctx, cancel := context.WithTimeout(ctx, o.Timeout)
|
||||
defer cancel()
|
||||
pool, err := pgxpool.New(pctx, o.PostgresDSN)
|
||||
if err != nil {
|
||||
s.OK = false
|
||||
s.Message = "ошибка подключения: " + err.Error()
|
||||
return s
|
||||
}
|
||||
defer pool.Close()
|
||||
if err := pool.Ping(pctx); err != nil {
|
||||
s.OK = false
|
||||
s.Message = "не отвечает: " + err.Error()
|
||||
return s
|
||||
}
|
||||
s.OK = true
|
||||
s.Message = "подключена, репозиторий m2m_core.deals"
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -111,20 +129,27 @@ func checkCryptoSocket(o CheckOptions) Status {
|
||||
}
|
||||
|
||||
func checkNSDAdapter(ctx context.Context, o CheckOptions) Status {
|
||||
s := Status{Name: "nsd-adapter (REST к ИШ)"}
|
||||
s := Status{Name: "Интеграционный шлюз НРД"}
|
||||
if o.NSDAdapterURL == "" {
|
||||
s.OK = true
|
||||
s.Message = "BJ_NSD_ADAPTER_URL не задан — используется mock NSDSender"
|
||||
s.Optional = true
|
||||
s.Message = "не подключён — режим эмуляции (mock)"
|
||||
return s
|
||||
}
|
||||
return httpHealth(ctx, o.NSDAdapterURL+"/healthz", o.Timeout, s)
|
||||
// У ИШ нет /healthz — проверяем рабочий эндпоинт Web API (engine/state
|
||||
// отвечает 200 «Running», когда движок поднят).
|
||||
st := httpHealth(ctx, o.NSDAdapterURL+"/api/admin/engine/state", o.Timeout, s)
|
||||
if st.OK {
|
||||
st.Message = "подключён, движок работает"
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func checkLKCallback(ctx context.Context, o CheckOptions) Status {
|
||||
s := Status{Name: "lk-emulator (callback)"}
|
||||
s := Status{Name: "Callback в личный кабинет", Optional: true}
|
||||
if o.LKCallbackURL == "" {
|
||||
s.OK = false
|
||||
s.Message = "BJ_LK_CALLBACK_URL не задан — callback'и в ЛК отключены"
|
||||
s.Message = "не настроен — уведомления в ЛК отключены (необязательно для работы с НРД)"
|
||||
return s
|
||||
}
|
||||
return httpHealth(ctx, o.LKCallbackURL+"/healthz", o.Timeout, s)
|
||||
|
||||
Reference in New Issue
Block a user