Files
gochat/backend/internal/app/redis.go
T
rogee aeddedf2a3 Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
Restructure the monorepo into clear top-level directories:
- backend/: Go module root (cmd, internal, pkg, configs, migrations,
  docs/swagger, scripts, tests, go.mod, Makefile, .air.toml)
- deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd
- docs/: project documentation + reports/ (moved from repo root)
- AGENTS.md: new AI coding-agent guide at repo root

Update all references to the new layout:
- Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root)
- docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile,
  env_file ../../.env, volume mounts ../../backend:/app
- deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile
- CI: working-directory: backend for go commands, file deploy/docker/Dockerfile,
  coverage path backend/coverage.out, health_check backend/scripts/
- backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../
- README: architecture tree, quickstart, config paths updated

Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh,
gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to
preserve history. Build, vet, SQLite tests, and docker compose config verified.
2026-07-07 14:44:12 +08:00

67 lines
1.7 KiB
Go

package app
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"github.com/gochat/gochat/internal/config"
"github.com/gochat/gochat/pkg/logger"
"github.com/redis/go-redis/v9"
)
// 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
}
poolSize := cfg.PoolSize
if poolSize <= 0 {
poolSize = 50
}
opts.PoolSize = poolSize
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, poolSize)
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
}