84 lines
2.3 KiB
Go
84 lines
2.3 KiB
Go
package queue
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// MuteFileName ist der Name der Mute-Datei im Config-Verzeichnis (bindender
|
||
|
|
// Vertrag: „persistenten Mute-State toggeln (Datei mute im Config-Dir)").
|
||
|
|
const MuteFileName = "mute"
|
||
|
|
|
||
|
|
// ErrNoMutePath meldet einen Set-Versuch ohne konfigurierten Datei-Pfad
|
||
|
|
// (Config-Dir nicht bestimmbar — der Daemon deaktiviert dann Mute mit einer
|
||
|
|
// Start-Warnung statt zu scheitern).
|
||
|
|
var ErrNoMutePath = errors.New("mute: kein Datei-Pfad konfiguriert (Config-Dir nicht bestimmbar)")
|
||
|
|
|
||
|
|
// MuteStore verwaltet den persistenten Mute-State als Datei im
|
||
|
|
// Config-Verzeichnis: Inhalt „true" = stumm, alles andere (oder keine Datei)
|
||
|
|
// = nicht stumm.
|
||
|
|
//
|
||
|
|
// Der Daemon liest die Datei bei jeder /speak-Anfrage neu — dadurch wirkt
|
||
|
|
// auch ein im Degraded Mode (Daemon tot) von der CLI direkt geschriebener
|
||
|
|
// State sofort, und der Zustand überlebt Daemon-Restarts.
|
||
|
|
type MuteStore struct {
|
||
|
|
// Path ist der vollständige Pfad der Mute-Datei. Leer (kein Config-Dir
|
||
|
|
// bestimmbar): Muted() ist immer false, Set ein Fehler.
|
||
|
|
Path string
|
||
|
|
}
|
||
|
|
|
||
|
|
// Muted meldet den persistenten Mute-State. Eine fehlende oder unlesbare
|
||
|
|
// Datei heißt: nicht stumm (Fehlstart ohne Config-Dir wird nie „stumm aus
|
||
|
|
// Versehen").
|
||
|
|
func (s MuteStore) Muted() bool {
|
||
|
|
if s.Path == "" {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
b, err := os.ReadFile(s.Path)
|
||
|
|
if err != nil {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
return strings.TrimSpace(string(b)) == "true"
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set schreibt den Mute-State atomar (temporäre Datei + Rename, damit
|
||
|
|
// Daemon und CLI nie eine halb geschriebene Datei lesen) und legt das
|
||
|
|
// Config-Verzeichnis bei Bedarf an.
|
||
|
|
func (s MuteStore) Set(muted bool) error {
|
||
|
|
if s.Path == "" {
|
||
|
|
return ErrNoMutePath
|
||
|
|
}
|
||
|
|
dir := filepath.Dir(s.Path)
|
||
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
content := "false\n"
|
||
|
|
if muted {
|
||
|
|
content = "true\n"
|
||
|
|
}
|
||
|
|
tmp, err := os.CreateTemp(dir, ".mute-*")
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
name := tmp.Name()
|
||
|
|
if _, err := tmp.WriteString(content); err != nil {
|
||
|
|
tmp.Close()
|
||
|
|
os.Remove(name)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if err := tmp.Close(); err != nil {
|
||
|
|
os.Remove(name)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if err := os.Chmod(name, 0o644); err != nil {
|
||
|
|
os.Remove(name)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if err := os.Rename(name, s.Path); err != nil {
|
||
|
|
os.Remove(name)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|