aboutsummaryrefslogtreecommitdiff
path: root/backend/fetchers/app.bsky.feed.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/fetchers/app.bsky.feed.go')
-rw-r--r--backend/fetchers/app.bsky.feed.go138
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
+}