aboutsummaryrefslogtreecommitdiff
path: root/backend/fetchers/app.bsky.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/fetchers/app.bsky.go')
-rw-r--r--backend/fetchers/app.bsky.go83
1 files changed, 81 insertions, 2 deletions
diff --git a/backend/fetchers/app.bsky.go b/backend/fetchers/app.bsky.go
index 6b25f0b..069a183 100644
--- a/backend/fetchers/app.bsky.go
+++ b/backend/fetchers/app.bsky.go
@@ -3,7 +3,9 @@ package fetchers
import (
"encoding/json"
"fmt"
+ "io"
"llostre/backend/auth"
+ "llostre/backend/general"
"llostre/backend/notes"
"log/slog"
"net/http"
@@ -28,7 +30,7 @@ func FetchAppBskyFeedPosts(logger *slog.Logger, did, pdsURL, accessToken string,
if err != nil {
return nil, err
}
- req.Header.Set("Authorization", "Bearer " + accessToken)
+ req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("DPoP", dpopProof)
resp, err := http.DefaultClient.Do(req)
@@ -42,7 +44,7 @@ func FetchAppBskyFeedPosts(logger *slog.Logger, did, pdsURL, accessToken string,
return nil, err
}
- profile, err := FetchProfile(did, pdsURL)
+ profile, err := FetchProfile(did, pdsURL, notesCache)
if err != nil {
logger.Error("profile fetch failed", "did", did, "error", err)
} else {
@@ -62,3 +64,80 @@ func FetchAppBskyFeedPosts(logger *slog.Logger, did, pdsURL, accessToken string,
return posts, nil
}
+
+func FetchPostByURI(uri, accessToken string, keypair *auth.DPoPKeyPair, cache *Cache) (*notes.Note, error) {
+ // check cache
+ if cached, found := cache.Get(uri); found {
+ return cached, nil
+ }
+
+ repo, collection, rkey, err := general.ParseURI(uri)
+
+ // need to resolve DID to PDS
+ pds, 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, "")
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ 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()
+
+ if resp.StatusCode != 200 {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("PDS returned status %d: %s", resp.StatusCode, string(body))
+ }
+
+ 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
+ }
+
+ // 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)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ note, err := notes.AppBskyFeedPostFromRecord(record, profile)
+ if err != nil {
+ return nil, err
+ }
+
+ // cache it
+ cache.Set(note.URI, note)
+
+ return note, nil
+}