package app import ( "context" "fmt" "strconv" "strings" "time" "github.com/redis/go-redis/v9" "github.com/gochat/gochat/internal/config" "github.com/gochat/gochat/pkg/logger" ) // NewRedisClient creates a Redis client for caching, Pub/Sub, and sessions. // Reference: Chatwoot config/cable.yml Redis adapter configuration func NewRedisClient(cfg *config.RedisConfig) (*redis.Client, error) { opts, err := parseRedisURL(cfg.URL) if err != nil { return nil, fmt.Errorf("failed to parse Redis URL: %w", err) } if cfg.Password != "" { opts.Password = cfg.Password } opts.PoolSize = 10 client := redis.NewClient(opts) // Verify connection ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := client.Ping(ctx).Err(); err != nil { return nil, fmt.Errorf("failed to connect to Redis: %w", err) } logger.L().Infof("Connected to Redis: %s (pool=%d)", cfg.URL, 10) return client, nil } // parseRedisURL parses a Redis URL into redis.Options. // Handles both "redis://host:port" and "redis://user:password@host:port/db" formats. func parseRedisURL(urlStr string) (*redis.Options, error) { opts, err := redis.ParseURL(urlStr) if err != nil { // Fallback: simple host:port parsing parts := strings.Split(strings.TrimPrefix(urlStr, "redis://"), ":") if len(parts) < 2 { return nil, fmt.Errorf("invalid Redis URL format: %s", urlStr) } port, err := strconv.Atoi(parts[1]) if err != nil { return nil, fmt.Errorf("invalid Redis port: %s", parts[1]) } opts = &redis.Options{ Addr: fmt.Sprintf("%s:%d", parts[0], port), } } return opts, nil }