diff options
Diffstat (limited to 'backend/fetchers/app.bsky.feed.go')
| -rw-r--r-- | backend/fetchers/app.bsky.feed.go | 138 |
1 files changed, 57 insertions, 81 deletions
diff --git a/backend/fetchers/app.bsky.feed.go b/backend/fetchers/app.bsky.feed.go index 92303fc..abc3b46 100644 --- a/backend/fetchers/app.bsky.feed.go +++ b/backend/fetchers/app.bsky.feed.go @@ -3,130 +3,91 @@ package fetchers import ( "encoding/json" "fmt" - "io" - "llostre/backend/auth" "llostre/backend/general" "llostre/backend/notes" "log/slog" - "net/http" ) -type ListRecordsResponse struct { - Records []notes.AppBskyFeedPostRecord `json:"records"` -} - -func FetchAppBskyFeedPosts(logger *slog.Logger, did, pdsURL, accessToken string, keypair *auth.DPoPKeyPair, notesCache *Cache) ([]notes.Note, error) { - url := fmt.Sprintf("%s/xrpc/com.atproto.repo.listRecords?repo=%s&collection=app.bsky.feed.post", pdsURL, did) - - logger.Debug("generating DPoP proof", "url", url) - dpopProof, err := keypair.GenerateDPoPProof("GET", url, "") - if err != nil { - logger.Error("DPoP generation failed", "error", err) - return nil, err - } - - logger.Debug("making request to PDS") - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err +func FetchAppBskyFeedPosts(logger *slog.Logger, did, pdsURL, slingshotURL string, cache *Cache) ([]notes.Note, error) { + // get author of the note + profile, found := cache.GetProfile(did) + var err error + if !found { + profile, err = FetchProfile(logger, did, pdsURL, slingshotURL, cache) } - req.Header.Set("Authorization", "Bearer "+accessToken) - req.Header.Set("DPoP", dpopProof) - - resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } - defer resp.Body.Close() - var response ListRecordsResponse - if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { - return nil, err + // try slingshot first if given + if slingshotURL != "" { + values, err := general.FetchRawRecordCollection(logger, did, "app.bsky.feed.post", slingshotURL) + if err != nil { + logger.Error("Fetching from slingshot failed") + } else { + return parseAppBskyFeedPostCollection(logger, values, profile, cache) + } } - profile, err := FetchProfile(did, pdsURL, notesCache) + values, err := general.FetchRawRecordCollection(logger, did, "app.bsky.feed.post", pdsURL) if err != nil { - logger.Error("profile fetch failed", "did", did, "error", err) - } else { - logger.Debug("fetched profile") - } - - posts := make([]notes.Note, 0, len(response.Records)) - for _, record := range response.Records { - bp, err := notes.NoteFromAppBskyFeedPostRecord(record, profile) - if err != nil { - logger.Error("failed to convert record", "error", err, "uri", record.URI) - continue - } - notesCache.Set(bp.URI, bp) - posts = append(posts, *bp) + return nil, err } - return posts, nil + return parseAppBskyFeedPostCollection(logger, values, profile, cache) } -func FetchPostByURI(uri, accessToken string, keypair *auth.DPoPKeyPair, cache *Cache) (*notes.Note, error) { +func FetchAppBskyFeedPostByURI(logger *slog.Logger, uri, slingshotURL string, cache *Cache) (*notes.Note, error) { // check cache if cached, found := cache.Get(uri); found { return cached, nil } - repo, collection, rkey, err := general.ParseURI(uri) + repo, _, _, err := general.ParseURI(uri) // need to resolve DID to PDS - pds, err := FetchPDS(repo) + pdsURL, err := FetchPDS(repo) if err != nil { return nil, err } - url := fmt.Sprintf("%s/xrpc/com.atproto.repo.getRecord?repo=%s&collection=%s&rkey=%s", - pds, repo, collection, rkey) - - // fetch with DPoP - dpopProof, err := keypair.GenerateDPoPProof("GET", url, "") + // get author of the note + profile, found := cache.GetProfile(repo) + if !found { + profile, err = FetchProfile(logger, repo, pdsURL, slingshotURL, cache) + } if err != nil { return nil, err } - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err + // try slingshot first if given + if slingshotURL != "" { + rawRecord, err := general.FetchRawRecordByURI(logger, uri, slingshotURL) + if err != nil { + logger.Error("fetching from slingshot failed", "error", err) + } else { + return parseAppBskyFeedPostRecord(rawRecord, profile, cache) + } } - req.Header.Set("Authorization", "Bearer "+accessToken) - req.Header.Set("DPoP", dpopProof) - resp, err := http.DefaultClient.Do(req) + rawRecord, err := general.FetchRawRecordByURI(logger, uri, pdsURL) if err != nil { + logger.Error("Fetching from PDS failed") return nil, err } - defer resp.Body.Close() - if resp.StatusCode != 200 { - body, _ := io.ReadAll(resp.Body) - return nil, fmt.Errorf("PDS returned status %d: %s", resp.StatusCode, string(body)) - } + return parseAppBskyFeedPostRecord(rawRecord, profile, cache) +} - var result struct { - URI string `json:"uri"` - Value json.RawMessage `json:"value"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return nil, err +func parseAppBskyFeedPostRecord(rawRecord *general.RawRecord, profile *general.Profile, cache *Cache) (*notes.Note, error) { + if rawRecord == nil { + return nil, fmt.Errorf("unable to parse nil record") } - // convert to AppBskyFeedPostRecord record := notes.AppBskyFeedPostRecord{ - URI: result.URI, - } - if err := json.Unmarshal(result.Value, &record.Value); err != nil { - return nil, err - } - - // get author of the note - profile, found := cache.GetProfile(repo) - if !found { - profile, err = FetchProfile(repo, pds, cache) + URI: rawRecord.URI, } + err := json.Unmarshal(rawRecord.Value, &record.Value) if err != nil { return nil, err } @@ -141,3 +102,18 @@ func FetchPostByURI(uri, accessToken string, keypair *auth.DPoPKeyPair, cache *C return note, nil } + +func parseAppBskyFeedPostCollection(logger *slog.Logger, records []general.RawRecord, profile *general.Profile, cache *Cache) ([]notes.Note, error) { + posts := make([]notes.Note, 0, len(records)) + for _, record := range records { + note, err := parseAppBskyFeedPostRecord(&record, profile, cache) + if err != nil { + logger.Error("failed to parse post record", "error", err) + continue + } + cache.Set(note.URI, note) + posts = append(posts, *note) + } + + return posts, nil +} |
