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 }