github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/cache/cache.go (about)

     1  package cache
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"hash/fnv"
     8  	"time"
     9  
    10  	"github.com/tickoalcantara12/micro/v3/service/client"
    11  	"github.com/tickoalcantara12/micro/v3/service/context/metadata"
    12  	cache "github.com/patrickmn/go-cache"
    13  )
    14  
    15  // New returns an initialised cache.
    16  func New() *Cache {
    17  	return &Cache{
    18  		cache: cache.New(cache.NoExpiration, 30*time.Second),
    19  	}
    20  }
    21  
    22  // Cache for responses
    23  type Cache struct {
    24  	cache *cache.Cache
    25  }
    26  
    27  type Options struct {
    28  	// Expiry sets the cache expiry
    29  	Expiry time.Duration
    30  }
    31  
    32  // used to store the options in context
    33  type optionsKey struct{}
    34  
    35  // Get a response from the cache
    36  func (c *Cache) Get(ctx context.Context, req client.Request) (interface{}, bool) {
    37  	return c.cache.Get(key(ctx, req))
    38  }
    39  
    40  // Set a response in the cache
    41  func (c *Cache) Set(ctx context.Context, req client.Request, rsp interface{}, expiry time.Duration) {
    42  	c.cache.Set(key(ctx, req), rsp, expiry)
    43  }
    44  
    45  // List the key value pairs in the cache
    46  func (c *Cache) List() map[string]string {
    47  	items := c.cache.Items()
    48  
    49  	rsp := make(map[string]string, len(items))
    50  	for k, v := range items {
    51  		bytes, _ := json.Marshal(v.Object)
    52  		rsp[k] = string(bytes)
    53  	}
    54  
    55  	return rsp
    56  }
    57  
    58  // key returns a hash for the context and request
    59  func key(ctx context.Context, req client.Request) string {
    60  	ns, _ := metadata.Get(ctx, "Micro-Namespace")
    61  
    62  	bytes, _ := json.Marshal(map[string]interface{}{
    63  		"namespace": ns,
    64  		"request": map[string]interface{}{
    65  			"service":  req.Service(),
    66  			"endpoint": req.Endpoint(),
    67  			"method":   req.Method(),
    68  			"body":     req.Body(),
    69  		},
    70  	})
    71  
    72  	h := fnv.New64()
    73  	h.Write(bytes)
    74  	return fmt.Sprintf("%x", h.Sum(nil))
    75  }
    76  
    77  func SetOptions(ctx context.Context, opts *Options) context.Context {
    78  	if ctx == nil {
    79  		ctx = context.Background()
    80  	}
    81  	return context.WithValue(ctx, optionsKey{}, opts)
    82  }
    83  
    84  func GetOptions(ctx context.Context) (*Options, bool) {
    85  	if ctx == nil {
    86  		return nil, false
    87  	}
    88  	opts, ok := ctx.Value(optionsKey{}).(*Options)
    89  	return opts, ok
    90  }
    91  
    92  func CallOption(opts *Options) client.CallOption {
    93  	return func(o *client.CallOptions) {
    94  		if o.Context == nil {
    95  			o.Context = context.Background()
    96  		}
    97  		o.Context = SetOptions(o.Context, opts)
    98  	}
    99  }
   100  
   101  func CallExpiry(t time.Duration) client.CallOption {
   102  	return CallOption(&Options{
   103  		Expiry: t,
   104  	})
   105  }