package lkgateway // Шаги настройки — одни и те же для мастера и дашборда: дашборд пишет «Требуется настройка — N из M» // ровно по шагам мастера (с учётом лицензии), а не по отдельному списку проверок. import ( "context" "sync" "sync/atomic" "time" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/cryptocli" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter" ) type SetupStep struct { Step int Title string Done bool } var setupProbeCache = struct { sync.Mutex at time.Time validata string certs int }{} // setupProbes — версия Валидаты и число сертификатов (внешние вызовы) с кэшем на минуту. func setupProbes(rc *RuntimeConfig) (string, int) { setupProbeCache.Lock() defer setupProbeCache.Unlock() if time.Since(setupProbeCache.at) < time.Minute { return setupProbeCache.validata, setupProbeCache.certs } ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second) defer cancel() setupProbeCache.validata, _, _ = validataVersion(ctx) setupProbeCache.certs = len(ownValidCerts(storeCertsForUI(rc.Snapshot()))) setupProbeCache.at = time.Now() return setupProbeCache.validata, setupProbeCache.certs } // keyWizInstalled — мастер ключа дошёл до конца в этом запуске bj (ключ подключён, подпись подтверждена). // Сверка справочника шлюза асинхронная и отстаёт; по этой отметке шаг «Ключ подписи» выполнен сразу — // и в мастере, и в плашке на главной. var keyWizInstalled atomic.Bool // setupSteps — шаги мастера этой установки и выполнены ли они: ровно тот путь и те же // правила, что в мастере (wizPath + wizDone), чтобы плашка на главной не расходилась с ним. func setupSteps(rc *RuntimeConfig) []SetupStep { validata, certs := setupProbes(rc) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() done := wizDone(ctx, rc, validata, certs > 0 || keyWizInstalled.Load()) path, _ := wizPath(rc, done, 0) var steps []SetupStep for _, n := range path { steps = append(steps, SetupStep{n, wizStepTitles[n], done[n]}) } return steps } // ownValidCerts — свои сертификаты (с закрытым ключом), срок которых не истёк: только они делают шаг // «Сертификаты» выполненным (сертификаты НРД и УЦ в хранилище есть и без ключа организации). func ownValidCerts(certs []cryptocli.Certificate) []cryptocli.Certificate { var out []cryptocli.Certificate now := time.Now() for _, c := range certs { if c.HasPrivateKey && (c.NotAfter.IsZero() || c.NotAfter.After(now)) { out = append(out, c) } } return out } // doneOrg — организация и её депозитарные реквизиты в НРД заданы (без них перевод не сформировать). func doneOrg(s Settings) bool { return orgCode(s) != "" && orgINN(s) != "" && s.NSD.DeponentCode != "" && s.NSD.AccountID != "" && s.NSD.SectionID != "" } // doneQuik — подключение к МНП проверено и ключевые объекты M2M видны. func doneQuik(s Settings) bool { return s.Quik.Verified && s.Quik.M2MMissing == "" } // doneNSD — адрес ИШ задан и профиль известен bj (неизвестный профиль — молча режим имитации). func doneNSD(s Settings) bool { if s.NSD.IGWBaseURL == "" || s.NSD.Profile == "" { return false } _, err := nsdadapter.LookupProfile(s.NSD.Profile) return err == nil } // doneAlerts — оповещения уходят наружу (почта или Zabbix) и резервные копии включены. func doneAlerts(s Settings) bool { smtp := s.Alerts.SMTP return ((smtp.Enabled && smtp.Host != "" && smtp.To != "") || s.Alerts.Zabbix.Enabled) && s.Backup.Enabled }