package api import ( "context" "errors" "net/http" "time" "github.com/mrleo1nid/pzmanager/internal/pzserver" "github.com/mrleo1nid/pzmanager/internal/updater" ) // handleCheckUpdate спрашивает у репозитория последнюю версию. func (s *Server) handleCheckUpdate(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, s.updater.Check(r.Context())) } // handleApplyUpdate качает новую версию и перезапускает панель. Ответ уходит // раньше, чем работа заканчивается: обновление убивает текущий процесс. func (s *Server) handleApplyUpdate(w http.ResponseWriter, r *http.Request) { var body struct { Version string `json:"version"` } if r.ContentLength > 0 && !decodeJSON(w, r, &body) { return } if !s.updater.CanApply(r.Context()) { writeError(w, http.StatusPreconditionFailed, updater.ErrNoAdmin.Error()) return } name := "Обновление панели" err := s.jobs.Start(name, func(ctx context.Context, log func(string)) error { // Игровой сервер останавливаем сами: иначе это сделает systemd уже в // момент перезапуска, и ожидание растянется на таймаут остановки. s.stopServerBefore(log, "обновлением") log("Запускаю обновление — оно идёт отдельной службой и переживёт перезапуск панели") log("Подробности: journalctl -u pzmanager-update -f") return s.updater.Apply(ctx, log, body.Version) }) if err != nil { writeOpError(w, err) return } writeJSON(w, http.StatusAccepted, map[string]any{"task": name}) } // handleRestartManager перезапускает саму панель. func (s *Server) handleRestartManager(w http.ResponseWriter, r *http.Request) { if !s.updater.CanApply(r.Context()) { writeError(w, http.StatusPreconditionFailed, updater.ErrNoAdmin.Error()) return } name := "Перезапуск панели" err := s.jobs.Start(name, func(ctx context.Context, log func(string)) error { s.stopServerBefore(log, "перезапуском") log("Перезапускаю панель") return s.updater.Restart(ctx, log) }) if err != nil { writeOpError(w, err) return } writeJSON(w, http.StatusAccepted, map[string]any{"task": name}) } // stopServerBefore корректно гасит игровой сервер перед тем, как панель уйдёт // в перезапуск: мир сохраняется, а systemd не ждёт таймаут остановки. func (s *Server) stopServerBefore(log func(string), what string) { if s.sup.State() == pzserver.StateStopped { return } log("Останавливаю игровой сервер перед " + what) if err := s.sup.Stop(); err != nil && !errors.Is(err, pzserver.ErrNotRunning) { log("Остановить сервер не удалось: " + err.Error()) return } s.sup.WaitStopped(30 * time.Second) }