Обновления: кнопка «Обновить» показывает настоящий результат, устаревшие данные не предлагаются

Жалоба со стенда: в «Обновлениях» висит ЛК 0.2.0, нажимаешь «Обновить» —
ничего не происходит. На деле обновление уходило в фон и падало («манифест
HTTP 404: релизов в канале нет» — стенд на канале stable, релизы выкладываются
в beta), а отказ оседал в незаметной строке «Последняя проверка».

- Модули обновляются на месте и во flash показывается фактический результат;
  в фон уходит только обновление ядра, где ответа установщика всё равно не
  дождаться (bj-server перезапускается раньше).
- Строка результата при отказе показывается предупреждением, а не серым текстом.
- Если последняя проверка не удалась, кнопки установки скрыты, у версии —
  пояснение «нажмите „Проверить обновления“»: предлагать установку по данным
  неудачной проверки нельзя.
- Версии запоминаются вместе с каналом (components_channel); при смене канала
  прошлые данные забываются — они относились к другому каналу.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-18 19:39:09 +03:00
parent 55f523e1ed
commit 560c39da18
5 changed files with 150 additions and 11 deletions
+28 -9
View File
@@ -326,6 +326,7 @@ type SetupData struct {
LKPreview LKPreviewStatus // кабинет на этом сервере для просмотра
LKData LKDataView // курсы валют и ежедневный срез стоимости
Units []UnitView // службы bj и её модулей
UpdateFailed bool // последняя попытка обновления закончилась отказом
Versions SystemVersions // версии компонентов bj и внешних систем
Modules map[string]bool // какие лицензируемые модули разрешены (ключ = признак)
Features []LicenseFeatureView // признаки лицензии для карточки
@@ -394,6 +395,7 @@ func (h *setupHandlers) renderSetup(w http.ResponseWriter, req *http.Request, fl
LKPreview: lkPreviewStatus(h.rc, req),
LKData: lkDataView(h.rc),
Units: unitViews(h.rc),
UpdateFailed: updateResultFailed(s.Update.LastResult),
LKKeyMask: lkKeyForPage(s.LK.APIKey),
Versions: systemVersions(h.rc),
Modules: modulesAllowed(h.rc),
@@ -1243,10 +1245,16 @@ func (h *setupHandlers) saveUpdate(w http.ResponseWriter, r *http.Request) {
return
}
cfg := h.rc.Snapshot().Update
was := updateChannel(cfg)
cfg.BaseURL = strings.TrimSpace(r.FormValue("base_url"))
cfg.Channel = strings.TrimSpace(r.FormValue("channel"))
cfg.PublicKey = strings.TrimSpace(r.FormValue("public_key"))
cfg.AutoCheck = r.FormValue("auto_check") != ""
if updateChannel(cfg) != was {
// Версии из прошлого канала к новому не относятся — забываем их до проверки.
cfg.Components, cfg.ComponentsChannel, cfg.Available, cfg.Notes = nil, "", "", ""
cfg.LastResult = "канал сменён на «" + updateChannel(cfg) + "» — нажмите «Проверить обновления»"
}
if err := h.rc.SaveUpdateSettings(cfg); err != nil {
setupFlash(w, r, "обновления: ошибка сохранения: "+err.Error())
return
@@ -1277,24 +1285,35 @@ func (h *setupHandlers) applyUpdate(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
names := r.Form["component"]
rc := h.rc
// В фоне: при обновлении ядра bj-server перезапустится раньше, чем придёт ответ установщика.
go func() {
msg, err := NewUpdater(rc).ApplyUpdate(context.Background(), names)
cfg := rc.Snapshot().Update
save := func(msg string, err error) string {
if err != nil {
msg = "Обновление не применено: " + err.Error()
} else {
msg = "Обновление: " + msg
}
log.Printf("lk-gateway: %s", msg)
cfg := rc.Snapshot().Update
cfg.LastResult, cfg.LastCheck = msg, time.Now().UTC()
_ = rc.SaveUpdateSettings(cfg)
}()
what := "всех компонентов с новой версией"
if len(names) > 0 {
what = strings.Join(names, ", ")
return msg
}
setupFlash(w, r, "Обновление "+what+" запущено: файлы скачиваются и проверяются, затем перезапускаются службы. Итог — в строке «Последняя проверка» через минуту; при обновлении ядра страница временно не отвечает.")
// Обновление ядра — только в фоне: bj-server перезапустится раньше, чем придёт
// ответ установщика, и страница всё равно не дождётся. Модули обновляем на месте
// и показываем настоящий результат: иначе отказ («в канале нет релизов», нет
// лицензии, не сходится подпись) виден только строкой «Последняя проверка»,
// и со стороны выглядит так, будто кнопка ничего не делает.
if updateTouchesCore(rc, names) {
go func() { save(NewUpdater(rc).ApplyUpdate(context.Background(), names)) }()
what := "всех компонентов с новой версией"
if len(names) > 0 {
what = strings.Join(names, ", ")
}
setupFlash(w, r, "Обновление "+what+" запущено: файлы скачиваются и проверяются, затем перезапускаются службы. Итог — в строке «Последняя проверка» через минуту; при обновлении ядра страница временно не отвечает.")
return
}
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Minute)
defer cancel()
setupFlash(w, r, save(NewUpdater(rc).ApplyUpdate(ctx, names)))
}
// uploadUpdate — POST /admin/setup/update/upload: пакет обновления файлом (закрытый контур).