// Package redis adapts go-redis's pooled client to cache.Store. package redis import ( "context" "errors" "strings" "time" "git.yuntuo.hk/k2safe/go-omni/cache" goredis "github.com/redis/go-redis/v9" ) // Store borrows the client; its owner must close the client after users stop. type Store struct { client goredis.Cmdable prefix string } func New(client goredis.Cmdable, prefix string) (*Store, error) { if client == nil || len(prefix) > 1024 || strings.ContainsAny(prefix, "\r\n") { return nil, errors.New("cache/redis: invalid client or prefix") } return &Store{client: client, prefix: prefix}, nil } func (s *Store) Get(ctx context.Context, key string) ([]byte, error) { if err := cache.Check(ctx, key, 0); err != nil { return nil, err } value, err := s.client.Get(ctx, s.prefix+key).Bytes() if errors.Is(err, goredis.Nil) { return nil, cache.ErrMiss } return value, err } func (s *Store) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error { if err := cache.Check(ctx, key, ttl); err != nil { return err } // Redis expiration precision is milliseconds; round up, never truncate a // positive duration to an unbounded lifetime. if ttl > 0 && ttl < time.Millisecond { ttl = time.Millisecond } return s.client.Set(ctx, s.prefix+key, value, ttl).Err() } func (s *Store) Delete(ctx context.Context, keys ...string) error { if ctx == nil { return errors.New("cache/redis: nil context") } if err := ctx.Err(); err != nil { return err } names := make([]string, len(keys)) for i, key := range keys { if err := cache.Check(ctx, key, 0); err != nil { return err } names[i] = s.prefix + key } if len(names) == 0 { return nil } return s.client.Del(ctx, names...).Err() }