this repo has no description
0
fork

Configure Feed

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

goat: generic record data (#751)

Little hack to make `goat` work better with generic record data, aka
when we don't know the Lexicon. In this context, just dumping the JSON
to stdout (pretty printed).

Sharing b/c we might want to do this generally, at least for API
endpoints: `json.RawMessage` instead of `lexutil.LexiconTypeDecoder`
when we encounter `unknown` schema type. Note that this won't work for
records, and the schema rules do allow `unknown` in records, it just
hasn't happened yet.

Another place we encounter this is DID documents, which don't even have
`$type` in the JSON.

authored by

bnewbold and committed by
GitHub
f9efd8cf 0de3e30f

+106 -20
+9 -18
cmd/goat/net.go
··· 3 3 import ( 4 4 "context" 5 5 "fmt" 6 - "io" 7 6 "log/slog" 8 - "net/http" 9 7 10 8 "github.com/bluesky-social/indigo/atproto/data" 11 9 "github.com/bluesky-social/indigo/atproto/identity" 12 10 "github.com/bluesky-social/indigo/atproto/syntax" 11 + "github.com/bluesky-social/indigo/xrpc" 13 12 ) 14 13 15 14 func fetchRecord(ctx context.Context, ident identity.Identity, aturi syntax.ATURI) (any, error) { 16 - pdsURL := ident.PDSEndpoint() 17 15 18 16 slog.Debug("fetching record", "did", ident.DID.String(), "collection", aturi.Collection().String(), "rkey", aturi.RecordKey().String()) 19 - url := fmt.Sprintf("%s/xrpc/com.atproto.repo.getRecord?repo=%s&collection=%s&rkey=%s", 20 - pdsURL, ident.DID, aturi.Collection(), aturi.RecordKey()) 21 - resp, err := http.Get(url) 22 - if err != nil { 23 - return nil, err 17 + xrpcc := xrpc.Client{ 18 + Host: ident.PDSEndpoint(), 24 19 } 25 - if resp.StatusCode != http.StatusOK { 26 - return nil, fmt.Errorf("fetch failed") 27 - } 28 - respBytes, err := io.ReadAll(resp.Body) 20 + resp, err := RepoGetRecord(ctx, &xrpcc, "", aturi.Collection().String(), ident.DID.String(), aturi.RecordKey().String()) 29 21 if err != nil { 30 22 return nil, err 31 23 } 32 24 33 - body, err := data.UnmarshalJSON(respBytes) 25 + if nil == resp.Value { 26 + return nil, fmt.Errorf("empty record in response") 27 + } 28 + record, err := data.UnmarshalJSON(*resp.Value) 34 29 if err != nil { 35 - return nil, err 36 - } 37 - record, ok := body["value"].(map[string]any) 38 - if !ok { 39 - return nil, fmt.Errorf("fetched record was not an object") 30 + return nil, fmt.Errorf("fetched record was invalid data: %w", err) 40 31 } 41 32 return record, nil 42 33 }
+2 -2
cmd/goat/record.go
··· 180 180 cursor := "" 181 181 for { 182 182 // collection string, cursor string, limit int64, repo string, reverse bool, rkeyEnd string, rkeyStart string 183 - resp, err := comatproto.RepoListRecords(ctx, &xrpcc, nsid, cursor, 100, ident.DID.String(), false, "", "") 183 + resp, err := RepoListRecords(ctx, &xrpcc, nsid, cursor, 100, ident.DID.String(), false, "", "") 184 184 if err != nil { 185 185 return err 186 186 } ··· 295 295 rkey := cctx.String("rkey") 296 296 297 297 // NOTE: need to fetch existing record CID to perform swap. this is optional in theory, but golang can't deal with "optional" and "nullable", so we always need to set this (?) 298 - existing, err := comatproto.RepoGetRecord(ctx, xrpcc, "", nsid, xrpcc.Auth.Did, rkey) 298 + existing, err := RepoGetRecord(ctx, xrpcc, "", nsid, xrpcc.Auth.Did, rkey) 299 299 if err != nil { 300 300 return err 301 301 }
+42
cmd/goat/repogetRecord.go
··· 1 + // Copied from indigo:api/atproto/repolistRecords.go 2 + 3 + package main 4 + 5 + // schema: com.atproto.repo.getRecord 6 + 7 + import ( 8 + "context" 9 + "encoding/json" 10 + 11 + "github.com/bluesky-social/indigo/xrpc" 12 + ) 13 + 14 + // RepoGetRecord_Output is the output of a com.atproto.repo.getRecord call. 15 + type RepoGetRecord_Output struct { 16 + Cid *string `json:"cid,omitempty" cborgen:"cid,omitempty"` 17 + Uri string `json:"uri" cborgen:"uri"` 18 + // NOTE: changed from lex decoder to json.RawMessage 19 + Value *json.RawMessage `json:"value" cborgen:"value"` 20 + } 21 + 22 + // RepoGetRecord calls the XRPC method "com.atproto.repo.getRecord". 23 + // 24 + // cid: The CID of the version of the record. If not specified, then return the most recent version. 25 + // collection: The NSID of the record collection. 26 + // repo: The handle or DID of the repo. 27 + // rkey: The Record Key. 28 + func RepoGetRecord(ctx context.Context, c *xrpc.Client, cid string, collection string, repo string, rkey string) (*RepoGetRecord_Output, error) { 29 + var out RepoGetRecord_Output 30 + 31 + params := map[string]interface{}{ 32 + "cid": cid, 33 + "collection": collection, 34 + "repo": repo, 35 + "rkey": rkey, 36 + } 37 + if err := c.Do(ctx, xrpc.Query, "", "com.atproto.repo.getRecord", params, nil, &out); err != nil { 38 + return nil, err 39 + } 40 + 41 + return &out, nil 42 + }
+53
cmd/goat/repolistRecords.go
··· 1 + // Copied from indigo:api/atproto/repolistRecords.go 2 + 3 + package main 4 + 5 + // schema: com.atproto.repo.listRecords 6 + 7 + import ( 8 + "context" 9 + "encoding/json" 10 + 11 + "github.com/bluesky-social/indigo/xrpc" 12 + ) 13 + 14 + // RepoListRecords_Output is the output of a com.atproto.repo.listRecords call. 15 + type RepoListRecords_Output struct { 16 + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` 17 + Records []*RepoListRecords_Record `json:"records" cborgen:"records"` 18 + } 19 + 20 + // RepoListRecords_Record is a "record" in the com.atproto.repo.listRecords schema. 21 + type RepoListRecords_Record struct { 22 + Cid string `json:"cid" cborgen:"cid"` 23 + Uri string `json:"uri" cborgen:"uri"` 24 + // NOTE: changed from lex decoder to json.RawMessage 25 + Value *json.RawMessage `json:"value" cborgen:"value"` 26 + } 27 + 28 + // RepoListRecords calls the XRPC method "com.atproto.repo.listRecords". 29 + // 30 + // collection: The NSID of the record type. 31 + // limit: The number of records to return. 32 + // repo: The handle or DID of the repo. 33 + // reverse: Flag to reverse the order of the returned records. 34 + // rkeyEnd: DEPRECATED: The highest sort-ordered rkey to stop at (exclusive) 35 + // rkeyStart: DEPRECATED: The lowest sort-ordered rkey to start from (exclusive) 36 + func RepoListRecords(ctx context.Context, c *xrpc.Client, collection string, cursor string, limit int64, repo string, reverse bool, rkeyEnd string, rkeyStart string) (*RepoListRecords_Output, error) { 37 + var out RepoListRecords_Output 38 + 39 + params := map[string]interface{}{ 40 + "collection": collection, 41 + "cursor": cursor, 42 + "limit": limit, 43 + "repo": repo, 44 + "reverse": reverse, 45 + "rkeyEnd": rkeyEnd, 46 + "rkeyStart": rkeyStart, 47 + } 48 + if err := c.Do(ctx, xrpc.Query, "", "com.atproto.repo.listRecords", params, nil, &out); err != nil { 49 + return nil, err 50 + } 51 + 52 + return &out, nil 53 + }