nsfwapp/backend/tasks_status.go
2026-04-27 14:40:16 +02:00

280 lines
6.8 KiB
Go

// backend\tasks_status.go
package main
import (
"encoding/json"
"net/http"
"strings"
"sync"
"time"
)
type CleanupTaskState struct {
Queued bool `json:"queued"`
Running bool `json:"running"`
QueuedAt time.Time `json:"queuedAt"`
StartedAt time.Time `json:"startedAt"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
Text string `json:"text,omitempty"`
Error string `json:"error,omitempty"`
CurrentFile string `json:"currentFile,omitempty"`
Done int `json:"done"`
Total int `json:"total"`
}
type CheckVideosTaskState struct {
Queued bool `json:"queued"`
Running bool `json:"running"`
QueuedAt time.Time `json:"queuedAt"`
StartedAt time.Time `json:"startedAt"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
Text string `json:"text,omitempty"`
Error string `json:"error,omitempty"`
CurrentFile string `json:"currentFile,omitempty"`
Done int `json:"done"`
Total int `json:"total"`
}
type RegenerateAssetsTaskState struct {
Running bool `json:"running"`
File string `json:"file,omitempty"`
Text string `json:"text,omitempty"`
Error string `json:"error,omitempty"`
}
type TasksStatusResponse struct {
GenerateAssets AssetsTaskState `json:"generateAssets"`
RegenerateAssets RegenerateAssetsTaskState `json:"regenerateAssets"`
RegenerateAssetsJobs []map[string]any `json:"regenerateAssetsJobs"`
CheckVideos CheckVideosTaskState `json:"checkVideos"`
Cleanup CleanupTaskState `json:"cleanup"`
AnyRunning bool `json:"anyRunning"`
}
var (
cleanupTaskMu sync.Mutex
cleanupTaskState CleanupTaskState
regenerateAssetsTaskMu sync.Mutex
regenerateAssetsTaskState RegenerateAssetsTaskState
)
func cleanupNowTime() *time.Time {
t := time.Now()
return &t
}
func anyToString(v any) string {
switch x := v.(type) {
case string:
return x
case []byte:
return string(x)
default:
return ""
}
}
func snapshotRegenerateAssetsTaskState() RegenerateAssetsTaskState {
regenerateAssetsTaskMu.Lock()
st := regenerateAssetsTaskState
regenerateAssetsTaskMu.Unlock()
return st
}
func setRegenerateAssetsTaskRunning(file, text string) {
regenerateAssetsTaskMu.Lock()
regenerateAssetsTaskState = RegenerateAssetsTaskState{
Running: true,
File: strings.TrimSpace(file),
Text: strings.TrimSpace(text),
Error: "",
}
regenerateAssetsTaskMu.Unlock()
publishTaskState()
}
func setRegenerateAssetsTaskDone(file, text string) {
regenerateAssetsTaskMu.Lock()
regenerateAssetsTaskState = RegenerateAssetsTaskState{
Running: false,
File: strings.TrimSpace(file),
Text: strings.TrimSpace(text),
Error: "",
}
regenerateAssetsTaskMu.Unlock()
publishTaskState()
}
func setRegenerateAssetsTaskError(file, errText string) {
regenerateAssetsTaskMu.Lock()
regenerateAssetsTaskState = RegenerateAssetsTaskState{
Running: false,
File: strings.TrimSpace(file),
Text: "",
Error: strings.TrimSpace(errText),
}
regenerateAssetsTaskMu.Unlock()
publishTaskState()
}
func clearRegenerateAssetsTaskState() {
regenerateAssetsTaskMu.Lock()
regenerateAssetsTaskState = RegenerateAssetsTaskState{}
regenerateAssetsTaskMu.Unlock()
publishTaskState()
}
func snapshotCleanupTaskState() CleanupTaskState {
cleanupTaskMu.Lock()
st := cleanupTaskState
cleanupTaskMu.Unlock()
return st
}
func setCleanupTaskQueued(text string) {
cleanupTaskMu.Lock()
cleanupTaskState = CleanupTaskState{
Queued: true,
Running: false,
QueuedAt: time.Now(),
StartedAt: time.Time{},
FinishedAt: nil,
Text: strings.TrimSpace(text),
Error: "",
CurrentFile: "",
Done: 0,
Total: 0,
}
cleanupTaskMu.Unlock()
publishTaskState()
}
func setCleanupTaskRunning(text string) {
cleanupTaskMu.Lock()
now := time.Now()
queuedAt := cleanupTaskState.QueuedAt
if queuedAt.IsZero() {
queuedAt = now
}
cleanupTaskState = CleanupTaskState{
Queued: false,
Running: true,
QueuedAt: queuedAt,
StartedAt: now,
FinishedAt: nil,
Text: strings.TrimSpace(text),
Error: "",
CurrentFile: "",
Done: 0,
Total: 0,
}
cleanupTaskMu.Unlock()
publishTaskState()
}
func setCleanupTaskProgress(done, total int, currentFile, text string) {
cleanupTaskMu.Lock()
now := time.Now()
if cleanupTaskState.QueuedAt.IsZero() {
cleanupTaskState.QueuedAt = now
}
if cleanupTaskState.StartedAt.IsZero() {
cleanupTaskState.StartedAt = now
}
cleanupTaskState.Queued = false
cleanupTaskState.Running = true
cleanupTaskState.Done = done
cleanupTaskState.Total = total
cleanupTaskState.CurrentFile = strings.TrimSpace(currentFile)
cleanupTaskState.Text = strings.TrimSpace(text)
cleanupTaskState.Error = ""
cleanupTaskState.FinishedAt = nil
cleanupTaskMu.Unlock()
publishTaskState()
}
func setCleanupTaskDone(text string) {
cleanupTaskMu.Lock()
cleanupTaskState.Queued = false
cleanupTaskState.Running = false
cleanupTaskState.Text = strings.TrimSpace(text)
cleanupTaskState.CurrentFile = ""
cleanupTaskState.Error = ""
cleanupTaskState.FinishedAt = cleanupNowTime()
if cleanupTaskState.Total > 0 {
cleanupTaskState.Done = cleanupTaskState.Total
}
cleanupTaskMu.Unlock()
publishTaskState()
}
func setCleanupTaskError(errText string) {
cleanupTaskMu.Lock()
cleanupTaskState.Queued = false
cleanupTaskState.Running = false
cleanupTaskState.Text = ""
cleanupTaskState.Error = strings.TrimSpace(errText)
cleanupTaskState.CurrentFile = ""
cleanupTaskState.FinishedAt = cleanupNowTime()
cleanupTaskMu.Unlock()
publishTaskState()
}
func tasksStatusHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Nur GET erlaubt", http.StatusMethodNotAllowed)
return
}
assets := getGenerateAssetsTaskStatus()
regenerate := snapshotRegenerateAssetsTaskState()
regenerateJobs := getRegenerateAssetsJobsSnapshot()
checkVideos := snapshotCheckVideosTaskState()
cleanup := snapshotCleanupTaskState()
anyRegenerateRunning := regenerate.Running
if !anyRegenerateRunning {
for _, job := range regenerateJobs {
state := strings.TrimSpace(strings.ToLower(anyToString(job["state"])))
if state == "queued" || state == "running" {
anyRegenerateRunning = true
break
}
}
}
resp := TasksStatusResponse{
GenerateAssets: assets,
RegenerateAssets: regenerate,
RegenerateAssetsJobs: regenerateJobs,
CheckVideos: checkVideos,
Cleanup: cleanup,
AnyRunning: assets.Queued || assets.Running || anyRegenerateRunning || checkVideos.Queued || checkVideos.Running || cleanup.Queued || cleanup.Running,
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-store")
_ = json.NewEncoder(w).Encode(resp)
}