this repo has no description
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "log/slog"
7 "net/http"
8 "strconv"
9)
10
11type FeedReponse struct {
12 Cursor string `json:"cursor"`
13 Feed []FeedItem `json:"feed"`
14}
15
16type FeedItem struct {
17 Post string `json:"post"`
18 FeedContext string `json:"feedContext"`
19}
20
21type WellKnownResponse struct {
22 Context []string `json:"@context"`
23 Id string `json:"id"`
24 Service []WellKnownService `json:"service"`
25}
26
27type WellKnownService struct {
28 Id string `json:"id"`
29 Type string `json:"type"`
30 ServiceEndpoint string `json:"serviceEndpoint"`
31}
32
33func (s *Server) HandleGetFeedSkeleton(w http.ResponseWriter, r *http.Request) {
34 slog.Info("got request for feed skeleton", "host", r.RemoteAddr)
35 params := r.URL.Query()
36
37 feed := params.Get("feed")
38 if feed == "" {
39 slog.Error("missing feed query param", "host", r.RemoteAddr)
40 http.Error(w, "missing feed query param", http.StatusBadRequest)
41 return
42 }
43 slog.Info("request for feed", "feed", feed)
44
45 limitStr := params.Get("limit")
46 limit := 50
47 if limitStr != "" {
48 var err error
49 limit, err = strconv.Atoi(limitStr)
50 if err != nil {
51 slog.Error("convert limit query param", "error", err)
52 http.Error(w, "invalid limit query param", http.StatusBadRequest)
53 return
54 }
55 if limit < 1 || limit > 100 {
56 limit = 50
57 }
58 }
59
60 cursor := params.Get("cursor")
61 usersDID, err := getRequestUserDID(r)
62 if err != nil {
63 slog.Error("validate auth", "error", err)
64 http.Error(w, "validate auth", http.StatusUnauthorized)
65 return
66 }
67 if usersDID == "" {
68 slog.Error("missing users DID from request")
69 http.Error(w, "validate auth", http.StatusUnauthorized)
70 return
71 }
72
73 resp, err := s.feeder.GetFeed(r.Context(), usersDID, feed, cursor, limit)
74 if err != nil {
75 slog.Error("get feed", "error", err, "feed", feed)
76 http.Error(w, "error getting feed", http.StatusInternalServerError)
77 return
78 }
79
80 b, err := json.Marshal(resp)
81 if err != nil {
82 slog.Error("marshall error", "error", err, "host", r.RemoteAddr)
83 http.Error(w, "failed to encode resp", http.StatusInternalServerError)
84 return
85 }
86
87 w.Header().Set("Content-Type", "application/json")
88
89 _, _ = w.Write(b)
90}
91
92type DescribeFeedResponse struct {
93 DID string `json:"did"`
94 Feeds []FeedRespsonse `json:"feeds"`
95}
96
97type FeedRespsonse struct {
98 URI string `json:"uri"`
99}
100
101func (s *Server) HandleDescribeFeedGenerator(w http.ResponseWriter, r *http.Request) {
102 slog.Info("got request for describe feed", "host", r.RemoteAddr)
103 resp := DescribeFeedResponse{
104 DID: fmt.Sprintf("did:web:%s", s.feedHost),
105 Feeds: []FeedRespsonse{
106 {
107 URI: fmt.Sprintf("at://%s/app.bsky.feed.generator/bookmark-replies", s.feedDidBase),
108 },
109 {
110 URI: fmt.Sprintf("at://%s/app.bsky.feed.generator/bookmarks", s.feedDidBase),
111 },
112 },
113 }
114
115 b, err := json.Marshal(resp)
116 if err != nil {
117 http.Error(w, "failed to encode resp", http.StatusInternalServerError)
118 return
119 }
120
121 _, _ = w.Write(b)
122}
123
124func (s *Server) HandleWellKnown(w http.ResponseWriter, r *http.Request) {
125 slog.Info("got request for well known", "host", r.RemoteAddr)
126 resp := WellKnownResponse{
127 Context: []string{"https://www.w3.org/ns/did/v1"},
128 Id: fmt.Sprintf("did:web:%s", s.feedHost),
129 Service: []WellKnownService{
130 {
131 Id: "#bsky_fg",
132 Type: "BskyFeedGenerator",
133 ServiceEndpoint: fmt.Sprintf("https://%s", s.feedHost),
134 },
135 },
136 }
137
138 b, err := json.Marshal(resp)
139 if err != nil {
140 http.Error(w, "failed to encode resp", http.StatusInternalServerError)
141 return
142 }
143
144 _, _ = w.Write(b)
145}