Files
talk/internal/queue/mute.go
T

80 lines
2.0 KiB
Go
Raw Normal View History

package queue
import (
"errors"
"os"
"path/filepath"
"strings"
)
// MuteFileName is the mute file's name inside the config directory.
const MuteFileName = "mute"
// ErrNoMutePath reports a Set attempt without a configured file path (config
// directory unknown; the daemon then runs without mute and warns at start).
var ErrNoMutePath = errors.New("mute: no file path configured (config directory unknown)")
// MuteStore manages the persistent mute state as a file in the config
// directory: content "true" = muted, anything else (or no file) = not muted.
//
// The daemon re-reads the file on every /speak request, so a state written
// by the CLI while no daemon runs takes effect immediately, and the state
// survives daemon restarts.
type MuteStore struct {
// Path is the mute file's full path. Empty (no config directory): Muted
// is always false and Set an error.
Path string
}
// Muted reports the persistent mute state. A missing or unreadable file
// means not muted: a broken setup must never be "accidentally silent".
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 writes the mute state atomically (temp file + rename, so daemon and
// CLI never read a half-written file) and creates the config directory if
// needed.
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
}