DRMDTool/handlers.go
2024-09-14 03:39:15 +02:00

354 lines
7.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
)
type ProgressInfo struct {
Percentage float64
CurrentFile string
Paused bool
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
progressMutex.Lock()
defer progressMutex.Unlock()
jobsInfo := make(map[string]struct {
Percentage float64
CurrentFile string
Paused bool
})
for filename, info := range progress {
jobsInfo[filename] = struct {
Percentage float64
CurrentFile string
Paused bool
}{
Percentage: info.Percentage,
CurrentFile: info.CurrentFile,
Paused: info.Paused,
}
}
err := templates.ExecuteTemplate(w, "index", struct {
Jobs map[string]struct {
Percentage float64
CurrentFile string
Paused bool
}
}{jobsInfo})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func handleUpload(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(32 << 20)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
files := r.MultipartForm.File["files"]
if len(files) == 0 {
http.Error(w, "No files uploaded", http.StatusBadRequest)
return
}
uploadedFiles := []string{}
for _, fileHeader := range files {
file, err := fileHeader.Open()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
tempFile, err := os.CreateTemp(uploadDir, fileHeader.Filename)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer tempFile.Close()
_, err = io.Copy(tempFile, file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
uploadedFiles = append(uploadedFiles, filepath.Base(tempFile.Name()))
_, err = parseInputFile(tempFile.Name())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
validFiles := []string{}
for _, file := range uploadedFiles {
if file != "" {
validFiles = append(validFiles, file)
}
}
if len(validFiles) == 0 {
http.Error(w, "No valid files were uploaded", http.StatusBadRequest)
return
}
http.Redirect(w, r, "/select?files="+url.QueryEscape(strings.Join(validFiles, ",")), http.StatusSeeOther)
}
func handleSelect(w http.ResponseWriter, r *http.Request) {
filesParam := r.URL.Query().Get("files")
filenames := strings.Split(filesParam, ",")
allItems := make(map[string]map[string][]Item)
for _, filename := range filenames {
if filename == "" {
continue
}
fullPath := filepath.Join(uploadDir, filename)
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
continue
}
items, err := parseInputFile(fullPath)
if err != nil {
continue
}
groupedItems := groupItemsBySeason(items)
allItems[filename] = groupedItems
}
if len(allItems) == 0 {
http.Error(w, "No valid files were processed", http.StatusBadRequest)
return
}
err := templates.ExecuteTemplate(w, "select", struct {
Filenames string
AllItems map[string]map[string][]Item
}{
Filenames: filesParam,
AllItems: allItems,
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func handleProcess(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
selectedItems := r.Form["items"]
if len(selectedItems) == 0 {
http.Error(w, "No items selected", http.StatusBadRequest)
return
}
itemsByFile := make(map[string][]string)
for _, item := range selectedItems {
parts := strings.SplitN(item, ":", 2)
if len(parts) != 2 {
continue
}
filename, itemName := parts[0], parts[1]
itemsByFile[filename] = append(itemsByFile[filename], itemName)
}
for filename, items := range itemsByFile {
fullPath := filepath.Join(uploadDir, filename)
allItems, err := parseInputFile(fullPath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
selectedItems := filterSelectedItems(allItems, items)
go processItems(filename, selectedItems)
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func handleProgress(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("filename")
if r.Header.Get("Accept") == "application/json" {
progressInfo := getProgress(filename)
if progressInfo == nil {
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"error": "No progress information found"})
return
}
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(progressInfo)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
return
}
err := templates.ExecuteTemplate(w, "progress", struct{ Filename string }{filename})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func handlePause(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("filename")
if filename == "" {
http.Error(w, "Filename is required", http.StatusBadRequest)
return
}
jobsMutex.Lock()
jobInfo, exists := jobs[filename]
jobsMutex.Unlock()
if !exists {
http.Error(w, "Job not found", http.StatusNotFound)
return
}
jobInfo.Paused = true
if jobInfo.Cmd != nil && jobInfo.Cmd.Process != nil {
jobInfo.Cmd.Process.Kill()
}
progressMutex.Lock()
if progressInfo, ok := progress[filename]; ok {
progressInfo.Paused = true
}
progressMutex.Unlock()
fmt.Fprintf(w, "Pause signal sent for %s", filename)
}
func handleResume(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("filename")
if filename == "" {
http.Error(w, "Filename is required", http.StatusBadRequest)
return
}
jobsMutex.Lock()
jobInfo, exists := jobs[filename]
jobsMutex.Unlock()
if !exists {
http.Error(w, "Job not found", http.StatusNotFound)
return
}
jobInfo.Paused = false
jobInfo.ResumeChan <- struct{}{}
progressMutex.Lock()
if progressInfo, ok := progress[filename]; ok {
progressInfo.Paused = false
}
progressMutex.Unlock()
fmt.Fprintf(w, "Resume signal sent for %s", filename)
}
func handleAbort(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("filename")
if filename == "" {
http.Error(w, "Filename is required", http.StatusBadRequest)
return
}
jobsMutex.Lock()
jobInfo, exists := jobs[filename]
jobsMutex.Unlock()
if !exists {
http.Error(w, "Job not found", http.StatusNotFound)
return
}
close(jobInfo.AbortChan)
if jobInfo.Cmd != nil && jobInfo.Cmd.Process != nil {
jobInfo.Cmd.Process.Kill()
}
if jobInfo.TempDir != "" {
os.RemoveAll(jobInfo.TempDir)
}
fmt.Fprintf(w, "Abort signal sent for %s", filename)
}
func handleClearCompleted(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
clearCompletedJobs()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]bool{"success": true})
}
func clearCompletedJobs() {
progressMutex.Lock()
defer progressMutex.Unlock()
for filename, info := range progress {
if info.Percentage >= 100 {
delete(progress, filename)
}
}
}
func updateProgress(filename string, value float64, currentFile string) {
progressMutex.Lock()
defer progressMutex.Unlock()
jobsMutex.Lock()
jobInfo, exists := jobs[filename]
jobsMutex.Unlock()
paused := false
if exists {
paused = jobInfo.Paused
}
if existingProgress, ok := progress[filename]; ok {
existingProgress.Percentage = value
existingProgress.CurrentFile = currentFile
existingProgress.Paused = paused
} else {
progress[filename] = &ProgressInfo{
Percentage: value,
CurrentFile: currentFile,
Paused: paused,
}
}
}