veza/veza-backend-api/internal/services/upload_store.go
2025-12-12 21:34:34 -05:00

79 lines
2.2 KiB
Go

package services
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
// UploadStateStore defines the interface for storing upload state
type UploadStateStore interface {
SetState(ctx context.Context, api *ChunkUploadInfo) error
GetState(ctx context.Context, uploadID string) (*ChunkUploadInfo, error)
DeleteState(ctx context.Context, uploadID string) error
}
// RedisUploadStore implements UploadStateStore using Redis
type RedisUploadStore struct {
client *redis.Client
ttl time.Duration
}
// NewRedisUploadStore create a new RedisUploadStore
func NewRedisUploadStore(client *redis.Client, ttl time.Duration) *RedisUploadStore {
return &RedisUploadStore{
client: client,
ttl: ttl,
}
}
func (s *RedisUploadStore) getKey(uploadID string) string {
return fmt.Sprintf("veza:upload:%s", uploadID)
}
func (s *RedisUploadStore) SetState(ctx context.Context, info *ChunkUploadInfo) error {
data, err := json.Marshal(info)
if err != nil {
return fmt.Errorf("failed to marshal upload info: %w", err)
}
key := s.getKey(info.UploadID)
// Use the configured TTL (e.g. 24h) to automatically clean up state
if err := s.client.Set(ctx, key, data, s.ttl).Err(); err != nil {
return fmt.Errorf("failed to save upload state to redis: %w", err)
}
return nil
}
func (s *RedisUploadStore) GetState(ctx context.Context, uploadID string) (*ChunkUploadInfo, error) {
key := s.getKey(uploadID)
data, err := s.client.Get(ctx, key).Bytes()
if err != nil {
if err == redis.Nil {
return nil, fmt.Errorf("upload not found")
}
return nil, fmt.Errorf("failed to get upload state from redis: %w", err)
}
var info ChunkUploadInfo
if err := json.Unmarshal(data, &info); err != nil {
return nil, fmt.Errorf("failed to unmarshal upload info: %w", err)
}
// Re-initialize map if nil (can happen with JSON)
if info.Chunks == nil {
info.Chunks = make(map[int]ChunkInfo)
}
return &info, nil
}
func (s *RedisUploadStore) DeleteState(ctx context.Context, uploadID string) error {
key := s.getKey(uploadID)
if err := s.client.Del(ctx, key).Err(); err != nil {
return fmt.Errorf("failed to delete upload state from redis: %w", err)
}
return nil
}