A locally focused bluesky appview

missing post fetcher

+1
handlers.go
··· 351 351 352 352 uri := fmt.Sprintf("at://%s/app.bsky.feed.post/%s", r.Did, p.Rkey) 353 353 if len(p.Raw) == 0 || p.NotFound { 354 + s.addMissingPost(ctx, uri) 354 355 posts[ix] = postResponse{ 355 356 Uri: uri, 356 357 Missing: true,
+3
main.go
··· 159 159 dir: dir, 160 160 161 161 missingProfiles: make(chan string, 1024), 162 + missingPosts: make(chan string, 1024), 162 163 } 163 164 164 165 pgb := &PostgresBackend{ ··· 193 194 }() 194 195 195 196 go s.missingProfileFetcher() 197 + go s.missingPostFetcher() 196 198 197 199 seqno, err := loadLastSeq("sequence.txt") 198 200 if err != nil { ··· 219 221 220 222 mpLk sync.Mutex 221 223 missingProfiles chan string 224 + missingPosts chan string 222 225 } 223 226 224 227 func (s *Server) getXrpcClient() (*xrpc.Client, error) {
+64
missing.go
··· 4 4 "bytes" 5 5 "context" 6 6 "fmt" 7 + "strings" 7 8 8 9 "github.com/bluesky-social/indigo/api/atproto" 9 10 "github.com/bluesky-social/indigo/api/bsky" ··· 65 66 66 67 return s.backend.HandleUpdateProfile(ctx, repo, "self", "", buf.Bytes(), cc) 67 68 } 69 + 70 + func (s *Server) addMissingPost(ctx context.Context, uri string) { 71 + select { 72 + case s.missingPosts <- uri: 73 + case <-ctx.Done(): 74 + } 75 + } 76 + 77 + func (s *Server) missingPostFetcher() { 78 + for uri := range s.missingPosts { 79 + if err := s.fetchMissingPost(context.TODO(), uri); err != nil { 80 + log.Warn("failed to fetch missing post", "uri", uri, "error", err) 81 + } 82 + } 83 + } 84 + 85 + func (s *Server) fetchMissingPost(ctx context.Context, uri string) error { 86 + // Parse AT URI: at://did:plc:xxx/app.bsky.feed.post/rkey 87 + parts := strings.Split(uri, "/") 88 + if len(parts) < 5 || !strings.HasPrefix(parts[2], "did:") { 89 + return fmt.Errorf("invalid AT URI: %s", uri) 90 + } 91 + 92 + did := parts[2] 93 + collection := parts[3] 94 + rkey := parts[4] 95 + 96 + repo, err := s.backend.getOrCreateRepo(ctx, did) 97 + if err != nil { 98 + return err 99 + } 100 + 101 + resp, err := s.dir.LookupDID(ctx, syntax.DID(did)) 102 + if err != nil { 103 + return err 104 + } 105 + 106 + c := &xrpc.Client{ 107 + Host: resp.PDSEndpoint(), 108 + } 109 + 110 + rec, err := atproto.RepoGetRecord(ctx, c, "", collection, did, rkey) 111 + if err != nil { 112 + return err 113 + } 114 + 115 + post, ok := rec.Value.Val.(*bsky.FeedPost) 116 + if !ok { 117 + return fmt.Errorf("record we got back wasn't a post somehow") 118 + } 119 + 120 + buf := new(bytes.Buffer) 121 + if err := post.MarshalCBOR(buf); err != nil { 122 + return err 123 + } 124 + 125 + cc, err := cid.Decode(*rec.Cid) 126 + if err != nil { 127 + return err 128 + } 129 + 130 + return s.backend.HandleCreatePost(ctx, repo, rkey, buf.Bytes(), cc) 131 + }