try implement sync.GetRecord

This commit is contained in:
Evan Jarrett
2025-10-15 11:08:59 -05:00
parent 74f665f9e0
commit 8a3f88a104
2 changed files with 76 additions and 1 deletions
+1 -1
View File
@@ -12,6 +12,7 @@ require (
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/ipfs/go-cid v0.4.1
github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4
github.com/klauspost/compress v1.18.0
github.com/mattn/go-sqlite3 v1.14.32
github.com/opencontainers/go-digest v1.0.0
@@ -68,7 +69,6 @@ require (
github.com/ipfs/go-merkledag v0.11.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-verifcid v0.0.3 // indirect
github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
+75
View File
@@ -1,10 +1,15 @@
package pds
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/ipfs/go-cid"
"github.com/ipld/go-car"
carutil "github.com/ipld/go-car/util"
)
// XRPC handler for ATProto endpoints
@@ -63,6 +68,7 @@ func (h *XRPCHandler) RegisterHandlers(mux *http.ServeMux) {
// Sync endpoints
mux.HandleFunc("/xrpc/com.atproto.sync.listRepos", corsMiddleware(h.HandleListRepos))
mux.HandleFunc("/xrpc/com.atproto.sync.getRecord", corsMiddleware(h.HandleSyncGetRecord))
// Blob endpoints (wrap existing presigned URL logic)
mux.HandleFunc("/xrpc/com.atproto.repo.uploadBlob", corsMiddleware(h.HandleUploadBlob))
@@ -240,6 +246,75 @@ func (h *XRPCHandler) HandleListRecords(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(response)
}
// HandleSyncGetRecord returns a single record as a CAR file for sync
func (h *XRPCHandler) HandleSyncGetRecord(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
did := r.URL.Query().Get("did")
collection := r.URL.Query().Get("collection")
rkey := r.URL.Query().Get("rkey")
if did == "" || collection == "" || rkey == "" {
http.Error(w, "missing required parameters", http.StatusBadRequest)
return
}
if did != h.pds.DID() {
http.Error(w, "invalid did", http.StatusBadRequest)
return
}
// Only support crew collection for now
if collection != CrewCollection {
http.Error(w, "collection not found", http.StatusNotFound)
return
}
// Get the record CID and raw bytes
recordCID, _, err := h.pds.GetCrewMember(r.Context(), rkey)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get record: %v", err), http.StatusNotFound)
return
}
// Get the raw block from the blockstore
blk, err := h.pds.repo.Blockstore().Get(r.Context(), recordCID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get record block: %v", err), http.StatusInternalServerError)
return
}
// Write CAR file with the single record
w.Header().Set("Content-Type", "application/vnd.ipld.car")
// Create a buffer to write the CAR data
var buf bytes.Buffer
// Create CAR header with the record CID as root
header := &car.CarHeader{
Roots: []cid.Cid{recordCID},
Version: 1,
}
// Write the CAR header
if err := car.WriteHeader(header, &buf); err != nil {
http.Error(w, fmt.Sprintf("failed to write CAR header: %v", err), http.StatusInternalServerError)
return
}
// Write the block using LdWrite
if err := carutil.LdWrite(&buf, recordCID.Bytes(), blk.RawData()); err != nil {
http.Error(w, fmt.Sprintf("failed to write block to CAR: %v", err), http.StatusInternalServerError)
return
}
// Write the CAR data to the response
w.Write(buf.Bytes())
}
// HandleUploadBlob wraps existing presigned upload URL logic
func (h *XRPCHandler) HandleUploadBlob(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {