aboutsummaryrefslogtreecommitdiff
path: root/cmd/stealthmountain/main.go
blob: db0a61f36bc760e3d0cc6953538bbe39cc82d463 (plain)
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
}