package redis import ( "context" "fmt" "time" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" "carrot_bbs/internal/config" ) // Client Redis客户端 type Client struct { rdb *redis.Client isMiniRedis bool mr *miniredis.Miniredis } // New 创建Redis客户端 func New(cfg *config.RedisConfig) (*Client, error) { switch cfg.Type { case "miniredis": // 启动内嵌Redis模拟 mr, err := miniredis.Run() if err != nil { return nil, fmt.Errorf("failed to start miniredis: %w", err) } rdb := redis.NewClient(&redis.Options{ Addr: mr.Addr(), Password: "", DB: 0, }) return &Client{ rdb: rdb, isMiniRedis: true, mr: mr, }, nil case "redis": // 使用真实Redis rdb := redis.NewClient(&redis.Options{ Addr: cfg.Redis.Addr(), Password: cfg.Redis.Password, DB: cfg.Redis.DB, PoolSize: cfg.PoolSize, }) ctx := context.Background() if err := rdb.Ping(ctx).Err(); err != nil { return nil, fmt.Errorf("failed to connect to redis: %w", err) } return &Client{rdb: rdb, isMiniRedis: false}, nil default: // 默认使用miniredis mr, err := miniredis.Run() if err != nil { return nil, fmt.Errorf("failed to start miniredis: %w", err) } rdb := redis.NewClient(&redis.Options{ Addr: mr.Addr(), }) return &Client{ rdb: rdb, isMiniRedis: true, mr: mr, }, nil } } // Get 获取值 func (c *Client) Get(ctx context.Context, key string) (string, error) { return c.rdb.Get(ctx, key).Result() } // Set 设置值 func (c *Client) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error { return c.rdb.Set(ctx, key, value, expiration).Err() } // Del 删除键 func (c *Client) Del(ctx context.Context, keys ...string) error { return c.rdb.Del(ctx, keys...).Err() } // Exists 检查键是否存在 func (c *Client) Exists(ctx context.Context, keys ...string) (int64, error) { return c.rdb.Exists(ctx, keys...).Result() } // Incr 递增 func (c *Client) Incr(ctx context.Context, key string) (int64, error) { return c.rdb.Incr(ctx, key).Result() } // Expire 设置过期时间 func (c *Client) Expire(ctx context.Context, key string, expiration time.Duration) (bool, error) { return c.rdb.Expire(ctx, key, expiration).Result() } // GetClient 获取原生客户端 func (c *Client) GetClient() *redis.Client { return c.rdb } // Close 关闭连接 func (c *Client) Close() error { if err := c.rdb.Close(); err != nil { return err } if c.mr != nil { c.mr.Close() } return nil } // IsMiniRedis 返回是否是miniredis func (c *Client) IsMiniRedis() bool { return c.isMiniRedis } // ==================== Hash 操作 ==================== // HSet 设置 Hash 字段 func (c *Client) HSet(ctx context.Context, key string, field string, value interface{}) error { return c.rdb.HSet(ctx, key, field, value).Err() } // HMSet 批量设置 Hash 字段 func (c *Client) HMSet(ctx context.Context, key string, values map[string]interface{}) error { return c.rdb.HMSet(ctx, key, values).Err() } // HGet 获取 Hash 字段值 func (c *Client) HGet(ctx context.Context, key string, field string) (string, error) { return c.rdb.HGet(ctx, key, field).Result() } // HMGet 批量获取 Hash 字段值 func (c *Client) HMGet(ctx context.Context, key string, fields ...string) ([]interface{}, error) { return c.rdb.HMGet(ctx, key, fields...).Result() } // HGetAll 获取 Hash 所有字段 func (c *Client) HGetAll(ctx context.Context, key string) (map[string]string, error) { return c.rdb.HGetAll(ctx, key).Result() } // HDel 删除 Hash 字段 func (c *Client) HDel(ctx context.Context, key string, fields ...string) error { return c.rdb.HDel(ctx, key, fields...).Err() } // HExists 检查 Hash 字段是否存在 func (c *Client) HExists(ctx context.Context, key string, field string) (bool, error) { return c.rdb.HExists(ctx, key, field).Result() } // HLen 获取 Hash 字段数量 func (c *Client) HLen(ctx context.Context, key string) (int64, error) { return c.rdb.HLen(ctx, key).Result() } // ==================== Sorted Set 操作 ==================== // ZAdd 添加 Sorted Set 成员 func (c *Client) ZAdd(ctx context.Context, key string, score float64, member string) error { return c.rdb.ZAdd(ctx, key, redis.Z{Score: score, Member: member}).Err() } // ZAddArgs 批量添加 Sorted Set 成员 func (c *Client) ZAddArgs(ctx context.Context, key string, members ...redis.Z) error { return c.rdb.ZAdd(ctx, key, members...).Err() } // ZRangeByScore 按分数范围获取成员(升序) func (c *Client) ZRangeByScore(ctx context.Context, key string, min, max string, offset, count int64) ([]string, error) { return c.rdb.ZRangeByScore(ctx, key, &redis.ZRangeBy{ Min: min, Max: max, Offset: offset, Count: count, }).Result() } // ZRevRangeByScore 按分数范围获取成员(降序) func (c *Client) ZRevRangeByScore(ctx context.Context, key string, max, min string, offset, count int64) ([]string, error) { return c.rdb.ZRevRangeByScore(ctx, key, &redis.ZRangeBy{ Min: min, Max: max, Offset: offset, Count: count, }).Result() } // ZRange 获取指定范围的成员(升序) func (c *Client) ZRange(ctx context.Context, key string, start, stop int64) ([]string, error) { return c.rdb.ZRange(ctx, key, start, stop).Result() } // ZRevRange 获取指定范围的成员(降序) func (c *Client) ZRevRange(ctx context.Context, key string, start, stop int64) ([]string, error) { return c.rdb.ZRevRange(ctx, key, start, stop).Result() } // ZRem 删除 Sorted Set 成员 func (c *Client) ZRem(ctx context.Context, key string, members ...interface{}) error { return c.rdb.ZRem(ctx, key, members...).Err() } // ZScore 获取成员分数 func (c *Client) ZScore(ctx context.Context, key string, member string) (float64, error) { return c.rdb.ZScore(ctx, key, member).Result() } // ZCard 获取 Sorted Set 成员数量 func (c *Client) ZCard(ctx context.Context, key string) (int64, error) { return c.rdb.ZCard(ctx, key).Result() } // ZCount 统计分数范围内的成员数量 func (c *Client) ZCount(ctx context.Context, key string, min, max string) (int64, error) { return c.rdb.ZCount(ctx, key, min, max).Result() } // ==================== Pipeline 操作 ==================== // Pipeliner Pipeline 接口(使用 redis 库原生接口) type Pipeliner = redis.Pipeliner // Pipeline 创建 Pipeline func (c *Client) Pipeline() Pipeliner { return c.rdb.Pipeline() }