79 lines
2.2 KiB
Go
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
|
|
}
|