feat(api): /speak meldet Gesetz-Verwürfe, /status zeigt Gesetz-State
POST /speak antwortet bei Verwurf dokumentiert mit 202 {id:"",
discarded:"rate_limit"|"quiet_hours"} (+ toast:true im Toast-Modus)
— analog zum Mute-Muster, kein Fehler. GET /status ergänzt additiv
rate_limit {interval, allow_high_burst, next_slot} und quiet_hours
{window, active, mode, until} (RFC3339 bzw. null). talkd verwired die
Gesetze aus der Config und loggt sie beim Start. Die CLI meldet
'discarded: <grund>' plain (wie muted) und zeigt in talk status die
Zeilen rate-limit/ruhezeit mit Slot bzw. Fenster-Ende.
This commit is contained in:
1 parent
5385a4b87d
commit
b56c8abfae
6 files changed
+194
-27
No files matched your search
+43
-2
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"code.m3ta.dev/m3tam3re/talk/internal/api"
|
||||
"code.m3ta.dev/m3tam3re/talk/internal/config"
|
||||
@@ -71,8 +72,9 @@ func printMuteState(muted bool, stdout io.Writer) {
|
||||
|
||||
// runStatus implementiert `talk status`: plain Block aus GET /status —
|
||||
// Daemon-Adresse + Version, Queue-Länge, aktuelles Item, Mute-State,
|
||||
// aktiver Provider. Ohne Daemon: klarer Fehler (status ist eine Anfrage an
|
||||
// den Daemon; der Degraded Mode hat keinen Status).
|
||||
// aktiver Provider, Gesetz-State (Rate-Limit, Ruhezeit). Ohne Daemon:
|
||||
// klarer Fehler (status ist eine Anfrage an den Daemon; der Degraded Mode
|
||||
// hat keinen Status).
|
||||
func runStatus(args []string, opts *sayOptions, stdin io.Reader, stdout, stderr io.Writer) int {
|
||||
cfg, err := config.Load(config.Options{Getenv: getenv})
|
||||
if err != nil {
|
||||
@@ -101,9 +103,48 @@ func runStatus(args []string, opts *sayOptions, stdin io.Reader, stdout, stderr
|
||||
}
|
||||
fmt.Fprintf(stdout, "mute: %s\n", muteState)
|
||||
fmt.Fprintf(stdout, "provider: %s\n", st.Provider)
|
||||
printLawState(stdout, st)
|
||||
return exitOK
|
||||
}
|
||||
|
||||
// printLawState schreibt den Gesetz-State (Task 05) aus GET /status:
|
||||
// Rate-Limit mit Burst-Recht und nächstem Slot sowie das Ruhezeit-Fenster.
|
||||
func printLawState(stdout io.Writer, st *api.StatusResponse) {
|
||||
if st.RateLimit != nil {
|
||||
interval := st.RateLimit.Interval
|
||||
if interval == "0s" {
|
||||
interval = "aus (unbegrenzt)"
|
||||
}
|
||||
burst := "verboten"
|
||||
if st.RateLimit.AllowHighBurst {
|
||||
burst = "erlaubt"
|
||||
}
|
||||
line := fmt.Sprintf("rate-limit: %s (high-burst %s)", interval, burst)
|
||||
if st.RateLimit.NextSlot != nil {
|
||||
if ts, err := time.Parse(time.RFC3339, *st.RateLimit.NextSlot); err == nil {
|
||||
line += fmt.Sprintf(", nächster slot %s", ts.Format("15:04:05"))
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(stdout, line)
|
||||
}
|
||||
if st.QuietHours != nil {
|
||||
window := st.QuietHours.Window
|
||||
if window == "" {
|
||||
window = "aus"
|
||||
}
|
||||
state := "inaktiv"
|
||||
if st.QuietHours.Active {
|
||||
state = "aktiv"
|
||||
if st.QuietHours.Until != nil {
|
||||
if ts, err := time.Parse(time.RFC3339, *st.QuietHours.Until); err == nil {
|
||||
state += " bis " + ts.Format("15:04")
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(stdout, "ruhezeit: %s (modus %s, %s)\n", window, st.QuietHours.Mode, state)
|
||||
}
|
||||
}
|
||||
|
||||
// runCancel implementiert `talk cancel`: POST /cancel — bricht die laufende
|
||||
// Ansage ab und leert die Queue; stdout meldet die Zahl der abgebrochenen
|
||||
// Ansagen. Ohne Daemon gibt es nichts, was talk abbrechen könnte.
|
||||
|
||||
Reference in new issue
Block a user