1package engine
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7
8 appbsky "github.com/bluesky-social/indigo/api/bsky"
9 "github.com/bluesky-social/indigo/atproto/syntax"
10)
11
12// Represents app.bsky social graph relationship between a primary account, and an "other" account
13type AccountRelationship struct {
14 // the DID of the "other" account
15 DID syntax.DID
16 // if the primary account is followed by this "other" DID
17 FollowedBy bool
18 // if the primary account follows this "other" DID
19 Following bool
20}
21
22// Helper to fetch social graph relationship metadata
23func (eng *Engine) GetAccountRelationship(ctx context.Context, primary, other syntax.DID) (*AccountRelationship, error) {
24
25 logger := eng.Logger.With("did", primary.String(), "otherDID", other.String())
26
27 cacheKey := fmt.Sprintf("%s/%s", primary.String(), other.String())
28 existing, err := eng.Cache.Get(ctx, "graph-rel", cacheKey)
29 if err != nil {
30 return nil, fmt.Errorf("failed checking account relationship cache: %w", err)
31 }
32 if existing != "" {
33 var ar AccountRelationship
34 err := json.Unmarshal([]byte(existing), &ar)
35 if err != nil || ar.DID != primary {
36 return nil, fmt.Errorf("parsing AccountRelationship from cache: %v", err)
37 }
38 return &ar, nil
39 }
40
41 if eng.BskyClient == nil {
42 logger.Warn("skipping account relationship fetch")
43 ar := AccountRelationship{DID: other}
44 return &ar, nil
45 }
46
47 // fetch account relationship from AppView
48 accountRelationshipFetches.Inc()
49 resp, err := appbsky.GraphGetRelationships(ctx, eng.BskyClient, primary.String(), []string{other.String()})
50 if err != nil || len(resp.Relationships) != 1 {
51 logger.Warn("account relationship lookup failed", "err", err)
52 ar := AccountRelationship{DID: other}
53 return &ar, nil
54 }
55
56 if len(resp.Relationships) != 1 || resp.Relationships[0].GraphDefs_Relationship == nil {
57 logger.Warn("account relationship actor not found")
58 }
59
60 rel := resp.Relationships[0].GraphDefs_Relationship
61 ar := AccountRelationship{
62 DID: primary,
63 FollowedBy: rel.FollowedBy != nil,
64 Following: rel.Following != nil,
65 }
66 return &ar, nil
67}