github.com/soulteary/pocket-bookcase@v0.0.0-20240428065142-0b5a9a0fc98a/internal/http/response/file.go (about)

     1  package response
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  
     8  	"github.com/gin-gonic/gin"
     9  	"github.com/soulteary/pocket-bookcase/internal/model"
    10  )
    11  
    12  // SendFile sends file to client with caching header
    13  func SendFile(c *gin.Context, storageDomain model.StorageDomain, path string) {
    14  	c.Header("Cache-Control", "public, max-age=86400")
    15  
    16  	if !storageDomain.FileExists(path) {
    17  		c.AbortWithStatus(http.StatusNotFound)
    18  		return
    19  	}
    20  
    21  	info, err := storageDomain.Stat(path)
    22  	if err != nil {
    23  		c.AbortWithStatus(http.StatusInternalServerError)
    24  		return
    25  	}
    26  
    27  	c.Header("ETag", fmt.Sprintf("W/%x-%x", info.ModTime().Unix(), info.Size()))
    28  
    29  	// TODO: Find a better way to send the file to the client from the FS, probably making a
    30  	// conversion between afero.Fs and http.FileSystem to use c.FileFromFS.
    31  	fileContent, err := storageDomain.FS().Open(path)
    32  	if err != nil {
    33  		c.AbortWithStatus(http.StatusInternalServerError)
    34  		return
    35  	}
    36  
    37  	_, err = io.Copy(c.Writer, fileContent)
    38  	if err != nil {
    39  		c.AbortWithStatus(http.StatusInternalServerError)
    40  		return
    41  	}
    42  }