diff --git a/cmd/bsky-modactions/main.go b/cmd/bsky-modactions/main.go --- a/cmd/bsky-modactions/main.go +++ b/cmd/bsky-modactions/main.go @@ -8,6 +8,7 @@ "log/slog" "net/http" "os" "os/signal" + "time" comatproto "github.com/bluesky-social/indigo/api/atproto" "github.com/fxamacker/cbor/v2" @@ -102,9 +103,32 @@ } } }() + mux := http.NewServeMux() + mux.HandleFunc("/config", configHandler) + mux.HandleFunc("/", valueHandler) + + srv := &http.Server{ + Addr: "127.0.0.1:4456", + Handler: mux, + } + + go func() { + if err := srv.ListenAndServe(); err != nil { + slog.Error("error starting HTTP server", "err", err) + return + } + }() + <-ctx.Done() stop() slog.Info("shutting down") + + endctx, cancel := context.WithTimeout(context.TODO(), time.Minute) + defer cancel() + + if err := srv.Shutdown(endctx); err != nil { + slog.Error("error shutting down server", "err", err) + } return nil } diff --git a/cmd/bsky-modactions/munin.go b/cmd/bsky-modactions/munin.go new file mode 100644 --- /dev/null +++ b/cmd/bsky-modactions/munin.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "regexp" + + "github.com/redis/go-redis/v9" +) + +// https://guide.munin-monitoring.org/en/latest/reference/plugin.html#notes-on-field-names +var sanitize = regexp.MustCompile("[^a-zA-Z0-9_]") + +var rdb = redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", + DB: 0, +}) + +const AddedStop = 7 + +func configHandler(w http.ResponseWriter, r *http.Request) { + labels, err := rdb.ZRevRange(context.TODO(), LabelsAdded, 0, AddedStop).Result() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + fmt.Fprint(w, "graph_title bluesky labels added\n") + fmt.Fprint(w, "graph_category bluesky\n") + fmt.Fprint(w, "graph_vlabel labels / ${graph_period}\n") + fmt.Fprint(w, "graph_width 600\n") + fmt.Fprint(w, "graph_height 300\n") + + for _, label := range labels { + slug := sanitize.ReplaceAll([]byte(label), []byte("_")) + fmt.Fprintf(w, "%s.label %s\n", slug, label) + fmt.Fprintf(w, "%s.type DERIVE\n", slug) + } +} + +func valueHandler(w http.ResponseWriter, r *http.Request) { + labels, err := rdb.ZRevRangeWithScores(context.TODO(), LabelsAdded, 0, AddedStop).Result() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + for _, label := range labels { + key := label.Member.(string) + slug := sanitize.ReplaceAll([]byte(key), []byte("_")) + fmt.Fprintf(w, "%s.value %0.f\n", slug, label.Score) + } +}