github.com/safedep/dry@v0.0.0-20241016050132-a15651f0548b/cache/cache.go (about) 1 package cache 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "time" 7 8 "github.com/safedep/dry/log" 9 ) 10 11 // Type for cache data 12 type CacheData []byte 13 14 // Represent an unique cache data identifier 15 // Multiple attributes are used to help in indexing / partitioning 16 type CacheKey struct { 17 Source string 18 Type string 19 Id string 20 } 21 22 // Defines a type for a cacheable function (closure) 23 type CachableFunc[T any] func() (T, error) 24 25 // Internally maintained default caching adapter 26 var globalCachingAdapter Cache 27 28 // Cache define the contract for implementing caches 29 type Cache interface { 30 Put(key *CacheKey, data *CacheData, ttl time.Duration) error 31 Get(key *CacheKey) (*CacheData, error) 32 } 33 34 func init() { 35 Disable() 36 } 37 38 func setGlobalCachingAdapter(a Cache) { 39 globalCachingAdapter = a 40 } 41 42 func Disable() { 43 setGlobalCachingAdapter(newNoCache()) 44 } 45 46 func EnableWith(adapter Cache) { 47 setGlobalCachingAdapter(adapter) 48 } 49 50 // Through define the devex sugar - Read through cache 51 func Through[T any](key *CacheKey, ttl time.Duration, fun CachableFunc[T]) (T, error) { 52 system := globalCachingAdapter 53 if system == nil { 54 panic("default cache adapter is not set") 55 } 56 57 var empty T 58 data, err := system.Get(key) 59 if err != nil { 60 // Cache lookup failed, invoke actual function 61 realData, err := fun() 62 if err != nil { 63 return empty, err 64 } 65 66 // Cache output from actual function - Must not fail original path 67 serializedData, err := JsonSerialize(realData) 68 if err != nil { 69 log.Debugf("Cache: Failed to serialize type:%T err:%v", 70 realData, err) 71 return realData, nil 72 } 73 74 err = system.Put(key, &serializedData, ttl) 75 if err != nil { 76 log.Debugf("Cache: Failed to put due to: %v", err) 77 } 78 79 return realData, nil 80 } else { 81 // Cache lookup is successful 82 // Adapter bug in case of NPE on data 83 return JsonDeserialize[T](*data) 84 } 85 } 86 87 func JsonSerialize[T any](data T) (CacheData, error) { 88 serialized, err := json.Marshal(data) 89 if err != nil { 90 return CacheData{}, err 91 } 92 93 return CacheData(serialized), nil 94 } 95 96 func JsonDeserialize[T any](data CacheData) (T, error) { 97 var deserialized T 98 err := json.NewDecoder(bytes.NewReader([]byte(data))).Decode(&deserialized) 99 100 return deserialized, err 101 }