A demo of a Bluesky feed generator in Go
at 12df7567294b94a475140d080b7be6aaebcd776e 66 lines 1.5 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("/.well-known/did.json", srv.HandleWellKnown) 46 addr := fmt.Sprintf("0.0.0.0:%d", port) 47 48 srv.httpsrv = &http.Server{ 49 Addr: addr, 50 Handler: mux, 51 } 52 return srv, nil 53} 54 55// Run will start the server - it is a blocking function 56func (s *Server) Run() { 57 err := s.httpsrv.ListenAndServe() 58 if err != nil { 59 slog.Error("listen and serve", "error", err) 60 } 61} 62 63// Stop will shutdown the server 64func (s *Server) Stop(ctx context.Context) error { 65 return s.httpsrv.Shutdown(ctx) 66}