github.com/soulteary/pocket-bookcase@v0.0.0-20240428065142-0b5a9a0fc98a/internal/domains/storage.go (about)

     1  package domains
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/fs"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/soulteary/pocket-bookcase/internal/dependencies"
    11  	"github.com/soulteary/pocket-bookcase/internal/model"
    12  	"github.com/spf13/afero"
    13  )
    14  
    15  type StorageDomain struct {
    16  	deps *dependencies.Dependencies
    17  	fs   afero.Fs
    18  }
    19  
    20  func NewStorageDomain(deps *dependencies.Dependencies, fs afero.Fs) *StorageDomain {
    21  	return &StorageDomain{
    22  		deps: deps,
    23  		fs:   fs,
    24  	}
    25  }
    26  
    27  // Stat returns the FileInfo structure describing file.
    28  func (d *StorageDomain) Stat(name string) (fs.FileInfo, error) {
    29  	return d.fs.Stat(name)
    30  }
    31  
    32  // FS returns the filesystem used by this domain.
    33  func (d *StorageDomain) FS() afero.Fs {
    34  	return d.fs
    35  }
    36  
    37  // FileExists checks if a file exists in storage.
    38  func (d *StorageDomain) FileExists(name string) bool {
    39  	info, err := d.Stat(name)
    40  	return err == nil && !info.IsDir()
    41  }
    42  
    43  // DirExists checks if a directory exists in storage.
    44  func (d *StorageDomain) DirExists(name string) bool {
    45  	info, err := d.Stat(name)
    46  	return err == nil && info.IsDir()
    47  }
    48  
    49  // WriteData writes bytes data to a file in storage.
    50  // CAUTION: This function will overwrite existing file.
    51  func (d *StorageDomain) WriteData(dst string, data []byte) error {
    52  	// Create directory if not exist
    53  	dir := filepath.Dir(dst)
    54  	if !d.DirExists(dir) {
    55  		err := d.fs.MkdirAll(dir, os.ModePerm)
    56  		if err != nil {
    57  			return err
    58  		}
    59  	}
    60  
    61  	// Create file
    62  	file, err := d.fs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.ModePerm)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	defer file.Close()
    67  
    68  	// Write data
    69  	_, err = file.Write(data)
    70  	return err
    71  }
    72  
    73  // WriteFile writes a file to storage.
    74  func (d *StorageDomain) WriteFile(dst string, tmpFile *os.File) error {
    75  	if dst != "" && !d.DirExists(dst) {
    76  		err := d.fs.MkdirAll(filepath.Dir(dst), model.DataDirPerm)
    77  		if err != nil {
    78  			return fmt.Errorf("failed to create destination dir: %v", err)
    79  		}
    80  	}
    81  
    82  	dstFile, err := d.fs.Create(dst)
    83  	if err != nil {
    84  		return fmt.Errorf("failed to create destination file: %v", err)
    85  	}
    86  	defer dstFile.Close()
    87  
    88  	_, err = tmpFile.Seek(0, io.SeekStart)
    89  	if err != nil {
    90  		return fmt.Errorf("failed to rewind temporary file: %v", err)
    91  	}
    92  
    93  	_, err = io.Copy(dstFile, tmpFile)
    94  	if err != nil {
    95  		return fmt.Errorf("failed to copy file to the destination")
    96  	}
    97  
    98  	return nil
    99  }