mirror of
https://github.com/gofiber/storage.git
synced 2025-09-28 13:22:18 +08:00

Introduced NewFromConnection to create Storage using an existing Redis client, enhancing flexibility. Added benchmarks to test Redis operations with this method.
156 lines
3.3 KiB
Go
156 lines
3.3 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// Storage interface that is implemented by storage providers
|
|
type Storage struct {
|
|
db redis.UniversalClient
|
|
}
|
|
|
|
// NewFromConnection creates a new instance of Storage using the provided Redis universal client.
|
|
func NewFromConnection(conn redis.UniversalClient) *Storage {
|
|
return &Storage{
|
|
db: conn,
|
|
}
|
|
}
|
|
|
|
// New creates a new Redis storage instance.
|
|
func New(config ...Config) *Storage {
|
|
// Set default config
|
|
cfg := configDefault(config...)
|
|
|
|
// Create new redis universal client
|
|
var db redis.UniversalClient
|
|
|
|
// Parse the URL and update config values accordingly
|
|
if cfg.URL != "" {
|
|
options, err := redis.ParseURL(cfg.URL)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Update the config values with the parsed URL values
|
|
cfg.Username = options.Username
|
|
cfg.Password = options.Password
|
|
cfg.Database = options.DB
|
|
cfg.Addrs = []string{options.Addr}
|
|
|
|
// If cfg.TLSConfig is not provided, and options returns one, use it.
|
|
if cfg.TLSConfig == nil && options.TLSConfig != nil {
|
|
cfg.TLSConfig = options.TLSConfig
|
|
}
|
|
} else if len(cfg.Addrs) == 0 {
|
|
// Fallback to Host and Port values if Addrs is empty
|
|
cfg.Addrs = []string{fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)}
|
|
}
|
|
|
|
// Create Universal Client
|
|
db = redis.NewUniversalClient(&redis.UniversalOptions{
|
|
Addrs: cfg.Addrs,
|
|
MasterName: cfg.MasterName,
|
|
ClientName: cfg.ClientName,
|
|
SentinelUsername: cfg.SentinelUsername,
|
|
SentinelPassword: cfg.SentinelPassword,
|
|
DB: cfg.Database,
|
|
Username: cfg.Username,
|
|
Password: cfg.Password,
|
|
TLSConfig: cfg.TLSConfig,
|
|
PoolSize: cfg.PoolSize,
|
|
})
|
|
|
|
// Test connection
|
|
if err := db.Ping(context.Background()).Err(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Empty collection if Clear is true
|
|
if cfg.Reset {
|
|
if err := db.FlushDB(context.Background()).Err(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// Create new store
|
|
return &Storage{
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// Get value by key
|
|
func (s *Storage) Get(key string) ([]byte, error) {
|
|
if len(key) <= 0 {
|
|
return nil, nil
|
|
}
|
|
val, err := s.db.Get(context.Background(), key).Bytes()
|
|
if err == redis.Nil {
|
|
return nil, nil
|
|
}
|
|
return val, err
|
|
}
|
|
|
|
// Set key with value
|
|
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
|
if len(key) <= 0 || len(val) <= 0 {
|
|
return nil
|
|
}
|
|
return s.db.Set(context.Background(), key, val, exp).Err()
|
|
}
|
|
|
|
// Delete key by key
|
|
func (s *Storage) Delete(key string) error {
|
|
if len(key) <= 0 {
|
|
return nil
|
|
}
|
|
return s.db.Del(context.Background(), key).Err()
|
|
}
|
|
|
|
// Reset all keys
|
|
func (s *Storage) Reset() error {
|
|
return s.db.FlushDB(context.Background()).Err()
|
|
}
|
|
|
|
// Close the database
|
|
func (s *Storage) Close() error {
|
|
return s.db.Close()
|
|
}
|
|
|
|
// Return database client
|
|
func (s *Storage) Conn() redis.UniversalClient {
|
|
return s.db
|
|
}
|
|
|
|
// Return all the keys
|
|
func (s *Storage) Keys() ([][]byte, error) {
|
|
var keys [][]byte
|
|
var cursor uint64
|
|
var err error
|
|
|
|
for {
|
|
var batch []string
|
|
|
|
if batch, cursor, err = s.db.Scan(context.Background(), cursor, "*", 10).Result(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, key := range batch {
|
|
keys = append(keys, []byte(key))
|
|
}
|
|
|
|
if cursor == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
if len(keys) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return keys, nil
|
|
}
|