4adc1398f6
- шаг «База bj»: перенос на сервер PostgreSQL организации (проверка подключения, версии, прав, пустой базы; pg_dump → psql; сверка числа строк по таблицам; переключение и перезапуск); прежняя база — запасная копия; резервные копии: дамп внешней базы по её подключению, восстановление её не трогает - все формы: пустые видимые обязательные поля называются по имени и подсвечиваются; DEPO — и на сервере - «Обновить/Создать канал»: в фоне bj, ход по этапам с таймером (и после перезагрузки страницы), переходы заблокированы до конца, в конце проверка, что шлюз загрузил канал; состояние ИШ во время записи — без очереди к root-обработчику (страница больше не висит на «Проверяю…») Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
154 lines
5.5 KiB
Go
154 lines
5.5 KiB
Go
package lkgateway
|
|
|
|
// Запись канала контура НРД в ИШ (06.10.2026). Root-обработчик пишет канал в базу ИШ и перезапускает шлюз — до
|
|
// двух минут. Раньше это делал сам запрос страницы: перезагрузка страницы прерывала ожидание, а запрос
|
|
// состояния ИШ вставал в очередь за записью канала — страница висела на «Проверяю…» без объяснений, и человек
|
|
// мог уйти «Далее» посреди перезапуска. Теперь запись идёт в фоне bj, страница показывает её ход (и после
|
|
// перезагрузки), а в конце bj проверяет, что шлюз действительно загрузил канал.
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter"
|
|
)
|
|
|
|
// igateContourView — ход записи канала для страницы.
|
|
type igateContourView struct {
|
|
Running bool `json:"running"`
|
|
Contour string `json:"contour,omitempty"`
|
|
Stage string `json:"stage,omitempty"` // write | engine | channel | done
|
|
Started int64 `json:"started,omitempty"`
|
|
Done bool `json:"done,omitempty"`
|
|
OK bool `json:"ok"`
|
|
Msg string `json:"msg,omitempty"`
|
|
At int64 `json:"at,omitempty"`
|
|
}
|
|
|
|
type igateContourState struct {
|
|
sync.Mutex
|
|
v igateContourView
|
|
}
|
|
|
|
var igateContourJob igateContourState
|
|
|
|
func (j *igateContourState) start(contour string) bool {
|
|
j.Lock()
|
|
defer j.Unlock()
|
|
if j.v.Running {
|
|
return false
|
|
}
|
|
j.v = igateContourView{Running: true, Contour: contour, Stage: "write", Started: time.Now().Unix(), OK: true}
|
|
return true
|
|
}
|
|
|
|
func (j *igateContourState) stage(st string) {
|
|
j.Lock()
|
|
j.v.Stage = st
|
|
j.Unlock()
|
|
}
|
|
|
|
func (j *igateContourState) finish(ok bool, msg string) {
|
|
j.Lock()
|
|
j.v.Running, j.v.Done, j.v.OK, j.v.Msg, j.v.Stage, j.v.At = false, true, ok, msg, "done", time.Now().Unix()
|
|
j.Unlock()
|
|
}
|
|
|
|
func (j *igateContourState) view() igateContourView {
|
|
j.Lock()
|
|
defer j.Unlock()
|
|
v := j.v
|
|
if v.Done && time.Since(time.Unix(v.At, 0)) > 15*time.Minute {
|
|
return igateContourView{OK: true} // итог давний — не показываем
|
|
}
|
|
return v
|
|
}
|
|
|
|
// igateLastStatus — последнее состояние ИШ от root-обработчика (отдаётся, пока он занят записью канала).
|
|
var igateLastStatus lastStatus
|
|
|
|
type lastStatus struct {
|
|
sync.Mutex
|
|
m map[string]any
|
|
}
|
|
|
|
func (l *lastStatus) set(m map[string]any) {
|
|
l.Lock()
|
|
l.m = m
|
|
l.Unlock()
|
|
}
|
|
|
|
func (l *lastStatus) get() map[string]any {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
if l.m == nil {
|
|
return nil
|
|
}
|
|
out := map[string]any{}
|
|
for k, v := range l.m {
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|
|
|
|
// igateContourRun — запись канала контура в ИШ и проверка, что шлюз его загрузил (в фоне, без запроса страницы).
|
|
func igateContourRun(rc *RuntimeConfig, contour, crypto, dep string) {
|
|
extra := `{"contour":"` + contour + `","crypto":"` + crypto + `","deponent":"` + dep + `"}`
|
|
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
|
defer cancel()
|
|
go func() { // этап «перезапуск ИШ» — root-обработчик пишет канал за секунды и дальше ждёт движок
|
|
time.Sleep(4 * time.Second)
|
|
if v := igateContourJob.view(); v.Running && v.Stage == "write" {
|
|
igateContourJob.stage("engine")
|
|
}
|
|
}()
|
|
res, err := runKeymediaOp(ctx, "igate-contour", map[string]string{"extra": extra})
|
|
if err != nil || res["ok"] != true {
|
|
msg := errStr(err)
|
|
if e, ok := res["error"].(string); ok && e != "" {
|
|
msg = e
|
|
}
|
|
igateContourJob.finish(false, msg)
|
|
return
|
|
}
|
|
out := asString(res["output"])
|
|
code := strings.ToUpper(contour) + dep
|
|
if prof, err := nsdadapter.LookupProfile(contour + "-" + crypto); err == nil {
|
|
code = prof.Channel + dep
|
|
}
|
|
enabled := strings.Contains(out, "включён")
|
|
if enabled { // канал с ключом: шлюз должен его загрузить — иначе любой обмен даёт HTTP 500
|
|
igateContourJob.stage("channel")
|
|
base := pickStr(rc.Snapshot().NSD.IGWBaseURL, igateDefaultURL)
|
|
loaded := false
|
|
for i := 0; i < 20 && !loaded; i++ {
|
|
if found, en, err := igateChannelState(ctx, base, code); err == nil && found && en {
|
|
loaded = true
|
|
break
|
|
}
|
|
time.Sleep(3 * time.Second)
|
|
}
|
|
if !loaded {
|
|
igateContourJob.finish(false, "канал "+code+" записан, но шлюз его не загрузил — журнал ИШ: /var/lib/igate/.local/share/NSD Integration Gateway/logs-svc/log.txt")
|
|
return
|
|
}
|
|
out += "; шлюз загрузил канал " + code
|
|
}
|
|
if rc.Snapshot().NSD.Profile == "" {
|
|
// контур в bj ещё не выбран (новая установка) — первый настроенный канал и есть рабочий
|
|
n := rc.Snapshot().NSD
|
|
n.Profile, n.IGWBaseURL = contour+"-"+crypto, pickStr(n.IGWBaseURL, igateDefaultURL)
|
|
if rc.UpdateNSD(n) == nil {
|
|
out += ". bj работает с этим контуром и перезапускается — страница обновится сама"
|
|
go func() {
|
|
time.Sleep(3 * time.Second)
|
|
_, _ = restartUnit(context.Background(), "bj-server")
|
|
}()
|
|
}
|
|
}
|
|
refreshCertStore(rc)
|
|
igateContourJob.finish(true, out)
|
|
}
|