Files
2026-10-06 22:25:23 +02:00

104 lines
3.1 KiB
Go

package useCases
import (
"RenewCMS/internal/domain/audit"
"RenewCMS/internal/domain/update"
"context"
"sync"
"time"
)
type RequestRestartUseCase struct {
jobs update.JobStore
helper update.HelperDetector
results update.ResultStore
requests update.RestartRequestStore
status updateStatusBuilder
now func() time.Time
recorder audit.Recorder
mu sync.Mutex
}
func NewRequestRestartUseCase(store update.StatusStore, jobs update.JobStore, helper update.HelperDetector, results update.ResultStore, requests update.RestartRequestStore, currentVersion string, now func() time.Time, recorder audit.Recorder) *RequestRestartUseCase {
return &RequestRestartUseCase{
jobs: jobs,
helper: helper,
results: results,
requests: requests,
status: updateStatusBuilder{store: store, jobs: jobs, results: results, requests: requests, currentVersion: currentVersion, now: now},
now: now,
recorder: recorder,
}
}
func (r *RequestRestartUseCase) Request(ctx context.Context, userId uint32, kind string) (update.UpdateStatus, error) {
event := audit.NewEvent(audit.ActionRestartRequested, audit.CategorySystem)
status, request, err := r.request(userId, kind)
if err != nil {
recordFailure(ctx, r.recorder, event, err, restartFailureReasons...)
return update.UpdateStatus{}, err
}
event.Params = restartParams(request)
r.recorder.Record(ctx, event)
return status, nil
}
func restartParams(request update.RestartRequest) map[string]any {
params := map[string]any{audit.ParamKind: request.Kind}
if request.Kind == update.RestartKindUpdate {
params[audit.ParamTag] = request.Tag
}
return params
}
func (r *RequestRestartUseCase) request(userId uint32, kind string) (update.UpdateStatus, update.RestartRequest, error) {
if !r.helper.Installed() {
return update.UpdateStatus{}, update.RestartRequest{}, update.ErrNotPrepared
}
r.mu.Lock()
defer r.mu.Unlock()
current := r.status.build(true)
if err := refuseWhileBusy(current); err != nil {
return update.UpdateStatus{}, update.RestartRequest{}, err
}
request, err := r.requestFor(kind, userId)
if err != nil {
return update.UpdateStatus{}, update.RestartRequest{}, err
}
if err := r.results.Delete(); err != nil {
return update.UpdateStatus{}, update.RestartRequest{}, err
}
if err := r.requests.Write(request); err != nil {
return update.UpdateStatus{}, update.RestartRequest{}, err
}
return r.status.build(true), request, nil
}
func refuseWhileBusy(status update.UpdateStatus) error {
switch status.State {
case update.StateDownloading, update.StateVerifying:
return update.ErrJobInProgress
case update.StateRestarting:
return update.ErrRestartPending
}
return nil
}
func (r *RequestRestartUseCase) requestFor(kind string, userId uint32) (update.RestartRequest, error) {
request := update.RestartRequest{
Kind: update.RestartKindRestart,
RequestedAt: r.now().UTC(),
RequestedBy: userId,
}
if job, found := r.jobs.Load(); found && job.State == update.StateReady {
request.Kind = update.RestartKindUpdate
request.Tag = job.Tag
}
if kind != "" && kind != request.Kind {
return update.RestartRequest{}, update.ErrRestartKindMismatch
}
return request, nil
}