127 lines
3.4 KiB
Go
127 lines
3.4 KiB
Go
package file
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"path/filepath"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
"knowlege-lsxd/internal/types/interfaces"
|
|
)
|
|
|
|
// minioFileService MinIO file service implementation
|
|
type minioFileService struct {
|
|
client *minio.Client
|
|
bucketName string
|
|
}
|
|
|
|
// NewMinioFileService creates a MinIO file service
|
|
func NewMinioFileService(endpoint,
|
|
accessKeyID, secretAccessKey, bucketName string, useSSL bool) (interfaces.FileService, error) {
|
|
// Initialize MinIO client
|
|
client, err := minio.New(endpoint, &minio.Options{
|
|
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
|
|
Secure: useSSL,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize MinIO client: %w", err)
|
|
}
|
|
|
|
// Check if bucket exists, create if not
|
|
exists, err := client.BucketExists(context.Background(), bucketName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to check bucket: %w", err)
|
|
}
|
|
|
|
if !exists {
|
|
err = client.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create bucket: %w", err)
|
|
}
|
|
}
|
|
|
|
return &minioFileService{
|
|
client: client,
|
|
bucketName: bucketName,
|
|
}, nil
|
|
}
|
|
|
|
// SaveFile saves a file to MinIO
|
|
func (s *minioFileService) SaveFile(ctx context.Context,
|
|
file *multipart.FileHeader, tenantID uint, knowledgeID string,
|
|
) (string, error) {
|
|
// Generate object name
|
|
ext := filepath.Ext(file.Filename)
|
|
objectName := fmt.Sprintf("%d/%s/%s%s", tenantID, knowledgeID, uuid.New().String(), ext)
|
|
|
|
// Open file
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to open file: %w", err)
|
|
}
|
|
defer src.Close()
|
|
|
|
// Upload file to MinIO
|
|
_, err = s.client.PutObject(ctx, s.bucketName, objectName, src, file.Size, minio.PutObjectOptions{
|
|
ContentType: file.Header.Get("Content-Type"),
|
|
})
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to upload file to MinIO: %w", err)
|
|
}
|
|
|
|
// Return the complete path to the object
|
|
return fmt.Sprintf("minio://%s/%s", s.bucketName, objectName), nil
|
|
}
|
|
|
|
// GetFile gets a file from MinIO
|
|
func (s *minioFileService) GetFile(ctx context.Context, filePath string) (io.ReadCloser, error) {
|
|
// Parse MinIO path
|
|
// Format: minio://bucketName/objectName
|
|
if len(filePath) < 9 || filePath[:8] != "minio://" {
|
|
return nil, fmt.Errorf("invalid MinIO file path: %s", filePath)
|
|
}
|
|
|
|
// Extract object name
|
|
objectName := filePath[9+len(s.bucketName):]
|
|
if objectName[0] == '/' {
|
|
objectName = objectName[1:]
|
|
}
|
|
|
|
// Get object
|
|
obj, err := s.client.GetObject(ctx, s.bucketName, objectName, minio.GetObjectOptions{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get file from MinIO: %w", err)
|
|
}
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
// DeleteFile deletes a file
|
|
func (s *minioFileService) DeleteFile(ctx context.Context, filePath string) error {
|
|
// Parse MinIO path
|
|
// Format: minio://bucketName/objectName
|
|
if len(filePath) < 9 || filePath[:8] != "minio://" {
|
|
return fmt.Errorf("invalid MinIO file path: %s", filePath)
|
|
}
|
|
|
|
// Extract object name
|
|
objectName := filePath[9+len(s.bucketName):]
|
|
if objectName[0] == '/' {
|
|
objectName = objectName[1:]
|
|
}
|
|
|
|
// Delete object
|
|
err := s.client.RemoveObject(ctx, s.bucketName, objectName, minio.RemoveObjectOptions{
|
|
GovernanceBypass: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|