Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118package deliberi
import ( "context" "encoding/json" "fmt" "net/http" "strings" "time"
"github.com/bluesky-social/indigo/atproto/syntax" indigoxrpc "github.com/bluesky-social/indigo/xrpc" "github.com/samber/lo" "tangled.org/core/api/org_tangled" "tangled.org/core/api/tangled")
type recipientResolver interface { ListRecipients(ctx context.Context, uri string, collection string) ([]string, error) RepoOwner(ctx context.Context, repoDid string) (ownerDid, name string, err error)}
type inviteLister interface { ListCollaboratorInvitesBy(ctx context.Context, subjectDid string) (InviteAnswer, error)}
type InviteOffer struct { Uri string `json:"uri"` KnotDid string `json:"knot"` RepoDid string `json:"repo"` AddedBy string `json:"addedBy"` CreatedAt time.Time `json:"createdAt"`}
type InviteAnswer struct { Offers []InviteOffer `json:"items"` Pending []string `json:"pending"` Truncated bool `json:"truncated"`}
type bobbinClient struct { xc *indigoxrpc.Client}
func newBobbinClient(apiUrl string) *bobbinClient { return &bobbinClient{ xc: &indigoxrpc.Client{ Host: strings.TrimRight(apiUrl, "/"), Client: &http.Client{Timeout: 10 * time.Second}, }, }}
func (c *bobbinClient) ListRecipients(ctx context.Context, uri string, collection string) ([]string, error) { out, err := org_tangled.TempNotificationListRecipients(ctx, c.xc, collection, uri) if err != nil { return nil, fmt.Errorf("calling %s: %w", org_tangled.TempNotificationListRecipientsNSID, err) } return out.Dids, nil}
// repoByRepoDid mirrors sh.tangled.repo.getRepoByRepoDid's output, but keeps the// record raw: the owner comes from the uri's authority, so a record we can't// type-decode still resolves an owner.type repoByRepoDid struct { Uri string `json:"uri"` Value json.RawMessage `json:"value"`}
// RepoOwner resolves a repo DID to the did that holds its sh.tangled.repo// record, along with the repo's cosmetic name.func (c *bobbinClient) RepoOwner(ctx context.Context, repoDid string) (string, string, error) { var out repoByRepoDid params := map[string]any{"repoDid": repoDid} if err := c.xc.Do(ctx, indigoxrpc.Query, "", tangled.RepoGetRepoByRepoDidNSID, params, nil, &out); err != nil { return "", "", fmt.Errorf("calling %s: %w", tangled.RepoGetRepoByRepoDidNSID, err) }
owner := syntax.ATURI(out.Uri).Authority().String() if owner == "" { return "", "", fmt.Errorf("no authority in uri %q", out.Uri) }
// the name is cosmetic, so a decode failure is not fatal. var rec struct { Name string `json:"name"` } _ = json.Unmarshal(out.Value, &rec)
return owner, rec.Name, nil}
const repoListCollaboratorInvitesByNSID = "sh.tangled.repo.listCollaboratorInvitesBy"
func (c *bobbinClient) ListCollaboratorInvitesBy(ctx context.Context, subjectDid string) (InviteAnswer, error) { var out InviteAnswer params := map[string]any{"subject": subjectDid} if err := c.xc.Do(ctx, indigoxrpc.Query, "", repoListCollaboratorInvitesByNSID, params, nil, &out); err != nil { return InviteAnswer{}, fmt.Errorf("calling %s: %w", repoListCollaboratorInvitesByNSID, err) }
if blank, found := lo.Find(out.Offers, func(offer InviteOffer) bool { return offer.Uri == "" || offer.KnotDid == "" || offer.RepoDid == "" }); found { missing := "record" if blank.Uri != "" { missing = lo.Ternary(blank.KnotDid == "", "knot", "repo") } return InviteAnswer{}, fmt.Errorf( "%s served offer missing its %s, so we couldn't tell it apart from a withdrawal", repoListCollaboratorInvitesByNSID, missing, ) }
return out, nil}