1
This commit is contained in:
143
internal/cache/valkey.go
vendored
Normal file
143
internal/cache/valkey.go
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
)
|
||||
|
||||
type ValKeyCacheConfig struct {
|
||||
Addrs []string
|
||||
Password string
|
||||
ReadOnly bool
|
||||
DialTimeout time.Duration
|
||||
PoolSize int
|
||||
DefaultTTL time.Duration
|
||||
RootCaFilePath string
|
||||
}
|
||||
|
||||
type valkeyClient interface {
|
||||
Set(key string, value any, expiration time.Duration) *redis.StatusCmd
|
||||
Get(key string) *redis.StringCmd
|
||||
Del(keys ...string) *redis.IntCmd
|
||||
Exists(keys ...string) *redis.IntCmd
|
||||
Ping() *redis.StatusCmd
|
||||
}
|
||||
|
||||
type valKeyCache struct {
|
||||
config ValKeyCacheConfig
|
||||
client valkeyClient
|
||||
}
|
||||
|
||||
func newValKeyCache(c Config) (*valKeyCache, error) {
|
||||
cfg, ok := c.(ValKeyCacheConfig)
|
||||
if !ok {
|
||||
return nil, ErrInvalidConfig
|
||||
}
|
||||
|
||||
caCert, err := os.ReadFile(cfg.RootCaFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrTlsConfig, err.Error())
|
||||
}
|
||||
|
||||
caCertPool := x509.NewCertPool()
|
||||
|
||||
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
|
||||
return nil, fmt.Errorf("%w: %s", ErrTlsConfig, "failed to append CA cert to pool")
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
|
||||
client := redis.NewUniversalClient(&redis.UniversalOptions{
|
||||
Addrs: cfg.Addrs,
|
||||
Password: cfg.Password,
|
||||
ReadOnly: cfg.ReadOnly,
|
||||
DialTimeout: cfg.DialTimeout,
|
||||
PoolSize: cfg.PoolSize,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
|
||||
if err := client.Ping().Err(); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrConnect, err)
|
||||
}
|
||||
|
||||
return &valKeyCache{
|
||||
config: cfg,
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *valKeyCache) Get(ctx context.Context, key string, valueType ValueType) (string, error) {
|
||||
if err := c.checkInstance(); err != nil {
|
||||
return "", fmt.Errorf("%w: %v", ErrGet, err)
|
||||
}
|
||||
|
||||
val, err := c.client.Get(getKey(key, valueType)).Result()
|
||||
if err == redis.Nil {
|
||||
return "", ErrKeyNotFound
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %v", ErrGet, err)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *valKeyCache) Set(ctx context.Context, key string, valueType ValueType, value any, expiration time.Duration) error {
|
||||
if err := c.checkInstance(); err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrSet, err)
|
||||
}
|
||||
|
||||
key = getKey(key, valueType)
|
||||
|
||||
if exists, err := c.client.Exists(key).Result(); err != nil || exists == 1 {
|
||||
if exists == 1 {
|
||||
return ErrKeyExists
|
||||
}
|
||||
|
||||
return fmt.Errorf("%w: %v", ErrSet, err)
|
||||
}
|
||||
|
||||
if err := c.client.Set(key, value, expiration).Err(); err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrSet, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *valKeyCache) Del(ctx context.Context, key string, valueType ValueType) error {
|
||||
if err := c.checkInstance(); err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrDel, err.Error())
|
||||
}
|
||||
|
||||
if res, err := c.client.Del(getKey(key, valueType)).Result(); err != nil || res == 0 {
|
||||
if res == 0 {
|
||||
return ErrKeyNotFound
|
||||
}
|
||||
|
||||
return fmt.Errorf("%w: %s", ErrDel, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *valKeyCache) checkInstance() error {
|
||||
if c == nil {
|
||||
return ErrInvalidInstance
|
||||
}
|
||||
|
||||
if s := c.client.Ping(); s.Err() != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidInstance, s.Err().Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user