Update für Persistenz
This commit is contained in:
86
main.go
86
main.go
@@ -13,10 +13,12 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -62,6 +64,8 @@ var (
|
||||
taskIndex = map[string]*Task{}
|
||||
started time.Time
|
||||
csrfKey []byte
|
||||
cfgPath = "tasks.json" // <- Dateipfad zentral
|
||||
cfgMu sync.Mutex // <- schützt Speichervorgang
|
||||
)
|
||||
|
||||
//go:embed web/*
|
||||
@@ -329,6 +333,11 @@ func handleSetInterval(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
t.setInterval(interval, enable)
|
||||
|
||||
// PERSISTENZ
|
||||
// auch die Werte im cfg.Tasks stecken bereits in t, also genügt:
|
||||
persistOrLog()
|
||||
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
@@ -344,6 +353,10 @@ func handleToggle(w http.ResponseWriter, r *http.Request) {
|
||||
t.Enabled = enable
|
||||
t.mutex.Unlock()
|
||||
t.scheduleNext()
|
||||
|
||||
// PERSISTENZ
|
||||
persistOrLog()
|
||||
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
@@ -399,16 +412,62 @@ func handleLogs(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
/* ====== Init/Load/Serve ====== */
|
||||
|
||||
func loadConfig() {
|
||||
f, err := os.Open("tasks.json")
|
||||
func saveConfigAtomic() error {
|
||||
cfgMu.Lock()
|
||||
defer cfgMu.Unlock()
|
||||
|
||||
// Schön formatiert schreiben
|
||||
b, err := json.MarshalIndent(cfg, "", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("tasks.json nicht gefunden: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// In dasselbe Verzeichnis wie cfgPath schreiben (wichtig für Rename-Atomizität)
|
||||
dir := filepath.Dir(cfgPath)
|
||||
base := filepath.Base(cfgPath)
|
||||
tmp := filepath.Join(dir, "."+base+".tmp")
|
||||
|
||||
// Temp-Datei erzeugen, schreiben, flushen
|
||||
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := f.Write(b); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
if err := f.Sync(); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Atomisch ersetzen
|
||||
if err := os.Rename(tmp, cfgPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bequemer Helfer zum Loggen statt Abbrechen
|
||||
func persistOrLog() {
|
||||
if err := saveConfigAtomic(); err != nil {
|
||||
log.Printf("WARN: Konnte %s nicht speichern: %v", cfgPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
func loadConfig() {
|
||||
f, err := os.Open(cfgPath)
|
||||
if err != nil {
|
||||
log.Fatalf("%s nicht gefunden: %v", cfgPath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
dec := json.NewDecoder(f)
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&cfg); err != nil {
|
||||
log.Fatalf("tasks.json fehlerhaft: %v", err)
|
||||
log.Fatalf("%s fehlerhaft: %v", cfgPath, err)
|
||||
}
|
||||
|
||||
if cfg.Listen == "" {
|
||||
@@ -495,8 +554,25 @@ func main() {
|
||||
Handler: basicAuth(mux),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// GRACEFUL SHUTDOWN + PERSISTENZ
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-stop
|
||||
log.Println("Beende... speichere Konfiguration.")
|
||||
persistOrLog()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
_ = server.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
log.Printf("Weboberfläche: http://%s (Basic Auth aktiv)", addr)
|
||||
log.Fatal(server.ListenAndServe())
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Server gestoppt.")
|
||||
}
|
||||
|
||||
/* ====== Embedded HTML (Tailwind-lite via CDN) ====== */
|
||||
|
||||
10
tasks.json
10
tasks.json
@@ -3,21 +3,19 @@
|
||||
"username": "admin",
|
||||
"password": "change-me",
|
||||
"scripts_dir": "C:\\scripts",
|
||||
"csrf_secret": "ersetzenMitEigenemSecret",
|
||||
"tasks": [
|
||||
{
|
||||
"name": "Nacht-Backup",
|
||||
"path": "C:\\scripts\\backup.ps1",
|
||||
"interval": "24h",
|
||||
"enabled": true,
|
||||
"timeout": "2h"
|
||||
},
|
||||
{
|
||||
"name": "IIS-Log-Rotation",
|
||||
"path": "C:\\scripts\\rotate.ps1",
|
||||
"interval": "0",
|
||||
"enabled": false,
|
||||
"interval": "5m",
|
||||
"timeout": "30m"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"csrf_secret": "ersetzenMitEigenemSecret"
|
||||
}
|
||||
Reference in New Issue
Block a user