1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
package main
import (
"context"
"flag"
"log/slog"
"os"
"regexp"
"time"
bskyData "github.com/bluesky-social/indigo/api/bsky"
jsModels "github.com/bluesky-social/jetstream/pkg/models"
"github.com/goccy/go-json"
"github.com/nats-io/nats.go"
"within.website/x/internal"
bsky "within.website/x/web/bskybot"
)
const (
PostTopic = "amano.commit.app.bsky.feed.post"
)
var (
blueskyAuthkey = flag.String("bsky-authkey", "", "Bluesky authkey")
blueskyHandle = flag.String("bsky-handle", "", "Bluesky handle")
blueskyPDS = flag.String("bsky-pds", "https://bsky.social", "Bluesky PDS")
natsURL = flag.String("nats-url", "nats://localhost:4222", "nats url")
sneakPeakRegex = regexp.MustCompile("(?i)sneak peak")
)
func main() {
internal.HandleStartup()
slog.Info("starting up",
"have-bsky-authkey", *blueskyAuthkey != "",
"bsky-handle", *blueskyHandle,
"bsky-pds", *blueskyPDS,
"nats-url", *natsURL,
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
bsAgent, err := bskyAuth(ctx, *blueskyPDS, *blueskyHandle, *blueskyAuthkey)
if err != nil {
slog.Error("can't auth to bluesky", "err", err)
os.Exit(1)
}
nc, err := nats.Connect(*natsURL)
if err != nil {
slog.Error("can't connect to NATS", "err", err)
os.Exit(1)
}
defer nc.Close()
slog.Info("connected to NATS")
sub, err := nc.SubscribeSync(PostTopic)
if err != nil {
slog.Error("can't subscribe to post feed", "err", err)
os.Exit(1)
}
defer sub.Drain()
for {
m, err := sub.NextMsg(time.Second)
if err != nil {
slog.Error("can't read message", "err", err)
continue
}
var commit jsModels.Commit
if err := json.Unmarshal(m.Data, &commit); err != nil {
slog.Error("can't unmarshal commit", "err", err)
continue
}
if commit.Operation == "delete" {
continue
}
var post bskyData.FeedPost
if err := json.Unmarshal(commit.Record, &post); err != nil {
slog.Error("can't unmarshal post", "err", err)
continue
}
if !sneakPeakRegex.MatchString(post.Text) {
continue
}
actorID := m.Header.Get("bsky-actor-did")
slog.Info("found a stealth mountain!", "id", commit.Rev, "actor", actorID)
reply, err := bsky.NewPostBuilder(`I think you mean "sneak peek"`).
InReplyTo(post, actorID, commit.CID, commit.RKey).
Build()
if err != nil {
slog.Error("can't build reply post", "err", err)
}
cid, uri, err := bsAgent.PostToFeed(ctx, reply)
if err != nil {
slog.Error("cannot post to feed", "err", err)
continue
}
slog.Info("posted to bluesky", "bluesky_cid", cid, "bluesky_uri", uri)
}
}
func bskyAuth(ctx context.Context, pds, handle, authkey string) (*bsky.BskyAgent, error) {
bluesky := bsky.NewAgent(ctx, pds, handle, authkey)
slog.Debug("connecting to bluesky server", "pds", pds, "handle", handle)
if err := bluesky.Connect(ctx); err != nil {
slog.Error("failed to connect to bluesky", "err", err)
return nil, err
}
return &bluesky, nil
}
|