9737c787f9
Инфраструктура 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>
141 lines
3.9 KiB
Go
141 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// WizardStage — какой странице wizard'а соответствует текущее состояние.
|
|
// Переходы: welcome → precheck → config → installing → done.
|
|
// Из любого можно вернуться в welcome (полный reset).
|
|
type WizardStage string
|
|
|
|
const (
|
|
StageWelcome WizardStage = "welcome"
|
|
StagePrecheck WizardStage = "precheck"
|
|
StageConfig WizardStage = "config"
|
|
StageInstalling WizardStage = "installing"
|
|
StageDone WizardStage = "done"
|
|
StageError WizardStage = "error"
|
|
)
|
|
|
|
// Config — данные, которые wizard собирает на стадии config.
|
|
type Config struct {
|
|
OrgINN string `json:"orgInn"` // ИНН организации
|
|
OrgName string `json:"orgName"` // отображаемое имя
|
|
AdminEmail string `json:"adminEmail"` // куда писать алерты
|
|
LicenseKey string `json:"licenseKey"` // годовой ключ (опционально, можно пропустить)
|
|
}
|
|
|
|
// StepStatus — текущее состояние конкретного шага установки.
|
|
type StepStatus string
|
|
|
|
const (
|
|
StepPending StepStatus = "pending"
|
|
StepRunning StepStatus = "running"
|
|
StepDone StepStatus = "done"
|
|
StepSkipped StepStatus = "skipped"
|
|
StepFailed StepStatus = "failed"
|
|
)
|
|
|
|
// StepState — снимок одного шага для отдачи в UI.
|
|
type StepState struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
Status StepStatus `json:"status"`
|
|
Message string `json:"message,omitempty"`
|
|
Started *time.Time `json:"started,omitempty"`
|
|
Finished *time.Time `json:"finished,omitempty"`
|
|
}
|
|
|
|
// PrecheckResult — результат одной системной проверки на стадии precheck.
|
|
type PrecheckResult struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
OK bool `json:"ok"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
// State — потокобезопасное состояние wizard'а. Хранит всё что нужно
|
|
// отрисовать на любой из страниц + текущий прогресс установки.
|
|
type State struct {
|
|
mu sync.RWMutex
|
|
|
|
artifactsDir string
|
|
|
|
Stage WizardStage `json:"stage"`
|
|
ErrorMsg string `json:"errorMsg,omitempty"`
|
|
Precheck []PrecheckResult `json:"precheck"`
|
|
Config Config `json:"config"`
|
|
Steps []StepState `json:"steps"`
|
|
|
|
bus *eventBus
|
|
}
|
|
|
|
func newState(artifactsDir string) *State {
|
|
return &State{
|
|
artifactsDir: artifactsDir,
|
|
Stage: StageWelcome,
|
|
Steps: buildStepList(),
|
|
bus: newEventBus(),
|
|
}
|
|
}
|
|
|
|
// Snapshot — потокобезопасная копия для GET /api/state.
|
|
func (s *State) Snapshot() State {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
cp := *s
|
|
cp.Precheck = append([]PrecheckResult(nil), s.Precheck...)
|
|
cp.Steps = append([]StepState(nil), s.Steps...)
|
|
return cp
|
|
}
|
|
|
|
func (s *State) setStage(st WizardStage) {
|
|
s.mu.Lock()
|
|
s.Stage = st
|
|
s.mu.Unlock()
|
|
s.bus.publish(event{Type: "stage", Data: mustJSON(map[string]string{"stage": string(st)})})
|
|
}
|
|
|
|
func (s *State) setError(msg string) {
|
|
s.mu.Lock()
|
|
s.Stage = StageError
|
|
s.ErrorMsg = msg
|
|
s.mu.Unlock()
|
|
s.bus.publish(event{Type: "error", Data: mustJSON(map[string]string{"message": msg})})
|
|
}
|
|
|
|
func (s *State) setPrecheck(items []PrecheckResult) {
|
|
s.mu.Lock()
|
|
s.Precheck = items
|
|
s.mu.Unlock()
|
|
s.bus.publish(event{Type: "precheck", Data: mustJSON(items)})
|
|
}
|
|
|
|
func (s *State) setConfig(c Config) {
|
|
s.mu.Lock()
|
|
s.Config = c
|
|
s.mu.Unlock()
|
|
}
|
|
|
|
func (s *State) updateStep(id string, fn func(*StepState)) {
|
|
s.mu.Lock()
|
|
var snap StepState
|
|
for i := range s.Steps {
|
|
if s.Steps[i].ID == id {
|
|
fn(&s.Steps[i])
|
|
snap = s.Steps[i]
|
|
break
|
|
}
|
|
}
|
|
s.mu.Unlock()
|
|
s.bus.publish(event{Type: "step", Data: mustJSON(snap)})
|
|
}
|
|
|
|
func mustJSON(v any) string {
|
|
b, _ := json.Marshal(v)
|
|
return string(b)
|
|
}
|