Agate/store/filesystem/filesystem.go

109 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package filesystem
import (
"context"
"fmt"
"gitea.unprism.ru/KRBL/Agate"
"gitea.unprism.ru/KRBL/Agate/store"
"io"
"os"
"path/filepath"
)
const blobExtension = ".zip"
// fileSystemStore реализует интерфейс store.BlobStore с использованием локальной файловой системы.
type fileSystemStore struct {
baseDir string // Директория для хранения блобов (архивов)
}
// NewFileSystemStore создает новое хранилище блобов в указанной директории.
func NewFileSystemStore(baseDir string) (store.BlobStore, error) {
// Убедимся, что директория существует
if err := os.MkdirAll(baseDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create base directory %s for filesystem blob store: %w", baseDir, err)
}
return &fileSystemStore{baseDir: baseDir}, nil
}
// getBlobPath формирует полный путь к файлу блоба.
func (fs *fileSystemStore) getBlobPath(snapshotID string) string {
// Используем ID снапшота в качестве имени файла
return filepath.Join(fs.baseDir, snapshotID+blobExtension)
}
// StoreBlob сохраняет данные из reader в файл в baseDir.
func (fs *fileSystemStore) StoreBlob(ctx context.Context, snapshotID string, reader io.Reader) (string, error) {
blobPath := fs.getBlobPath(snapshotID)
// Создаем или перезаписываем файл
file, err := os.Create(blobPath)
if err != nil {
return "", fmt.Errorf("failed to create blob file %s: %w", blobPath, err)
}
defer file.Close() // Гарантируем закрытие файла
// Копируем данные из ридера в файл
_, err = io.Copy(file, reader)
if err != nil {
// Если произошла ошибка копирования, удаляем неполный файл
os.Remove(blobPath)
return "", fmt.Errorf("failed to write data to blob file %s: %w", blobPath, err)
}
// Возвращаем путь к созданному файлу
return blobPath, nil
}
// RetrieveBlob открывает файл блоба и возвращает его как io.ReadCloser.
func (fs *fileSystemStore) RetrieveBlob(ctx context.Context, snapshotID string) (io.ReadCloser, error) {
blobPath := fs.getBlobPath(snapshotID)
// Открываем файл для чтения
file, err := os.Open(blobPath)
if err != nil {
if os.IsNotExist(err) {
// Если файл не найден, возвращаем кастомную ошибку
return nil, agate.ErrNotFound
}
return nil, fmt.Errorf("failed to open blob file %s: %w", blobPath, err)
}
// Возвращаем открытый файл (*os.File реализует io.ReadCloser)
return file, nil
}
// DeleteBlob удаляет файл блоба из файловой системы.
func (fs *fileSystemStore) DeleteBlob(ctx context.Context, snapshotID string) error {
blobPath := fs.getBlobPath(snapshotID)
// Удаляем файл
err := os.Remove(blobPath)
if err != nil {
if os.IsNotExist(err) {
// Если файл и так не существует, это не ошибка
return nil
}
// Если произошла другая ошибка при удалении
return fmt.Errorf("failed to delete blob file %s: %w", blobPath, err)
}
return nil
}
// GetBlobPath возвращает путь к файлу блоба, если он существует.
func (fs *fileSystemStore) GetBlobPath(ctx context.Context, snapshotID string) (string, error) {
blobPath := fs.getBlobPath(snapshotID)
// Проверяем существование файла
if _, err := os.Stat(blobPath); err != nil {
if os.IsNotExist(err) {
return "", agate.ErrNotFound
}
return "", fmt.Errorf("failed to stat blob file %s: %w", blobPath, err)
}
// Файл существует, возвращаем путь
return blobPath, nil
}