+1
.env-example
+1
.env-example
+14
-8
cmd/register-feed/main.go
+14
-8
cmd/register-feed/main.go
···
33
33
}
34
34
35
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"`
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"`
40
41
}
41
42
42
43
func main() {
···
136
137
if feedDID == "" {
137
138
return fmt.Errorf("FEED_DID environment not set")
138
139
}
140
+
acceptsInteractions := false
141
+
if os.Getenv("ACCEPTS_INTERACTIONS") == "true" {
142
+
acceptsInteractions = true
143
+
}
139
144
140
145
reqData := registerFeedGen{
141
146
Repo: auth.Did,
142
147
Collection: "app.bsky.feed.generator",
143
148
Rkey: feedName,
144
149
Record: registerRecord{
145
-
Did: feedDID,
146
-
DisplayName: feedDisplayName,
147
-
Description: feedDescription,
148
-
CreatedAt: time.Now(),
150
+
Did: feedDID,
151
+
DisplayName: feedDisplayName,
152
+
Description: feedDescription,
153
+
CreatedAt: time.Now(),
154
+
AcceptsInteractions: acceptsInteractions,
149
155
},
150
156
}
151
157
+44
handlers.go
+44
handlers.go
···
4
4
"context"
5
5
"encoding/json"
6
6
"fmt"
7
+
"io"
7
8
"log/slog"
8
9
"net/http"
9
10
"net/url"
···
112
113
_, _ = w.Write(b)
113
114
}
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
+
115
159
// WellKnownResponse is what's returned on a well-known endpoint
116
160
type WellKnownResponse struct {
117
161
Context []string `json:"@context"`
+1
readme.md
+1
readme.md
···
25
25
* FEED_DISPLAY_NAME - This is the name you will give your feed that users will be able to see
26
26
* FEED_DESCRIPTION - This is a description of your feed that users will be able to see
27
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"
28
29
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`
30
31
+1
server.go
+1
server.go
···
42
42
mux := http.NewServeMux()
43
43
mux.HandleFunc("/xrpc/app.bsky.feed.getFeedSkeleton", srv.HandleGetFeedSkeleton)
44
44
mux.HandleFunc("/xrpc/app.bsky.feed.describeFeedGenerator", srv.HandleDescribeFeedGenerator)
45
+
mux.HandleFunc("POST /xrpc/app.bsky.feed.sendInteractions", srv.HandleFeedInteractions)
45
46
mux.HandleFunc("/.well-known/did.json", srv.HandleWellKnown)
46
47
addr := fmt.Sprintf("0.0.0.0:%d", port)
47
48