package lkgateway import ( "context" "errors" "net" "net/http" "os" "time" ) // Status — состояние одной проверяемой подсистемы. type Status struct { Name string `json:"name"` OK bool `json:"ok"` Message string `json:"message,omitempty"` Detail string `json:"detail,omitempty"` } // SystemStatus — все проверки. type SystemStatus struct { Profile string `json:"profile"` Provider string `json:"crypto_provider"` Checks []Status `json:"checks"` CheckedAt time.Time `json:"checked_at"` } // CheckOptions — что и как проверять. type CheckOptions struct { PostgresDSN string // если пусто — режим in-memory, проверки нет CryptoSocket string // путь до UDS crypto-service NSDAdapterURL string // например http://127.0.0.1:8082 LKCallbackURL string // куда шлём callback (lk-emulator) Profile string // имя профиля nsdadapter (guest-gost...) CryptoProvider string // BJ_CRYPTO_PROVIDER (stub|cryptopro|...) Timeout time.Duration // таймаут на одну проверку } // CheckAll выполняет все доступные проверки и возвращает SystemStatus. func CheckAll(ctx context.Context, o CheckOptions) SystemStatus { if o.Timeout == 0 { o.Timeout = 2 * time.Second } out := SystemStatus{ Profile: o.Profile, Provider: o.CryptoProvider, CheckedAt: time.Now().UTC(), } out.Checks = append(out.Checks, checkPostgres(ctx, o)) out.Checks = append(out.Checks, checkCryptoSocket(o)) out.Checks = append(out.Checks, checkNSDAdapter(ctx, o)) out.Checks = append(out.Checks, checkLKCallback(ctx, o)) return out } func checkPostgres(_ context.Context, o CheckOptions) Status { s := Status{Name: "postgres"} if o.PostgresDSN == "" { s.OK = true s.Message = "in-memory (PostgresDSN не задан, репозиторий — m2mcore.MemoryRepository)" return s } // На M2 здесь будет sql.Open + Ping. На текущем шаге — заглушка. s.OK = false s.Message = "PostgreSQL Repository не подключён (требуется pgx, M2-шаг-3)" s.Detail = "DSN: " + o.PostgresDSN return s } func checkCryptoSocket(o CheckOptions) Status { s := Status{Name: "crypto-service (UDS)"} if o.CryptoSocket == "" { s.OK = false s.Message = "BJ_CRYPTO_SOCKET не задан" return s } info, err := os.Stat(o.CryptoSocket) if err != nil { s.OK = false s.Message = "сокет недоступен" s.Detail = err.Error() return s } if info.Mode()&os.ModeSocket == 0 { s.OK = false s.Message = "путь существует, но это не сокет" s.Detail = o.CryptoSocket return s } // Пробуем подключиться. d := net.Dialer{Timeout: o.Timeout} conn, err := d.Dial("unix", o.CryptoSocket) if err != nil { s.OK = false s.Message = "сокет существует, но не отвечает" s.Detail = err.Error() return s } _ = conn.Close() s.OK = true s.Message = "сокет открыт" s.Detail = o.CryptoSocket if o.CryptoProvider == "stub" || o.CryptoProvider == "" { s.Message += ", провайдер stub (реальная криптография не подключена)" } else { s.Message += ", провайдер " + o.CryptoProvider } return s } func checkNSDAdapter(ctx context.Context, o CheckOptions) Status { s := Status{Name: "nsd-adapter (REST к ИШ)"} if o.NSDAdapterURL == "" { s.OK = true s.Message = "BJ_NSD_ADAPTER_URL не задан — используется mock NSDSender" return s } return httpHealth(ctx, o.NSDAdapterURL+"/healthz", o.Timeout, s) } func checkLKCallback(ctx context.Context, o CheckOptions) Status { s := Status{Name: "lk-emulator (callback)"} if o.LKCallbackURL == "" { s.OK = false s.Message = "BJ_LK_CALLBACK_URL не задан — callback'и в ЛК отключены" return s } return httpHealth(ctx, o.LKCallbackURL+"/healthz", o.Timeout, s) } func httpHealth(ctx context.Context, url string, timeout time.Duration, s Status) Status { c := &http.Client{Timeout: timeout} req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { s.OK = false s.Message = "не получилось собрать запрос" s.Detail = err.Error() return s } resp, err := c.Do(req) if err != nil { s.OK = false s.Message = "недоступен" s.Detail = err.Error() return s } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { s.OK = false s.Message = "HTTP " + http.StatusText(resp.StatusCode) s.Detail = url return s } s.OK = true s.Message = "OK" s.Detail = url return s } // ErrUnknown — общий placeholder. var ErrUnknown = errors.New("lkgateway: unknown error")