Monorepo for Tangled — https://tangled.org
at master 142 lines 3.8 kB view raw
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() identity.Directory { 21 base := identity.BaseDirectory{ 22 PLCURL: identity.DefaultPLCURL, 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 DefaultDirectory(plcUrl string) identity.Directory { 46 base := identity.BaseDirectory{ 47 PLCURL: plcUrl, 48 HTTPClient: http.Client{ 49 Timeout: time.Second * 10, 50 Transport: &http.Transport{ 51 // would want this around 100ms for services doing lots of handle resolution. Impacts PLC connections as well, but not too bad. 52 IdleConnTimeout: time.Millisecond * 1000, 53 MaxIdleConns: 100, 54 }, 55 }, 56 Resolver: net.Resolver{ 57 Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 58 d := net.Dialer{Timeout: time.Second * 3} 59 return d.DialContext(ctx, network, address) 60 }, 61 }, 62 TryAuthoritativeDNS: true, 63 // primary Bluesky PDS instance only supports HTTP resolution method 64 SkipDNSDomainSuffixes: []string{".bsky.social"}, 65 UserAgent: "indigo-identity/" + versioninfo.Short(), 66 } 67 cached := identity.NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5) 68 return &cached 69} 70 71func RedisDirectory(url string) (identity.Directory, error) { 72 hitTTL := time.Hour * 24 73 errTTL := time.Second * 30 74 invalidHandleTTL := time.Minute * 5 75 return redisdir.NewRedisDirectory(BaseDirectory(), url, hitTTL, errTTL, invalidHandleTTL, 10000) 76} 77 78func DefaultResolver(plcUrl string) *Resolver { 79 return &Resolver{ 80 directory: DefaultDirectory(plcUrl), 81 } 82} 83 84func RedisResolver(redisUrl string) (*Resolver, error) { 85 directory, err := RedisDirectory(redisUrl) 86 if err != nil { 87 return nil, err 88 } 89 return &Resolver{ 90 directory: directory, 91 }, nil 92} 93 94func (r *Resolver) ResolveIdent(ctx context.Context, arg string) (*identity.Identity, error) { 95 id, err := syntax.ParseAtIdentifier(arg) 96 if err != nil { 97 return nil, err 98 } 99 100 return r.directory.Lookup(ctx, *id) 101} 102 103func (r *Resolver) ResolveIdents(ctx context.Context, idents []string) []*identity.Identity { 104 results := make([]*identity.Identity, len(idents)) 105 var wg sync.WaitGroup 106 107 done := make(chan struct{}) 108 defer close(done) 109 110 for idx, ident := range idents { 111 wg.Add(1) 112 go func(index int, id string) { 113 defer wg.Done() 114 115 select { 116 case <-ctx.Done(): 117 results[index] = nil 118 case <-done: 119 results[index] = nil 120 default: 121 identity, _ := r.ResolveIdent(ctx, id) 122 results[index] = identity 123 } 124 }(idx, ident) 125 } 126 127 wg.Wait() 128 return results 129} 130 131func (r *Resolver) InvalidateIdent(ctx context.Context, arg string) error { 132 id, err := syntax.ParseAtIdentifier(arg) 133 if err != nil { 134 return err 135 } 136 137 return r.directory.Purge(ctx, *id) 138} 139 140func (r *Resolver) Directory() identity.Directory { 141 return r.directory 142}