github.com/msales/pkg/v3@v3.24.0/cache/memcache.go (about) 1 package cache 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 "github.com/bradfitz/gomemcache/memcache" 9 ) 10 11 // MemcacheOptionsFunc represents an configuration function for Memcache. 12 type MemcacheOptionsFunc func(*memcache.Client) 13 14 // WithIdleConns configures the Memcache max idle connections. 15 func WithIdleConns(size int) MemcacheOptionsFunc { 16 return func(c *memcache.Client) { 17 c.MaxIdleConns = size 18 } 19 } 20 21 // WithTimeout configures the Memcache read and write timeout. 22 func WithTimeout(timeout time.Duration) MemcacheOptionsFunc { 23 return func(c *memcache.Client) { 24 c.Timeout = timeout 25 } 26 } 27 28 type memcacheCache struct { 29 client *memcache.Client 30 31 encoder func(v interface{}) ([]byte, error) 32 decoder decoder 33 } 34 35 // NewMemcache create a new Memcache cache instance. 36 func NewMemcache(uri string, opts ...MemcacheOptionsFunc) Cache { 37 c := memcache.New(uri) 38 39 for _, opt := range opts { 40 opt(c) 41 } 42 43 return &memcacheCache{ 44 client: c, 45 encoder: memcacheEncoder, 46 decoder: stringDecoder{}, 47 } 48 } 49 50 // Get gets the item for the given key. 51 func (c memcacheCache) Get(key string) *Item { 52 b := []byte(nil) 53 v, err := c.client.Get(key) 54 switch err { 55 case memcache.ErrCacheMiss: 56 err = ErrCacheMiss 57 case nil: 58 b = v.Value 59 } 60 61 return &Item{ 62 decoder: c.decoder, 63 value: b, 64 err: err, 65 } 66 } 67 68 // GetMulti gets the items for the given keys. 69 func (c memcacheCache) GetMulti(keys ...string) ([]*Item, error) { 70 val, err := c.client.GetMulti(keys) 71 if err != nil { 72 return nil, err 73 } 74 75 i := []*Item{} 76 for _, k := range keys { 77 var err = ErrCacheMiss 78 var b []byte 79 if v, ok := val[k]; ok { 80 b = v.Value 81 err = nil 82 } 83 84 i = append(i, &Item{ 85 decoder: c.decoder, 86 value: b, 87 err: err, 88 }) 89 } 90 91 return i, nil 92 } 93 94 // Set sets the item in the cache. 95 func (c memcacheCache) Set(key string, value interface{}, expire time.Duration) error { 96 v, err := c.encoder(value) 97 if err != nil { 98 return err 99 } 100 101 return c.client.Set(&memcache.Item{ 102 Key: key, 103 Value: v, 104 Expiration: int32(expire.Seconds()), 105 }) 106 } 107 108 // Add sets the item in the cache, but only if the key does not already exist. 109 func (c memcacheCache) Add(key string, value interface{}, expire time.Duration) error { 110 v, err := c.encoder(value) 111 if err != nil { 112 return err 113 } 114 115 err = c.client.Add(&memcache.Item{ 116 Key: key, 117 Value: v, 118 Expiration: int32(expire.Seconds()), 119 }) 120 if err == memcache.ErrNotStored { 121 return ErrNotStored 122 } 123 return err 124 } 125 126 // Replace sets the item in the cache, but only if the key already exists. 127 func (c memcacheCache) Replace(key string, value interface{}, expire time.Duration) error { 128 v, err := c.encoder(value) 129 if err != nil { 130 return err 131 } 132 133 err = c.client.Replace(&memcache.Item{ 134 Key: key, 135 Value: v, 136 Expiration: int32(expire.Seconds()), 137 }) 138 139 if err == memcache.ErrNotStored { 140 return ErrNotStored 141 } 142 return err 143 } 144 145 // Delete deletes the item with the given key. 146 func (c memcacheCache) Delete(key string) error { 147 return c.client.Delete(key) 148 } 149 150 // Inc increments a key by the value. 151 func (c memcacheCache) Inc(key string, value uint64) (int64, error) { 152 v, err := c.client.Increment(key, value) 153 return int64(v), err 154 } 155 156 // Dec decrements a key by the value. 157 func (c memcacheCache) Dec(key string, value uint64) (int64, error) { 158 v, err := c.client.Decrement(key, value) 159 return int64(v), err 160 } 161 162 func memcacheEncoder(v interface{}) ([]byte, error) { 163 switch v.(type) { 164 case bool: 165 if v.(bool) { 166 return []byte("1"), nil 167 } 168 return []byte("0"), nil 169 case int, int8, int16, int32, int64: 170 return []byte(fmt.Sprintf("%d", v)), nil 171 case uint, uint8, uint16, uint32, uint64: 172 return []byte(fmt.Sprintf("%d", v)), nil 173 case float32, float64: 174 return []byte(fmt.Sprintf("%f", v)), nil 175 case string: 176 return []byte(v.(string)), nil 177 } 178 179 return json.Marshal(v) 180 }