github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/identify2_cache.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "fmt" 8 "time" 9 10 keybase1 "github.com/keybase/client/go/protocol/keybase1" 11 "stathat.com/c/ramcache" 12 ) 13 14 // Identify2Cache stores User objects in memory for a fixed amount of 15 // time. 16 type Identify2Cache struct { 17 cache *ramcache.Ramcache 18 } 19 20 type Identify2Cacher interface { 21 Get(keybase1.UID, GetCheckTimeFunc, GetCacheDurationFunc, bool) (*keybase1.Identify2ResUPK2, error) 22 Insert(up *keybase1.Identify2ResUPK2) error 23 DidFullUserLoad(keybase1.UID) 24 Shutdown() 25 Delete(uid keybase1.UID) error 26 UseDiskCache() bool 27 } 28 29 type GetCheckTimeFunc func(keybase1.Identify2ResUPK2) keybase1.Time 30 type GetCacheDurationFunc func(keybase1.Identify2ResUPK2) time.Duration 31 32 // NewIdentify2Cache creates a Identify2Cache and sets the object max age to 33 // maxAge. Once a user is inserted, after maxAge duration passes, 34 // the user will be removed from the cache. 35 func NewIdentify2Cache(maxAge time.Duration) *Identify2Cache { 36 res := &Identify2Cache{ 37 cache: ramcache.New(), 38 } 39 res.cache.MaxAge = maxAge 40 res.cache.TTL = maxAge 41 return res 42 } 43 44 // Get returns a user object. If none exists for uid, it will return nil. 45 func (c *Identify2Cache) Get(uid keybase1.UID, gctf GetCheckTimeFunc, gcdf GetCacheDurationFunc, breaksOK bool) (*keybase1.Identify2ResUPK2, error) { 46 v, err := c.cache.Get(string(uid)) 47 if err != nil { 48 if err == ramcache.ErrNotFound { 49 return nil, nil 50 } 51 return nil, err 52 } 53 up, ok := v.(*keybase1.Identify2ResUPK2) 54 if !ok { 55 return nil, fmt.Errorf("invalid type in cache: %T", v) 56 } 57 58 if gctf != nil { 59 then := gctf(*up) 60 if then == 0 { 61 return nil, IdentifyTimeoutError{} 62 } 63 if up.TrackBreaks != nil && !breaksOK { 64 return nil, TrackBrokenError{} 65 } 66 67 thenTime := keybase1.FromTime(then) 68 timeout := gcdf(*up) 69 if time.Since(thenTime) > timeout { 70 return nil, IdentifyTimeoutError{} 71 } 72 } 73 74 return up, nil 75 } 76 77 // Insert adds a user to the cache, keyed on UID. 78 func (c *Identify2Cache) Insert(up *keybase1.Identify2ResUPK2) error { 79 tmp := *up 80 copy := &tmp 81 copy.Upk.Uvv.CachedAt = keybase1.ToTime(time.Now()) 82 return c.cache.Set(string(up.Upk.GetUID()), copy) 83 } 84 85 func (c *Identify2Cache) Delete(uid keybase1.UID) error { 86 return c.cache.Delete(string(uid)) 87 } 88 89 // Shutdown stops any goroutines in the cache. 90 func (c *Identify2Cache) Shutdown() { 91 c.cache.Shutdown() 92 } 93 94 // DidFullUserLoad is a noop unless we're testing... 95 func (c *Identify2Cache) DidFullUserLoad(_ keybase1.UID) {} 96 97 func (c *Identify2Cache) UseDiskCache() bool { return true }