this repo has no description
13
fork

Configure Feed

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

initial work on PDSClient

+134
+45
atproto/pdsclient/examples_test.go
··· 1 + package pdsclient 2 + 3 + import ( 4 + "bytes" 5 + "context" 6 + "fmt" 7 + 8 + "github.com/bluesky-social/indigo/atproto/client" 9 + "github.com/bluesky-social/indigo/atproto/syntax" 10 + ) 11 + 12 + func ExamplePDSClient_CreateRecord() { 13 + ctx := context.Background() 14 + pc := PDSClient{ 15 + APIClient: client.NewAPIClient("https://pds.example.com"), 16 + AccountDID: syntax.DID("did:web:example.com"), 17 + } 18 + 19 + record := map[string]any{ 20 + "$type": "com.example.record", 21 + "text": "hello world", 22 + } 23 + 24 + aturi, cstr, err := pc.CreateRecord(ctx, syntax.NSID("com.example.record"), "", record) 25 + if err != nil { 26 + panic("failed to create record: " + err.Error()) 27 + } 28 + fmt.Printf("%s\t%s\n", aturi, cstr) 29 + } 30 + 31 + func ExamplePDSClient_UploadBlob() { 32 + ctx := context.Background() 33 + pc := PDSClient{ 34 + APIClient: client.NewAPIClient("https://pds.example.com"), 35 + AccountDID: syntax.DID("did:web:example.com"), 36 + } 37 + 38 + bdata := bytes.NewBuffer([]byte("text string")) 39 + 40 + blob, err := pc.UploadBlob(ctx, "text/plain", bdata) 41 + if err != nil { 42 + panic("failed to upload blob: " + err.Error()) 43 + } 44 + fmt.Printf("%s\t%d\n", blob.Ref, blob.Size) 45 + }
+89
atproto/pdsclient/pdsclient.go
··· 1 + package pdsclient 2 + 3 + import ( 4 + "context" 5 + "encoding/json" 6 + "fmt" 7 + "io" 8 + "net/http" 9 + 10 + "github.com/bluesky-social/indigo/atproto/client" 11 + "github.com/bluesky-social/indigo/atproto/data" 12 + "github.com/bluesky-social/indigo/atproto/syntax" 13 + ) 14 + 15 + type PDSClient struct { 16 + *client.APIClient 17 + 18 + AccountDID syntax.DID 19 + } 20 + 21 + type createRecordBody struct { 22 + Repo syntax.DID `json:"repo"` 23 + Collection syntax.NSID `json:"collection"` 24 + RKey *syntax.RecordKey `json:"rkey,omitempty"` 25 + Record any `json:"record"` 26 + } 27 + 28 + type createRecordResp struct { 29 + CID syntax.CID `json:"cid"` 30 + URI syntax.ATURI `json:"uri"` 31 + ValidationStatus *string `json:"validationStatus,omitempty"` 32 + } 33 + 34 + // rkey is optional (pass empty string for server to create value) 35 + func (pc *PDSClient) CreateRecord(ctx context.Context, collection syntax.NSID, rkey syntax.RecordKey, record any) (syntax.ATURI, syntax.CID, error) { 36 + 37 + body := createRecordBody{ 38 + Repo: pc.AccountDID, 39 + Collection: collection, 40 + Record: record, 41 + } 42 + if rkey != "" { 43 + body.RKey = &rkey 44 + } 45 + 46 + var out createRecordResp 47 + endpoint := syntax.NSID("com.atproto.repo.createRecord") 48 + if err := pc.APIClient.Post(ctx, endpoint, body, out); err != nil { 49 + return "", "", err 50 + } 51 + return out.URI, out.CID, nil 52 + } 53 + 54 + // TODO: PutRecrod 55 + // TODO: DeleteRecord 56 + // TODO: GetRecord 57 + // TODO: ApplyWrites (?) 58 + 59 + type uploadBlobResp struct { 60 + Blob data.Blob `json:"blob"` 61 + } 62 + 63 + func (pc *PDSClient) UploadBlob(ctx context.Context, mimeType string, input io.Reader) (*data.Blob, error) { 64 + 65 + endpoint := syntax.NSID("com.atproto.repo.uploadBlob") 66 + req := client.NewAPIRequest(http.MethodPost, endpoint, input) 67 + req.Headers.Set("Accept", "application/json") 68 + req.Headers.Set("Content-Type", mimeType) 69 + 70 + resp, err := pc.APIClient.Do(ctx, req) 71 + if err != nil { 72 + return nil, err 73 + } 74 + defer resp.Body.Close() 75 + 76 + if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { 77 + var eb client.ErrorBody 78 + if err := json.NewDecoder(resp.Body).Decode(&eb); err != nil { 79 + return nil, &client.APIError{StatusCode: resp.StatusCode} 80 + } 81 + return nil, eb.APIError(resp.StatusCode) 82 + } 83 + 84 + var out uploadBlobResp 85 + if err := json.NewDecoder(resp.Body).Decode(out); err != nil { 86 + return nil, fmt.Errorf("failed decoding JSON response body: %w", err) 87 + } 88 + return &out.Blob, nil 89 + }