Files
Bridge-and-Join-s/internal/lkgateway/updprogress.go
T
fontvielle c9ab60130f ИШ: этапы обновления шлюза в окне обновления bj, проверка нового ИШ, свежая версия в строке НРД
- окно обновления bj после перезапуска ведёт обновление ИШ по этапам (загрузка, остановка,
  резервная копия, установка, запуск, проверка) и закрывается только после проверки;
  пока шлюз обновляется, то же окно на любой странице
- bj-igate-admin: этапы stop/backup/verify; после запуска сверяются версия, служба, движок,
  каналы и ключ с прежними (иначе автооткат), обмен с НРД
- версия ИШ в строке НРД читается всегда заново (кэш 6 ч — только сайт НРД);
  после установки версии пересобираются сразу

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
2026-10-21 22:50:43 +03:00

123 lines
4.0 KiB
Go

package lkgateway
// Ход обновления для окна с индикатором на странице: этапы (проверка, скачивание, установка,
// перезапуск) и байты скачанного. Страница опрашивает GET /admin/setup/update/progress; когда
// обновляется ядро, bj-server перезапускается — страница видит обрыв связи, ждёт и сверяет
// версию работающего ядра с целевой.
import (
"encoding/json"
"net/http"
"os"
"path/filepath"
"sync"
"time"
)
type updateProgressState struct {
Seq int64 `json:"seq"`
Active bool `json:"active"`
Finished bool `json:"finished"`
Step int `json:"step"`
Steps int `json:"steps"`
Stage string `json:"stage"`
Done int64 `json:"done"`
Total int64 `json:"total"`
Target string `json:"target,omitempty"` // версия ядра после обновления (если ядро обновляется)
Result string `json:"result,omitempty"`
Note string `json:"note,omitempty"` // пояснение, которое нужно показать и после перезапуска ядра
Err string `json:"error,omitempty"`
Started time.Time `json:"started"`
Version string `json:"version"` // версия работающего bj-server
IgateTo string `json:"igate_to,omitempty"` // bj сам обновит ИШ до этой версии (ещё не обновил)
Igate map[string]any `json:"igate,omitempty"` // ход установки ИШ (как /admin/setup/igate/install-status)
Up int `json:"up"` // секунд с запуска bj-server
}
var procStarted = time.Now()
var updProg = struct {
sync.Mutex
s updateProgressState
}{}
func progressBegin(steps int) {
updProg.Lock()
defer updProg.Unlock()
updProg.s = updateProgressState{Seq: updProg.s.Seq + 1, Active: true, Steps: steps, Started: time.Now()}
}
func progressStage(step int, stage string) {
updProg.Lock()
defer updProg.Unlock()
updProg.s.Step, updProg.s.Stage = step, stage
}
func progressBytes(done, total int64) {
updProg.Lock()
defer updProg.Unlock()
updProg.s.Done, updProg.s.Total = done, total
}
func progressTarget(v string) {
updProg.Lock()
defer updProg.Unlock()
updProg.s.Target = v
}
func progressNote(n string) {
updProg.Lock()
defer updProg.Unlock()
updProg.s.Note = n
}
func progressEnd(result string, err error) {
updProg.Lock()
defer updProg.Unlock()
updProg.s.Active, updProg.s.Finished, updProg.s.Result = false, true, result
if err != nil {
updProg.s.Err = err.Error()
}
}
// progressWatchDir — пока идёт скачивание, раз в полсекунды считает байты в каталоге подготовки.
// Возвращает функцию остановки.
func progressWatchDir(dir string, total int64) func() {
stop := make(chan struct{})
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
t := time.NewTicker(500 * time.Millisecond)
defer t.Stop()
for {
var n int64
_ = filepath.Walk(dir, func(_ string, fi os.FileInfo, err error) error {
if err == nil && fi.Mode().IsRegular() {
n += fi.Size()
}
return nil
})
progressBytes(n, total)
select {
case <-stop:
return
case <-t.C:
}
}
}()
return func() { close(stop); wg.Wait(); progressBytes(total, total) }
}
// updateProgressHandler — GET /admin/setup/update/progress.
func (h *setupHandlers) updateProgress(w http.ResponseWriter, r *http.Request) {
updProg.Lock()
s := updProg.s
updProg.Unlock()
s.Version = BuildVersion
s.IgateTo, s.Igate, s.Up = igatePendingUpgrade(), igateInstallStatusJSON(h.rc), int(time.Since(procStarted).Seconds())
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-store")
_ = json.NewEncoder(w).Encode(s)
}