123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- package storage
- import (
- "io"
- "os"
- "path/filepath"
- )
- // Storage defines the interface for object storage operations
- type Storage interface {
- // Bucket operations
- CreateBucket(name string) error
- DeleteBucket(name string) error
- BucketExists(name string) (bool, error)
- ListBuckets() ([]BucketInfo, error)
- // Object operations
- PutObject(bucket, key string, reader io.Reader) error
- GetObject(bucket, key string) (io.ReadCloser, *ObjectInfo, error)
- DeleteObject(bucket, key string) error
- ObjectExists(bucket, key string) (bool, error)
- GetObjectInfo(bucket, key string) (*ObjectInfo, error)
- ListObjects(bucket string) ([]ObjectInfo, error)
- }
- // FileSystemStorage implements Storage using the local file system
- type FileSystemStorage struct {
- baseDir string
- }
- // NewFileSystemStorage creates a new file system storage instance
- func NewFileSystemStorage(baseDir string) (*FileSystemStorage, error) {
- if err := os.MkdirAll(baseDir, 0755); err != nil {
- return nil, err
- }
- return &FileSystemStorage{
- baseDir: baseDir,
- }, nil
- }
- // CreateBucket creates a new bucket directory
- func (fs *FileSystemStorage) CreateBucket(name string) error {
- bucketPath := filepath.Join(fs.baseDir, name)
- // Check if bucket already exists
- if _, err := os.Stat(bucketPath); err == nil {
- return ErrBucketAlreadyExists
- }
- return os.MkdirAll(bucketPath, 0755)
- }
- // DeleteBucket removes a bucket directory
- func (fs *FileSystemStorage) DeleteBucket(name string) error {
- bucketPath := filepath.Join(fs.baseDir, name)
- return os.RemoveAll(bucketPath)
- }
- // BucketExists checks if a bucket exists
- func (fs *FileSystemStorage) BucketExists(name string) (bool, error) {
- bucketPath := filepath.Join(fs.baseDir, name)
- _, err := os.Stat(bucketPath)
- if os.IsNotExist(err) {
- return false, nil
- }
- if err != nil {
- return false, err
- }
- return true, nil
- }
- // ListBuckets lists all buckets
- func (fs *FileSystemStorage) ListBuckets() ([]BucketInfo, error) {
- entries, err := os.ReadDir(fs.baseDir)
- if err != nil {
- return nil, err
- }
- var buckets []BucketInfo
- for _, entry := range entries {
- if entry.IsDir() {
- info, err := entry.Info()
- if err != nil {
- continue
- }
- buckets = append(buckets, BucketInfo{
- Name: entry.Name(),
- CreationDate: info.ModTime(),
- })
- }
- }
- return buckets, nil
- }
- // PutObject stores an object
- func (fs *FileSystemStorage) PutObject(bucket, key string, reader io.Reader) error {
- bucketPath := filepath.Join(fs.baseDir, bucket)
- // Check if bucket exists
- if _, err := os.Stat(bucketPath); os.IsNotExist(err) {
- return ErrBucketNotFound
- }
- objectPath := filepath.Join(bucketPath, key)
- // Create parent directories if needed
- objectDir := filepath.Dir(objectPath)
- if err := os.MkdirAll(objectDir, 0755); err != nil {
- return err
- }
- // Create the file
- file, err := os.Create(objectPath)
- if err != nil {
- return err
- }
- defer file.Close()
- // Copy data to file
- _, err = io.Copy(file, reader)
- return err
- }
- // GetObject retrieves an object
- func (fs *FileSystemStorage) GetObject(bucket, key string) (io.ReadCloser, *ObjectInfo, error) {
- objectPath := filepath.Join(fs.baseDir, bucket, key)
- fileInfo, err := os.Stat(objectPath)
- if os.IsNotExist(err) {
- return nil, nil, ErrObjectNotFound
- }
- if err != nil {
- return nil, nil, err
- }
- file, err := os.Open(objectPath)
- if err != nil {
- return nil, nil, err
- }
- info := &ObjectInfo{
- Key: key,
- Size: fileInfo.Size(),
- LastModified: fileInfo.ModTime(),
- ETag: generateETag(fileInfo),
- }
- return file, info, nil
- }
- // DeleteObject removes an object
- func (fs *FileSystemStorage) DeleteObject(bucket, key string) error {
- objectPath := filepath.Join(fs.baseDir, bucket, key)
- err := os.Remove(objectPath)
- if os.IsNotExist(err) {
- return nil // S3 returns success even if object doesn't exist
- }
- return err
- }
- // ObjectExists checks if an object exists
- func (fs *FileSystemStorage) ObjectExists(bucket, key string) (bool, error) {
- objectPath := filepath.Join(fs.baseDir, bucket, key)
- _, err := os.Stat(objectPath)
- if os.IsNotExist(err) {
- return false, nil
- }
- if err != nil {
- return false, err
- }
- return true, nil
- }
- // GetObjectInfo retrieves object metadata
- func (fs *FileSystemStorage) GetObjectInfo(bucket, key string) (*ObjectInfo, error) {
- objectPath := filepath.Join(fs.baseDir, bucket, key)
- fileInfo, err := os.Stat(objectPath)
- if os.IsNotExist(err) {
- return nil, ErrObjectNotFound
- }
- if err != nil {
- return nil, err
- }
- return &ObjectInfo{
- Key: key,
- Size: fileInfo.Size(),
- LastModified: fileInfo.ModTime(),
- ETag: generateETag(fileInfo),
- }, nil
- }
- // ListObjects lists all objects in a bucket
- func (fs *FileSystemStorage) ListObjects(bucket string) ([]ObjectInfo, error) {
- bucketPath := filepath.Join(fs.baseDir, bucket)
- if _, err := os.Stat(bucketPath); os.IsNotExist(err) {
- return nil, ErrBucketNotFound
- }
- entries, err := os.ReadDir(bucketPath)
- if err != nil {
- return nil, err
- }
- var objects []ObjectInfo
- for _, entry := range entries {
- if !entry.IsDir() {
- info, err := entry.Info()
- if err != nil {
- continue
- }
- objects = append(objects, ObjectInfo{
- Key: entry.Name(),
- Size: info.Size(),
- LastModified: info.ModTime(),
- ETag: generateETag(info),
- })
- }
- }
- return objects, nil
- }
|