this repo has no description
1package main
2
3import (
4 "bytes"
5 "context"
6 "fmt"
7 "log/slog"
8 "net/http"
9 "os"
10 "os/signal"
11
12 comatproto "github.com/bluesky-social/indigo/api/atproto"
13 "github.com/fxamacker/cbor/v2"
14 "github.com/gorilla/websocket"
15 "github.com/redis/go-redis/v9"
16 "github.com/urfave/cli/v2"
17)
18
19const (
20 BskyModDid = `did:plc:ar7c4by46qjdydhdevvrndac` // @moderation.bsky.app
21 BskyModLabelEndpoint = `wss://mod.bsky.app/xrpc/com.atproto.label.subscribeLabels`
22
23 ActionsConfig = `bskymodactions:config`
24 LabelsAdded = `bskymodactions:added`
25 LabelsRemoved = `bskymodactions:removed`
26)
27
28func main() {
29 app := cli.App{
30 Name: "bsky-modactions",
31 }
32
33 app.Action = func(cctx *cli.Context) error {
34 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
35 defer stop()
36
37 rdb := redis.NewClient(&redis.Options{
38 Addr: "localhost:6379",
39 Password: "",
40 DB: 0,
41 })
42
43 url := BskyModLabelEndpoint
44 seq, err := rdb.HGet(ctx, ActionsConfig, "seq").Result()
45 if err == nil && seq != "" { // err check reversed
46 url += fmt.Sprintf("?cursor=%s", seq)
47 }
48 slog.Info("connecting to websocket", "url", url)
49
50 wsconn, _, err := websocket.DefaultDialer.DialContext(ctx, url, http.Header{
51 "User-Agent": []string{"bsky-modactions/0.1 (@bskycharts.edavis.dev)"},
52 })
53 if err != nil {
54 return err
55 }
56
57 go func() {
58 for {
59 select {
60 case <-ctx.Done():
61 return
62 default:
63 }
64
65 _, p, err := wsconn.ReadMessage()
66 if err != nil {
67 slog.Error("error reading message from websocket", "err", err)
68 continue
69 }
70
71 var info comatproto.LabelSubscribeLabels_Info
72 rest, err := cbor.UnmarshalFirst(p, &info)
73 if err != nil {
74 slog.Error("error unmarshalling info", "err", err)
75 continue
76 }
77
78 var labels comatproto.LabelSubscribeLabels_Labels
79 err = labels.UnmarshalCBOR(bytes.NewReader(rest))
80 if err != nil {
81 slog.Error("error unmarshalling label", "err", err)
82 continue
83 }
84 for _, label := range labels.Labels {
85 if label.Src != BskyModDid {
86 continue
87 }
88
89 key := LabelsAdded
90 if label.Neg != nil && *label.Neg {
91 key = LabelsRemoved
92 }
93
94 if err := rdb.ZIncrBy(ctx, key, 1, label.Val).Err(); err != nil {
95 slog.Error("error incrementing key", "key", key)
96 }
97 }
98
99 if err := rdb.HSet(ctx, ActionsConfig, "seq", labels.Seq).Err(); err != nil {
100 slog.Error("error updating seq", "err", err)
101 }
102 }
103 }()
104
105 <-ctx.Done()
106 stop()
107 slog.Info("shutting down")
108
109 return nil
110 }
111
112 if err := app.Run(os.Args); err != nil {
113 slog.Error("error running app", "err", err)
114 }
115}