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  }