A demo of a Bluesky feed generator in Go
at feed-interactions 67 lines 1.6 kB view raw
1package feed 2 3import ( 4 "context" 5 _ "embed" 6 "fmt" 7 "log/slog" 8 "net/http" 9) 10 11// Post describes a Bluesky post 12type Post struct { 13 ID int 14 RKey string 15 PostURI string 16 UserDID string 17 CreatedAt int64 18} 19 20// PostStore defines the interactions with a store 21type PostStore interface { 22 GetFeedPosts(cursor, limit int) ([]Post, error) 23 CreatePost(post Post) error 24} 25 26// Server is the feed server that will be called when a user requests to view a feed 27type Server struct { 28 httpsrv *http.Server 29 postStore PostStore 30 feedHost string 31 feedName string 32} 33 34// NewServer builds a server - call the Run function to start the server 35func NewServer(port int, feedHost, feedName string, postStore PostStore) (*Server, error) { 36 srv := &Server{ 37 feedHost: feedHost, 38 feedName: feedName, 39 postStore: postStore, 40 } 41 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 49 srv.httpsrv = &http.Server{ 50 Addr: addr, 51 Handler: mux, 52 } 53 return srv, nil 54} 55 56// Run will start the server - it is a blocking function 57func (s *Server) Run() { 58 err := s.httpsrv.ListenAndServe() 59 if err != nil { 60 slog.Error("listen and serve", "error", err) 61 } 62} 63 64// Stop will shutdown the server 65func (s *Server) Stop(ctx context.Context) error { 66 return s.httpsrv.Shutdown(ctx) 67}