l_ai_knowledge/internal/application/service/file/local.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
}