code.gitea.io/gitea@v1.22.3/modules/cache/string_cache.go (about) 1 // Copyright 2024 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package cache 5 6 import ( 7 "errors" 8 "strings" 9 10 "code.gitea.io/gitea/modules/json" 11 "code.gitea.io/gitea/modules/setting" 12 "code.gitea.io/gitea/modules/util" 13 14 chi_cache "gitea.com/go-chi/cache" //nolint:depguard 15 ) 16 17 type GetJSONError struct { 18 err error 19 cachedError string // Golang error can't be stored in cache, only the string message could be stored 20 } 21 22 func (e *GetJSONError) ToError() error { 23 if e.err != nil { 24 return e.err 25 } 26 return errors.New("cached error: " + e.cachedError) 27 } 28 29 type StringCache interface { 30 Ping() error 31 32 Get(key string) (string, bool) 33 Put(key, value string, ttl int64) error 34 Delete(key string) error 35 IsExist(key string) bool 36 37 PutJSON(key string, v any, ttl int64) error 38 GetJSON(key string, ptr any) (exist bool, err *GetJSONError) 39 40 ChiCache() chi_cache.Cache 41 } 42 43 type stringCache struct { 44 chiCache chi_cache.Cache 45 } 46 47 func NewStringCache(cacheConfig setting.Cache) (StringCache, error) { 48 adapter := util.IfZero(cacheConfig.Adapter, "memory") 49 interval := util.IfZero(cacheConfig.Interval, 60) 50 cc, err := chi_cache.NewCacher(chi_cache.Options{ 51 Adapter: adapter, 52 AdapterConfig: cacheConfig.Conn, 53 Interval: interval, 54 }) 55 if err != nil { 56 return nil, err 57 } 58 return &stringCache{chiCache: cc}, nil 59 } 60 61 func (sc *stringCache) Ping() error { 62 return sc.chiCache.Ping() 63 } 64 65 func (sc *stringCache) Get(key string) (string, bool) { 66 v := sc.chiCache.Get(key) 67 if v == nil { 68 return "", false 69 } 70 s, ok := v.(string) 71 return s, ok 72 } 73 74 func (sc *stringCache) Put(key, value string, ttl int64) error { 75 return sc.chiCache.Put(key, value, ttl) 76 } 77 78 func (sc *stringCache) Delete(key string) error { 79 return sc.chiCache.Delete(key) 80 } 81 82 func (sc *stringCache) IsExist(key string) bool { 83 return sc.chiCache.IsExist(key) 84 } 85 86 const cachedErrorPrefix = "<CACHED-ERROR>:" 87 88 func (sc *stringCache) PutJSON(key string, v any, ttl int64) error { 89 var s string 90 switch v := v.(type) { 91 case error: 92 s = cachedErrorPrefix + v.Error() 93 default: 94 b, err := json.Marshal(v) 95 if err != nil { 96 return err 97 } 98 s = util.UnsafeBytesToString(b) 99 } 100 return sc.chiCache.Put(key, s, ttl) 101 } 102 103 func (sc *stringCache) GetJSON(key string, ptr any) (exist bool, getErr *GetJSONError) { 104 s, ok := sc.Get(key) 105 if !ok || s == "" { 106 return false, nil 107 } 108 s, isCachedError := strings.CutPrefix(s, cachedErrorPrefix) 109 if isCachedError { 110 return true, &GetJSONError{cachedError: s} 111 } 112 if err := json.Unmarshal(util.UnsafeStringToBytes(s), ptr); err != nil { 113 return false, &GetJSONError{err: err} 114 } 115 return true, nil 116 } 117 118 func (sc *stringCache) ChiCache() chi_cache.Cache { 119 return sc.chiCache 120 }