refactor: ein Binary — talk startet den Daemon selbst, talkd und Degraded Mode entfallen
Zwei Binaries erzeugten den halben Komplexitätsballast: Degraded Mode mit Lock-Datei und Stale-Lock-Race, „läuft talkd?", Autostart-Konfiguration je OS, doppelte Chain-Konstruktion in cmd/talk und cmd/talkd — und der Degraded Mode kannte weder Rate-Limit noch Ruhezeiten. Jetzt: - internal/speak: der eine Sprech-Kern (Config + Sink + Kette → Ansage); Daemon und Direkt-Pfad benutzen ihn, es gibt keine zweite Zusammensetzung der Kette mehr. - internal/daemon: Run (der bisherige talkd-Kern), Spawn (detached per Setsid bzw. DETACHED_PROCESS, stdout/stderr → daemon.log), PID-Datei daemon.pid, Shutdown-Trigger. - `talk daemon run|start|stop`: Vordergrund (systemd/launchd), expliziter Hintergrund-Start, Stop per POST /shutdown — stop wartet, bis HTTP weg und die PID-Datei gelöscht ist (Prozess wirklich beendet). - Autostart: say/wrap starten den Daemon beim ersten Sprechbefehl selbst (daemon.autostart, Default an; Env TALK_AUTOSTART). Verliert ein paralleler Aufruf das Port-Rennen, erkennt er das am Kind-Ende und nutzt den Daemon des anderen — kein Timeout-Warten. - Direkt-Pfad statt Degraded Mode: ohne erreichbaren oder startbaren Daemon spricht talk direkt (Mute respektiert, kein Lock, Hinweis + Grund + Log-Pfad auf stderr). Steuerbefehle starten den Daemon bewusst nicht; `talk status` zeigt „läuft nicht" (Exit 1). - cmd/talkd und cmd/talk/degraded.go entfernt; README-Daemon-Abschnitt neu. Tests: Harness baut nur noch talk und startet `talk daemon run`; TALK_AUTOSTART=false als Grundausstattung aller Tests (kein Test hinterlässt Daemons), autostart_test.go schaltet es bewusst an: Autostart beim ersten say, Idempotenz, paralleler Start in EINE Queue, expliziter start/stop, Port fremd belegt → Direkt-Pfad ohne Timeout. Cross-Compile aller sechs Targets mit CGO_ENABLED=0 verifiziert. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
b86632006e
commit
bc26a73aeb
29 files changed
+1145
-584
No files matched your search
@@ -686,3 +686,48 @@ allow_high_burst = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestLoadDaemonAutostart deckt [daemon] autostart ab: Default an, TOML
|
||||
// kann es ausschalten, Env TALK_AUTOSTART schlägt die Datei, Unsinn ist ein
|
||||
// klarer Fehler.
|
||||
func TestLoadDaemonAutostart(t *testing.T) {
|
||||
fehlendeDatei := filepath.Join(t.TempDir(), "gibt-es-nicht.toml")
|
||||
writeTOML := func(t *testing.T, content string) string {
|
||||
path := filepath.Join(t.TempDir(), "config.toml")
|
||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
cfg, err := Load(Options{File: fehlendeDatei, Getenv: env(nil)})
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if !cfg.Daemon.Autostart {
|
||||
t.Error("Daemon.Autostart = false, want Default true")
|
||||
}
|
||||
|
||||
cfg, err = Load(Options{File: writeTOML(t, "[daemon]\nautostart = false\n"), Getenv: env(nil)})
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.Daemon.Autostart {
|
||||
t.Error("Daemon.Autostart = true, want false aus TOML")
|
||||
}
|
||||
|
||||
cfg, err = Load(Options{
|
||||
File: writeTOML(t, "[daemon]\nautostart = false\n"),
|
||||
Getenv: env(map[string]string{"TALK_AUTOSTART": "true"}),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if !cfg.Daemon.Autostart {
|
||||
t.Error("Daemon.Autostart = false, want true aus Env (Env schlägt Datei)")
|
||||
}
|
||||
|
||||
if _, err := Load(Options{File: fehlendeDatei, Getenv: env(map[string]string{"TALK_AUTOSTART": "vielleicht"})}); err == nil {
|
||||
t.Error("TALK_AUTOSTART=vielleicht: kein Fehler, want klarer Fehler")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user