You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
1.5 KiB

package memory
import (
"context"
"fmt"
"sync"
"time"
"gitoa.ru/go-4devs/cache"
)
// NewEncoding create new provider.
func NewEncoding() cache.Provider {
items := make(map[cache.Key]encodedEntry)
mu := sync.RWMutex{}
return func(ctx context.Context, operation string, item *cache.Item) error {
switch operation {
case cache.OperationSet:
i, err := newEncodedEntry(item)
if err != nil {
return err
}
mu.Lock()
items[item.Key] = i
mu.Unlock()
return nil
case cache.OperationDelete:
mu.Lock()
delete(items, item.Key)
mu.Unlock()
return nil
case cache.OperationGet:
mu.RLock()
i, ok := items[item.Key]
mu.RUnlock()
if !ok {
return wrapErr(cache.ErrCacheMiss)
}
return resolveEncodedEntry(i, item)
}
return wrapErr(cache.ErrOperationNotAllwed)
}
}
type encodedEntry struct {
data []byte
expired time.Time
}
func wrapErr(err error) error {
if err != nil {
return fmt.Errorf("%w: encoding", err)
}
return nil
}
func newEncodedEntry(item *cache.Item) (encodedEntry, error) {
var (
e encodedEntry
err error
)
e.data, err = item.Marshal()
if err != nil {
return e, wrapErr(err)
}
if item.TTL > 0 {
e.expired = item.Expired()
}
return e, nil
}
func resolveEncodedEntry(e encodedEntry, item *cache.Item) error {
if !e.expired.IsZero() {
item.TTL = time.Until(e.expired)
}
if item.IsExpired() {
return wrapErr(cache.ErrCacheExpired)
}
return wrapErr(item.Unmarshal(e.data))
}