Files
jiggablend/internal/storage/storage.go
2025-11-21 17:31:18 -06:00

138 lines
3.4 KiB
Go

package storage
import (
"fmt"
"io"
"os"
"path/filepath"
)
// Storage handles file storage operations
type Storage struct {
basePath string
}
// NewStorage creates a new storage instance
func NewStorage(basePath string) (*Storage, error) {
s := &Storage{basePath: basePath}
if err := s.init(); err != nil {
return nil, err
}
return s, nil
}
// init creates necessary directories
func (s *Storage) init() error {
dirs := []string{
s.basePath,
s.uploadsPath(),
s.outputsPath(),
}
for _, dir := range dirs {
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", dir, err)
}
}
return nil
}
// uploadsPath returns the path for uploads
func (s *Storage) uploadsPath() string {
return filepath.Join(s.basePath, "uploads")
}
// outputsPath returns the path for outputs
func (s *Storage) outputsPath() string {
return filepath.Join(s.basePath, "outputs")
}
// JobPath returns the path for a specific job's files
func (s *Storage) JobPath(jobID int64) string {
return filepath.Join(s.basePath, "jobs", fmt.Sprintf("%d", jobID))
}
// SaveUpload saves an uploaded file
func (s *Storage) SaveUpload(jobID int64, filename string, reader io.Reader) (string, error) {
jobPath := s.JobPath(jobID)
if err := os.MkdirAll(jobPath, 0755); err != nil {
return "", fmt.Errorf("failed to create job directory: %w", err)
}
filePath := filepath.Join(jobPath, filename)
file, err := os.Create(filePath)
if err != nil {
return "", fmt.Errorf("failed to create file: %w", err)
}
defer file.Close()
if _, err := io.Copy(file, reader); err != nil {
return "", fmt.Errorf("failed to write file: %w", err)
}
return filePath, nil
}
// SaveOutput saves an output file
func (s *Storage) SaveOutput(jobID int64, filename string, reader io.Reader) (string, error) {
outputPath := filepath.Join(s.outputsPath(), fmt.Sprintf("%d", jobID))
if err := os.MkdirAll(outputPath, 0755); err != nil {
return "", fmt.Errorf("failed to create output directory: %w", err)
}
filePath := filepath.Join(outputPath, filename)
file, err := os.Create(filePath)
if err != nil {
return "", fmt.Errorf("failed to create file: %w", err)
}
defer file.Close()
if _, err := io.Copy(file, reader); err != nil {
return "", fmt.Errorf("failed to write file: %w", err)
}
return filePath, nil
}
// GetFile returns a file reader for the given path
func (s *Storage) GetFile(filePath string) (*os.File, error) {
return os.Open(filePath)
}
// DeleteFile deletes a file
func (s *Storage) DeleteFile(filePath string) error {
return os.Remove(filePath)
}
// DeleteJobFiles deletes all files for a job
func (s *Storage) DeleteJobFiles(jobID int64) error {
jobPath := s.JobPath(jobID)
if err := os.RemoveAll(jobPath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to delete job files: %w", err)
}
outputPath := filepath.Join(s.outputsPath(), fmt.Sprintf("%d", jobID))
if err := os.RemoveAll(outputPath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed to delete output files: %w", err)
}
return nil
}
// FileExists checks if a file exists
func (s *Storage) FileExists(filePath string) bool {
_, err := os.Stat(filePath)
return err == nil
}
// GetFileSize returns the size of a file
func (s *Storage) GetFileSize(filePath string) (int64, error) {
info, err := os.Stat(filePath)
if err != nil {
return 0, err
}
return info.Size(), nil
}