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.
110 lines
2.0 KiB
110 lines
2.0 KiB
package redis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitoa.ru/go-4devs/cache"
|
|
)
|
|
|
|
type Conn interface {
|
|
Do(commandName string, args ...interface{}) (reply interface{}, err error)
|
|
Send(commandName string, args ...interface{}) error
|
|
Flush() error
|
|
Close() error
|
|
}
|
|
|
|
// New creates new provider.
|
|
func New(pool func(context.Context) (Conn, error)) cache.Provider {
|
|
return func(ctx context.Context, operation string, item *cache.Item) error {
|
|
conn, err := pool(ctx)
|
|
if err != nil {
|
|
return wrapErr(err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
key := item.Key.String()
|
|
|
|
switch operation {
|
|
case cache.OperationGet:
|
|
data, ttl, err := get(conn, key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
item.TTLInSecond(ttl)
|
|
|
|
return wrapErr(item.Unmarshal(data))
|
|
case cache.OperationSet:
|
|
data, err := item.Marshal()
|
|
if err != nil {
|
|
return wrapErr(err)
|
|
}
|
|
|
|
return set(conn, key, data, int(item.TTL.Seconds()))
|
|
case cache.OperationDelete:
|
|
return del(conn, key)
|
|
}
|
|
|
|
return wrapErr(cache.ErrOperationNotAllwed)
|
|
}
|
|
}
|
|
|
|
func get(conn Conn, key string) ([]byte, int64, error) {
|
|
data, err := conn.Do("GET", key)
|
|
if err != nil {
|
|
return nil, 0, wrapErr(err)
|
|
}
|
|
|
|
if data == nil {
|
|
return nil, 0, wrapErr(cache.ErrCacheMiss)
|
|
}
|
|
|
|
v, ok := data.([]byte)
|
|
if !ok {
|
|
return nil, 0, wrapErr(cache.ErrSourceNotValid)
|
|
}
|
|
|
|
expire, err := conn.Do("TTL", key)
|
|
if err != nil {
|
|
return v, 0, wrapErr(err)
|
|
}
|
|
|
|
ex, _ := expire.(int64)
|
|
|
|
return v, ex, nil
|
|
}
|
|
|
|
func set(conn Conn, key string, data []byte, ttl int) error {
|
|
if err := conn.Send("SET", key, data); err != nil {
|
|
return wrapErr(err)
|
|
}
|
|
|
|
if ttl > 0 {
|
|
if err := conn.Send("EXPIRE", key, ttl); err != nil {
|
|
return wrapErr(err)
|
|
}
|
|
}
|
|
|
|
if err := conn.Flush(); err != nil {
|
|
return fmt.Errorf("failed flush then set %s by %w", key, conn.Flush())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func del(conn Conn, key string) error {
|
|
if _, err := conn.Do("DEL", key); err != nil {
|
|
return wrapErr(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func wrapErr(err error) error {
|
|
if err != nil {
|
|
return fmt.Errorf("%w: redis pool", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|