A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
73
fork

Configure Feed

Select the types of activity you want to include in your feed.

try implement sync.GetRecord

+76 -1
+1 -1
go.mod
··· 12 12 github.com/gorilla/mux v1.8.1 13 13 github.com/gorilla/websocket v1.5.3 14 14 github.com/ipfs/go-cid v0.4.1 15 + github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 15 16 github.com/klauspost/compress v1.18.0 16 17 github.com/mattn/go-sqlite3 v1.14.32 17 18 github.com/opencontainers/go-digest v1.0.0 ··· 68 69 github.com/ipfs/go-merkledag v0.11.0 // indirect 69 70 github.com/ipfs/go-metrics-interface v0.0.1 // indirect 70 71 github.com/ipfs/go-verifcid v0.0.3 // indirect 71 - github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 // indirect 72 72 github.com/ipld/go-codec-dagpb v1.6.0 // indirect 73 73 github.com/ipld/go-ipld-prime v0.21.0 // indirect 74 74 github.com/jackc/pgpassfile v1.0.0 // indirect
+75
pkg/hold/pds/xrpc.go
··· 1 1 package pds 2 2 3 3 import ( 4 + "bytes" 4 5 "encoding/json" 5 6 "fmt" 6 7 "net/http" 7 8 "strings" 9 + 10 + "github.com/ipfs/go-cid" 11 + "github.com/ipld/go-car" 12 + carutil "github.com/ipld/go-car/util" 8 13 ) 9 14 10 15 // XRPC handler for ATProto endpoints ··· 63 68 64 69 // Sync endpoints 65 70 mux.HandleFunc("/xrpc/com.atproto.sync.listRepos", corsMiddleware(h.HandleListRepos)) 71 + mux.HandleFunc("/xrpc/com.atproto.sync.getRecord", corsMiddleware(h.HandleSyncGetRecord)) 66 72 67 73 // Blob endpoints (wrap existing presigned URL logic) 68 74 mux.HandleFunc("/xrpc/com.atproto.repo.uploadBlob", corsMiddleware(h.HandleUploadBlob)) ··· 238 244 239 245 w.Header().Set("Content-Type", "application/json") 240 246 json.NewEncoder(w).Encode(response) 247 + } 248 + 249 + // HandleSyncGetRecord returns a single record as a CAR file for sync 250 + func (h *XRPCHandler) HandleSyncGetRecord(w http.ResponseWriter, r *http.Request) { 251 + if r.Method != http.MethodGet { 252 + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) 253 + return 254 + } 255 + 256 + did := r.URL.Query().Get("did") 257 + collection := r.URL.Query().Get("collection") 258 + rkey := r.URL.Query().Get("rkey") 259 + 260 + if did == "" || collection == "" || rkey == "" { 261 + http.Error(w, "missing required parameters", http.StatusBadRequest) 262 + return 263 + } 264 + 265 + if did != h.pds.DID() { 266 + http.Error(w, "invalid did", http.StatusBadRequest) 267 + return 268 + } 269 + 270 + // Only support crew collection for now 271 + if collection != CrewCollection { 272 + http.Error(w, "collection not found", http.StatusNotFound) 273 + return 274 + } 275 + 276 + // Get the record CID and raw bytes 277 + recordCID, _, err := h.pds.GetCrewMember(r.Context(), rkey) 278 + if err != nil { 279 + http.Error(w, fmt.Sprintf("failed to get record: %v", err), http.StatusNotFound) 280 + return 281 + } 282 + 283 + // Get the raw block from the blockstore 284 + blk, err := h.pds.repo.Blockstore().Get(r.Context(), recordCID) 285 + if err != nil { 286 + http.Error(w, fmt.Sprintf("failed to get record block: %v", err), http.StatusInternalServerError) 287 + return 288 + } 289 + 290 + // Write CAR file with the single record 291 + w.Header().Set("Content-Type", "application/vnd.ipld.car") 292 + 293 + // Create a buffer to write the CAR data 294 + var buf bytes.Buffer 295 + 296 + // Create CAR header with the record CID as root 297 + header := &car.CarHeader{ 298 + Roots: []cid.Cid{recordCID}, 299 + Version: 1, 300 + } 301 + 302 + // Write the CAR header 303 + if err := car.WriteHeader(header, &buf); err != nil { 304 + http.Error(w, fmt.Sprintf("failed to write CAR header: %v", err), http.StatusInternalServerError) 305 + return 306 + } 307 + 308 + // Write the block using LdWrite 309 + if err := carutil.LdWrite(&buf, recordCID.Bytes(), blk.RawData()); err != nil { 310 + http.Error(w, fmt.Sprintf("failed to write block to CAR: %v", err), http.StatusInternalServerError) 311 + return 312 + } 313 + 314 + // Write the CAR data to the response 315 + w.Write(buf.Bytes()) 241 316 } 242 317 243 318 // HandleUploadBlob wraps existing presigned upload URL logic