Files
at-container-registry/pkg/atproto/directory.go

77 lines
2.6 KiB
Go

package atproto
import (
"context"
"net"
"net/http"
"sync"
"time"
"github.com/bluesky-social/indigo/atproto/identity"
"github.com/earthboundkid/versioninfo/v2"
)
var (
// Shared identity directory instance (singleton)
sharedDirectory identity.Directory
directoryOnce sync.Once
// testMode allows HTTP did:web resolution (IPs, non-TLS) for local development.
// Set via SetTestMode() on startup.
testMode bool
)
// SetTestMode enables relaxed did:web resolution for local development,
// allowing HTTP and IP-based did:web identifiers that the indigo directory rejects.
func SetTestMode(enabled bool) {
testMode = enabled
}
// IsTestMode returns whether test mode is enabled.
func IsTestMode() bool {
return testMode
}
// GetDirectory returns a shared identity.Directory instance with a 24-hour cache TTL.
// This is based on indigo's DefaultDirectory() with event-driven cache invalidation.
//
// Cache entries are invalidated via Jetstream events (identity changes, account status)
// which allows for a longer TTL while maintaining freshness. The Purge() method is called
// when identity or account events are received, ensuring the cache reflects real-time changes.
//
// Using a shared instance ensures all identity lookups across the application
// use the same cache, which is more memory-efficient and provides better cache hit rates.
func GetDirectory() identity.Directory {
directoryOnce.Do(func() {
base := identity.BaseDirectory{
PLCURL: identity.DefaultPLCURL,
HTTPClient: http.Client{
Timeout: time.Second * 10,
Transport: &http.Transport{
// would want this around 100ms for services doing lots of handle resolution. Impacts PLC connections as well, but not too bad.
IdleConnTimeout: time.Millisecond * 1000,
MaxIdleConns: 100,
},
},
Resolver: net.Resolver{
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{Timeout: time.Second * 3}
return d.DialContext(ctx, network, address)
},
},
TryAuthoritativeDNS: true,
// primary Bluesky PDS instance only supports HTTP resolution method
SkipDNSDomainSuffixes: []string{".bsky.social"},
UserAgent: "indigo-identity/" + versioninfo.Short(),
}
// Cache configuration:
// - capacity: 250,000 entries
// - hitTTL: 24 hours (event-driven invalidation via Jetstream provides freshness)
// - errTTL: 2 minutes
// - invalidHandleTTL: 5 minutes
cached := identity.NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5)
sharedDirectory = cached
})
return sharedDirectory
}