112 lines
3.5 KiB
Go
112 lines
3.5 KiB
Go
package file
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"knowlege-lsxd/internal/logger"
|
|
"knowlege-lsxd/internal/types/interfaces"
|
|
)
|
|
|
|
// localFileService implements the FileService interface for local file system storage
|
|
type localFileService struct {
|
|
baseDir string // Base directory for file storage
|
|
}
|
|
|
|
// NewLocalFileService creates a new local file service instance
|
|
func NewLocalFileService(baseDir string) interfaces.FileService {
|
|
return &localFileService{
|
|
baseDir: baseDir,
|
|
}
|
|
}
|
|
|
|
// SaveFile stores an uploaded file to the local file system
|
|
// The file is stored in a directory structure: baseDir/tenantID/knowledgeID/filename
|
|
// Returns the full file path or an error if saving fails
|
|
func (s *localFileService) SaveFile(ctx context.Context,
|
|
file *multipart.FileHeader, tenantID uint, knowledgeID string,
|
|
) (string, error) {
|
|
logger.Info(ctx, "Starting to save file locally")
|
|
logger.Infof(ctx, "File information: name=%s, size=%d, tenant ID=%d, knowledge ID=%s",
|
|
file.Filename, file.Size, tenantID, knowledgeID)
|
|
|
|
// Create storage directory with tenant and knowledge ID
|
|
dir := filepath.Join(s.baseDir, fmt.Sprintf("%d", tenantID), knowledgeID)
|
|
logger.Infof(ctx, "Creating directory: %s", dir)
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
logger.Errorf(ctx, "Failed to create directory: %v", err)
|
|
return "", fmt.Errorf("failed to create directory: %w", err)
|
|
}
|
|
|
|
// Generate unique filename using timestamp
|
|
ext := filepath.Ext(file.Filename)
|
|
filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
|
|
filePath := filepath.Join(dir, filename)
|
|
logger.Infof(ctx, "Generated file path: %s", filePath)
|
|
|
|
// Open source file for reading
|
|
logger.Info(ctx, "Opening source file")
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
logger.Errorf(ctx, "Failed to open source file: %v", err)
|
|
return "", fmt.Errorf("failed to open file: %w", err)
|
|
}
|
|
defer src.Close()
|
|
|
|
// Create destination file for writing
|
|
logger.Info(ctx, "Creating destination file")
|
|
dst, err := os.Create(filePath)
|
|
if err != nil {
|
|
logger.Errorf(ctx, "Failed to create destination file: %v", err)
|
|
return "", fmt.Errorf("failed to create file: %w", err)
|
|
}
|
|
defer dst.Close()
|
|
|
|
// Copy content from source to destination
|
|
logger.Info(ctx, "Copying file content")
|
|
if _, err := io.Copy(dst, src); err != nil {
|
|
logger.Errorf(ctx, "Failed to copy file content: %v", err)
|
|
return "", fmt.Errorf("failed to save file: %w", err)
|
|
}
|
|
|
|
logger.Infof(ctx, "File saved successfully: %s", filePath)
|
|
return filePath, nil
|
|
}
|
|
|
|
// GetFile retrieves a file from the local file system by its path
|
|
// Returns a ReadCloser for reading the file content
|
|
func (s *localFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {
|
|
logger.Infof(ctx, "Getting file: %s", filePath)
|
|
|
|
// Open the file for reading
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
logger.Errorf(ctx, "Failed to open file: %v", err)
|
|
return nil, fmt.Errorf("failed to open file: %w", err)
|
|
}
|
|
|
|
logger.Info(ctx, "File opened successfully")
|
|
return file, nil
|
|
}
|
|
|
|
// DeleteFile removes a file from the local file system
|
|
// Returns an error if deletion fails
|
|
func (s *localFileService) DeleteFile(ctx context.Context, filePath string) error {
|
|
logger.Infof(ctx, "Deleting file: %s", filePath)
|
|
|
|
// Remove the file
|
|
err := os.Remove(filePath)
|
|
if err != nil {
|
|
logger.Errorf(ctx, "Failed to delete file: %v", err)
|
|
return fmt.Errorf("failed to delete file: %w", err)
|
|
}
|
|
|
|
logger.Info(ctx, "File deleted successfully")
|
|
return nil
|
|
}
|