1package identity
2
3import (
4 "context"
5 "net/http"
6 "sync"
7)
8
9type BackingCache interface {
10 GetDoc(did string) (*DidDoc, bool)
11 PutDoc(did string, doc *DidDoc) error
12 BustDoc(did string) error
13
14 GetDid(handle string) (string, bool)
15 PutDid(handle string, did string) error
16 BustDid(handle string) error
17}
18
19type Passport struct {
20 h *http.Client
21 bc BackingCache
22 mu sync.RWMutex
23}
24
25func NewPassport(h *http.Client, bc BackingCache) *Passport {
26 if h == nil {
27 h = http.DefaultClient
28 }
29
30 return &Passport{
31 h: h,
32 bc: bc,
33 }
34}
35
36func (p *Passport) FetchDoc(ctx context.Context, did string) (*DidDoc, error) {
37 skipCache, _ := ctx.Value("skip-cache").(bool)
38
39 if !skipCache {
40 p.mu.RLock()
41 cached, ok := p.bc.GetDoc(did)
42 p.mu.RUnlock()
43
44 if ok {
45 return cached, nil
46 }
47 }
48
49 // TODO: should coalesce requests here
50 doc, err := FetchDidDoc(ctx, p.h, did)
51 if err != nil {
52 return nil, err
53 }
54
55 p.mu.Lock()
56 p.bc.PutDoc(did, doc)
57 p.mu.Unlock()
58
59 return doc, nil
60}
61
62func (p *Passport) ResolveHandle(ctx context.Context, handle string) (string, error) {
63 skipCache, _ := ctx.Value("skip-cache").(bool)
64
65 if !skipCache {
66 p.mu.RLock()
67 cached, ok := p.bc.GetDid(handle)
68 p.mu.RUnlock()
69
70 if ok {
71 return cached, nil
72 }
73 }
74
75 did, err := ResolveHandle(ctx, p.h, handle)
76 if err != nil {
77 return "", err
78 }
79
80 p.mu.Lock()
81 p.bc.PutDid(handle, did)
82 p.mu.Unlock()
83
84 return did, nil
85}
86
87func (p *Passport) BustDoc(ctx context.Context, did string) error {
88 p.mu.Lock()
89 defer p.mu.Unlock()
90 return p.bc.BustDoc(did)
91}
92
93func (p *Passport) BustDid(ctx context.Context, handle string) error {
94 p.mu.Lock()
95 defer p.mu.Unlock()
96 return p.bc.BustDid(handle)
97}