filebrowser/http/upload_cache_redis.go

83 lines
2.0 KiB
Go

package fbhttp
import (
"context"
"errors"
"fmt"
"log"
"strconv"
"github.com/redis/go-redis/v9"
)
// redisUploadCache is an upload cache for multi replica deployments
type redisUploadCache struct {
client *redis.Client
}
func newRedisUploadCache(redisURL string) (*redisUploadCache, error) {
if redisURL == "" {
return nil, fmt.Errorf("redis URL is required")
}
opts, err := redis.ParseURL(redisURL)
if err != nil {
return nil, fmt.Errorf("invalid redis URL: %w", err)
}
client := redis.NewClient(opts)
// Test connection
if err := client.Ping(context.Background()).Err(); err != nil {
return nil, fmt.Errorf("failed to connect to redis: %w", err)
}
return &redisUploadCache{client: client}, nil
}
func (c *redisUploadCache) filePathKey(filePath string) string {
return "filebrowser:upload:" + filePath
}
func (c *redisUploadCache) Register(filePath string, fileSize int64) {
err := c.client.Set(context.Background(), c.filePathKey(filePath), fileSize, uploadCacheTTL).Err()
if err != nil {
log.Printf("failed to register upload in redis cache: %v", err)
}
}
func (c *redisUploadCache) Complete(filePath string) {
err := c.client.Del(context.Background(), c.filePathKey(filePath)).Err()
if err != nil {
log.Printf("failed to complete upload in redis cache: %v", err)
}
}
func (c *redisUploadCache) GetLength(filePath string) (int64, error) {
result, err := c.client.Get(context.Background(), c.filePathKey(filePath)).Result()
if err != nil {
if errors.Is(err, redis.Nil) {
return 0, fmt.Errorf("no active upload found for the given path")
}
return 0, fmt.Errorf("redis error: %w", err)
}
size, err := strconv.ParseInt(result, 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid upload length in cache: %w", err)
}
return size, nil
}
func (c *redisUploadCache) Touch(filePath string) {
err := c.client.Expire(context.Background(), c.filePathKey(filePath), uploadCacheTTL).Err()
if err != nil {
log.Printf("failed to touch upload in redis cache: %v", err)
}
}
func (c *redisUploadCache) Close() {
c.client.Close()
}