+1
.env-example
+1
.env-example
+14
-8
cmd/register-feed/main.go
+14
-8
cmd/register-feed/main.go
···
33
}
34
35
type registerRecord struct {
36
-
Did string `json:"did"`
37
-
DisplayName string `json:"displayName"`
38
-
Description string `json:"description"`
39
-
CreatedAt time.Time `json:"createdAt"`
40
}
41
42
func main() {
···
136
if feedDID == "" {
137
return fmt.Errorf("FEED_DID environment not set")
138
}
139
140
reqData := registerFeedGen{
141
Repo: auth.Did,
142
Collection: "app.bsky.feed.generator",
143
Rkey: feedName,
144
Record: registerRecord{
145
-
Did: feedDID,
146
-
DisplayName: feedDisplayName,
147
-
Description: feedDescription,
148
-
CreatedAt: time.Now(),
149
},
150
}
151
···
33
}
34
35
type registerRecord struct {
36
+
Did string `json:"did"`
37
+
DisplayName string `json:"displayName"`
38
+
Description string `json:"description"`
39
+
CreatedAt time.Time `json:"createdAt"`
40
+
AcceptsInteractions bool `json:"acceptsInteractions"`
41
}
42
43
func main() {
···
137
if feedDID == "" {
138
return fmt.Errorf("FEED_DID environment not set")
139
}
140
+
acceptsInteractions := false
141
+
if os.Getenv("ACCEPTS_INTERACTIONS") == "true" {
142
+
acceptsInteractions = true
143
+
}
144
145
reqData := registerFeedGen{
146
Repo: auth.Did,
147
Collection: "app.bsky.feed.generator",
148
Rkey: feedName,
149
Record: registerRecord{
150
+
Did: feedDID,
151
+
DisplayName: feedDisplayName,
152
+
Description: feedDescription,
153
+
CreatedAt: time.Now(),
154
+
AcceptsInteractions: acceptsInteractions,
155
},
156
}
157
+44
handlers.go
+44
handlers.go
···
4
"context"
5
"encoding/json"
6
"fmt"
7
+
"io"
8
"log/slog"
9
"net/http"
10
"net/url"
···
113
_, _ = w.Write(b)
114
}
115
116
+
// FeedInteractions details the interactions that a user had with a feed when they viewed it
117
+
type FeedInteractions struct {
118
+
Interactions []Interaction `json:"interactions"`
119
+
}
120
+
121
+
type Interaction struct {
122
+
Item string `json:"item"`
123
+
Event string `json:"event"`
124
+
}
125
+
126
+
// HandleFeedInteractions will handle when the client sends back a feed interaction so you can improve
127
+
// the feed quality for the user
128
+
func (s *Server) HandleFeedInteractions(w http.ResponseWriter, r *http.Request) {
129
+
slog.Debug("handle feed interactions")
130
+
userDID, err := getRequestUserDID(r)
131
+
if err != nil {
132
+
slog.Error("validate user auth", "error", err)
133
+
http.Error(w, "validate auth", http.StatusUnauthorized)
134
+
return
135
+
}
136
+
137
+
body, err := io.ReadAll(r.Body)
138
+
if err != nil {
139
+
slog.Error("read feed interactions request body", "error", err)
140
+
http.Error(w, "read body", http.StatusBadRequest)
141
+
return
142
+
}
143
+
144
+
var feedInteractions FeedInteractions
145
+
err = json.Unmarshal(body, &feedInteractions)
146
+
if err != nil {
147
+
slog.Error("decode feed interactions request body", "error", err)
148
+
http.Error(w, "decode body", http.StatusBadRequest)
149
+
return
150
+
}
151
+
152
+
// here is where you would likely do something with the data that is sent to you such as improving the
153
+
// data you store for a users feed
154
+
for _, interaction := range feedInteractions.Interactions {
155
+
slog.Info("interaction for user", "user", userDID, "item", interaction.Item, "interaction", interaction.Event)
156
+
}
157
+
}
158
+
159
// WellKnownResponse is what's returned on a well-known endpoint
160
type WellKnownResponse struct {
161
Context []string `json:"@context"`
+1
readme.md
+1
readme.md
···
25
* FEED_DISPLAY_NAME - This is the name you will give your feed that users will be able to see
26
* FEED_DESCRIPTION - This is a description of your feed that users will be able to see
27
* FEED_DID - This is the DID that will be used to register the record. Unless you know what you are doing it's best to use `did:web:` + FEED_HOST_NAME (eg "did:web:demo-feed.com")
28
29
First you need to run the feed generator by building the application `go build -o demo-feed-generator ./cmd/feed-generator/main.go` and then running it `./demo-feed-generator`
30
···
25
* FEED_DISPLAY_NAME - This is the name you will give your feed that users will be able to see
26
* FEED_DESCRIPTION - This is a description of your feed that users will be able to see
27
* FEED_DID - This is the DID that will be used to register the record. Unless you know what you are doing it's best to use `did:web:` + FEED_HOST_NAME (eg "did:web:demo-feed.com")
28
+
* ACCEPTS_INTERACTIONS - Set this to be true if you wish your feed to accepts interactions such as "show more" or "show less"
29
30
First you need to run the feed generator by building the application `go build -o demo-feed-generator ./cmd/feed-generator/main.go` and then running it `./demo-feed-generator`
31
+1
server.go
+1
server.go
···
42
mux := http.NewServeMux()
43
mux.HandleFunc("/xrpc/app.bsky.feed.getFeedSkeleton", srv.HandleGetFeedSkeleton)
44
mux.HandleFunc("/xrpc/app.bsky.feed.describeFeedGenerator", srv.HandleDescribeFeedGenerator)
45
mux.HandleFunc("/.well-known/did.json", srv.HandleWellKnown)
46
addr := fmt.Sprintf("0.0.0.0:%d", port)
47
···
42
mux := http.NewServeMux()
43
mux.HandleFunc("/xrpc/app.bsky.feed.getFeedSkeleton", srv.HandleGetFeedSkeleton)
44
mux.HandleFunc("/xrpc/app.bsky.feed.describeFeedGenerator", srv.HandleDescribeFeedGenerator)
45
+
mux.HandleFunc("POST /xrpc/app.bsky.feed.sendInteractions", srv.HandleFeedInteractions)
46
mux.HandleFunc("/.well-known/did.json", srv.HandleWellKnown)
47
addr := fmt.Sprintf("0.0.0.0:%d", port)
48