forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1package idresolver 2 3import ( 4 "context" 5 "net" 6 "net/http" 7 "sync" 8 "time" 9 10 "github.com/bluesky-social/indigo/atproto/identity" 11 "github.com/bluesky-social/indigo/atproto/identity/redisdir" 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 "github.com/carlmjohnson/versioninfo" 14) 15 16type Resolver struct { 17 directory identity.Directory 18} 19 20func BaseDirectory(plcUrl string) identity.Directory { 21 base := identity.BaseDirectory{ 22 PLCURL: plcUrl, 23 HTTPClient: http.Client{ 24 Timeout: time.Second * 10, 25 Transport: &http.Transport{ 26 // would want this around 100ms for services doing lots of handle resolution. Impacts PLC connections as well, but not too bad. 27 IdleConnTimeout: time.Millisecond * 1000, 28 MaxIdleConns: 100, 29 }, 30 }, 31 Resolver: net.Resolver{ 32 Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 33 d := net.Dialer{Timeout: time.Second * 3} 34 return d.DialContext(ctx, network, address) 35 }, 36 }, 37 TryAuthoritativeDNS: true, 38 // primary Bluesky PDS instance only supports HTTP resolution method 39 SkipDNSDomainSuffixes: []string{".bsky.social"}, 40 UserAgent: "indigo-identity/" + versioninfo.Short(), 41 } 42 return &base 43} 44 45func RedisDirectory(url, plcUrl string) (identity.Directory, error) { 46 hitTTL := time.Hour * 24 47 errTTL := time.Second * 30 48 invalidHandleTTL := time.Minute * 5 49 return redisdir.NewRedisDirectory( 50 BaseDirectory(plcUrl), 51 url, 52 hitTTL, 53 errTTL, 54 invalidHandleTTL, 55 10000, 56 ) 57} 58 59func DefaultResolver(plcUrl string) *Resolver { 60 base := BaseDirectory(plcUrl) 61 cached := identity.NewCacheDirectory(base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5) 62 return &Resolver{ 63 directory: &cached, 64 } 65} 66 67func RedisResolver(redisUrl, plcUrl string) (*Resolver, error) { 68 directory, err := RedisDirectory(redisUrl, plcUrl) 69 if err != nil { 70 return nil, err 71 } 72 return &Resolver{ 73 directory: directory, 74 }, nil 75} 76 77func (r *Resolver) ResolveIdent(ctx context.Context, arg string) (*identity.Identity, error) { 78 id, err := syntax.ParseAtIdentifier(arg) 79 if err != nil { 80 return nil, err 81 } 82 83 return r.directory.Lookup(ctx, *id) 84} 85 86func (r *Resolver) ResolveIdents(ctx context.Context, idents []string) []*identity.Identity { 87 results := make([]*identity.Identity, len(idents)) 88 var wg sync.WaitGroup 89 90 done := make(chan struct{}) 91 defer close(done) 92 93 for idx, ident := range idents { 94 wg.Add(1) 95 go func(index int, id string) { 96 defer wg.Done() 97 98 select { 99 case <-ctx.Done(): 100 results[index] = nil 101 case <-done: 102 results[index] = nil 103 default: 104 identity, _ := r.ResolveIdent(ctx, id) 105 results[index] = identity 106 } 107 }(idx, ident) 108 } 109 110 wg.Wait() 111 return results 112} 113 114func (r *Resolver) InvalidateIdent(ctx context.Context, arg string) error { 115 id, err := syntax.ParseAtIdentifier(arg) 116 if err != nil { 117 return err 118 } 119 120 return r.directory.Purge(ctx, *id) 121} 122 123func (r *Resolver) Directory() identity.Directory { 124 return r.directory 125}