package general import ( "encoding/json" "fmt" "io" "llostre/auth" "log/slog" "net/http" ) type RawRecord struct { URI string `json:"uri"` Value json.RawMessage `json:"value"` } func FetchRawRecordCollection(logger *slog.Logger, did, collection, baseURL string, session *auth.OAuthState) ([]RawRecord, error) { url := fmt.Sprintf("%s/xrpc/com.atproto.repo.listRecords?repo=%s&collection=%s", baseURL, did, collection) logger.Debug("fetching raw record collection", "did", did, "endpoint", baseURL, "collection", collection) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } // only add auth if provided if session != nil { dpopProof, err := session.KeyPair.GenerateDPoPProof("GET", url, "") if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+session.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("server returned %d: %s", resp.StatusCode, string(body)) } var result struct { Records []RawRecord `json:"records"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result.Records, nil } func FetchRawRecordCollectionWithCursor(logger *slog.Logger, did, collection, baseURL string, session *auth.OAuthState, cursor string, limit int) ([]RawRecord, string, error) { url := fmt.Sprintf("%s/xrpc/com.atproto.repo.listRecords?repo=%s&collection=%s", baseURL, did, collection) if cursor != "" { url += "&cursor=" + cursor } if limit > 0 { url += fmt.Sprintf("&limit=%d", limit) } logger.Debug("fetching raw record collection", "did", did, "endpoint", baseURL, "collection", collection, "cursor", cursor) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, "", err } if session != nil { dpopProof, err := session.KeyPair.GenerateDPoPProof("GET", url, "") if err != nil { return nil, "", err } req.Header.Set("Authorization", "Bearer "+session.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("server returned %d: %s", resp.StatusCode, string(body)) } var result struct { Records []RawRecord `json:"records"` Cursor string `json:"cursor"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, "", err } return result.Records, result.Cursor, nil } func FetchRawRecordByURI(logger *slog.Logger, uri, baseURL string, session *auth.OAuthState) (*RawRecord, error) { repo, collection, rkey, err := ParseURI(uri) if err != nil { return nil, err } url := fmt.Sprintf("%s/xrpc/com.atproto.repo.getRecord?repo=%s&collection=%s&rkey=%s", baseURL, repo, collection, rkey) logger.Debug("fetching raw record by URI", "uri", uri, "endpoint", baseURL) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } // only add auth if provided if session != nil { dpopProof, err := session.KeyPair.GenerateDPoPProof("GET", url, "") if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+session.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("endpoint returned %d: %s", resp.StatusCode, string(body)) } var result RawRecord if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return &result, nil }