Initial QSfera import
This commit is contained in:
+64
@@ -0,0 +1,64 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultCache is the default cache.
|
||||
DefaultCache Cache = NewCache()
|
||||
// DefaultExpiration is the default duration for items stored in
|
||||
// the cache to expire.
|
||||
DefaultExpiration time.Duration = 0
|
||||
|
||||
// ErrItemExpired is returned in Cache.Get when the item found in the cache
|
||||
// has expired.
|
||||
ErrItemExpired error = errors.New("item has expired")
|
||||
// ErrKeyNotFound is returned in Cache.Get and Cache.Delete when the
|
||||
// provided key could not be found in cache.
|
||||
ErrKeyNotFound error = errors.New("key not found in cache")
|
||||
)
|
||||
|
||||
// Cache is the interface that wraps the cache.
|
||||
type Cache interface {
|
||||
// Get gets a cached value by key.
|
||||
Get(ctx context.Context, key string) (interface{}, time.Time, error)
|
||||
// Put stores a key-value pair into cache.
|
||||
Put(ctx context.Context, key string, val interface{}, d time.Duration) error
|
||||
// Delete removes a key from cache.
|
||||
Delete(ctx context.Context, key string) error
|
||||
// String returns the name of the implementation.
|
||||
String() string
|
||||
}
|
||||
|
||||
// Item represents an item stored in the cache.
|
||||
type Item struct {
|
||||
Value interface{}
|
||||
Expiration int64
|
||||
}
|
||||
|
||||
// Expired returns true if the item has expired.
|
||||
func (i *Item) Expired() bool {
|
||||
if i.Expiration == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return time.Now().UnixNano() > i.Expiration
|
||||
}
|
||||
|
||||
// NewCache returns a new cache.
|
||||
func NewCache(opts ...Option) Cache {
|
||||
options := NewOptions(opts...)
|
||||
items := make(map[string]Item)
|
||||
|
||||
if len(options.Items) > 0 {
|
||||
items = options.Items
|
||||
}
|
||||
|
||||
return &memCache{
|
||||
opts: options,
|
||||
items: items,
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type memCache struct {
|
||||
opts Options
|
||||
|
||||
items map[string]Item
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (c *memCache) Get(ctx context.Context, key string) (interface{}, time.Time, error) {
|
||||
c.RWMutex.RLock()
|
||||
defer c.RWMutex.RUnlock()
|
||||
|
||||
item, found := c.items[key]
|
||||
if !found {
|
||||
return nil, time.Time{}, ErrKeyNotFound
|
||||
}
|
||||
if item.Expired() {
|
||||
return nil, time.Time{}, ErrItemExpired
|
||||
}
|
||||
|
||||
return item.Value, time.Unix(0, item.Expiration), nil
|
||||
}
|
||||
|
||||
func (c *memCache) Put(ctx context.Context, key string, val interface{}, d time.Duration) error {
|
||||
var e int64
|
||||
if d == DefaultExpiration {
|
||||
d = c.opts.Expiration
|
||||
}
|
||||
if d > 0 {
|
||||
e = time.Now().Add(d).UnixNano()
|
||||
}
|
||||
|
||||
c.RWMutex.Lock()
|
||||
defer c.RWMutex.Unlock()
|
||||
|
||||
c.items[key] = Item{
|
||||
Value: val,
|
||||
Expiration: e,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *memCache) Delete(ctx context.Context, key string) error {
|
||||
c.RWMutex.Lock()
|
||||
defer c.RWMutex.Unlock()
|
||||
|
||||
_, found := c.items[key]
|
||||
if !found {
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
|
||||
delete(c.items, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memCache) String() string {
|
||||
return "memory"
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
// Options represents the options for the cache.
|
||||
type Options struct {
|
||||
// Context should contain all implementation specific options, using context.WithValue.
|
||||
Context context.Context
|
||||
// Logger is the be used logger
|
||||
Logger logger.Logger
|
||||
Items map[string]Item
|
||||
// Address represents the address or other connection information of the cache service.
|
||||
Address string
|
||||
Expiration time.Duration
|
||||
}
|
||||
|
||||
// Option manipulates the Options passed.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Expiration sets the duration for items stored in the cache to expire.
|
||||
func Expiration(d time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.Expiration = d
|
||||
}
|
||||
}
|
||||
|
||||
// Items initializes the cache with preconfigured items.
|
||||
func Items(i map[string]Item) Option {
|
||||
return func(o *Options) {
|
||||
o.Items = i
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddress sets the cache service address or connection information.
|
||||
func WithAddress(addr string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = addr
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext sets the cache context, for any extra configuration.
|
||||
func WithContext(c context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger sets underline logger.
|
||||
func WithLogger(l logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
}
|
||||
}
|
||||
|
||||
// NewOptions returns a new options struct.
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Expiration: DefaultExpiration,
|
||||
Items: make(map[string]Item),
|
||||
Logger: logger.DefaultLogger,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
Reference in New Issue
Block a user