github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/assets/model/common.go (about)

     1  package model
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"path"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/cozy/cozy-stack/pkg/filetype"
    11  )
    12  
    13  // sumLen defines the number of characters of the shasum to include in a
    14  // filename
    15  const sumLen = 10
    16  
    17  // AssetOption is used to insert a dynamic asset.
    18  type AssetOption struct {
    19  	Name     string `json:"name"`
    20  	Context  string `json:"context"`
    21  	URL      string `json:"url"`
    22  	Shasum   string `json:"shasum"`
    23  	IsCustom bool   `json:"is_custom,omitempty"`
    24  }
    25  
    26  // Asset holds unzipped read-only file contents and file metadata.
    27  type Asset struct {
    28  	AssetOption
    29  	Etag        string `json:"etag"`
    30  	NameWithSum string `json:"name_with_sum"`
    31  	Mime        string `json:"mime"`
    32  
    33  	brotliData []byte
    34  	brotliSize string
    35  	rawData    []byte
    36  	rawSize    string
    37  }
    38  
    39  // GetData returns the raw data as a slice of bytes.
    40  func (f *Asset) GetData() []byte {
    41  	return f.rawData
    42  }
    43  
    44  // Size returns the size in bytes of the asset (no compression).
    45  func (f *Asset) Size() string {
    46  	return f.rawSize
    47  }
    48  
    49  // Reader returns a bytes.Reader for the asset content (no compression).
    50  func (f *Asset) Reader() *bytes.Reader {
    51  	return bytes.NewReader(f.rawData)
    52  }
    53  
    54  // BrotliSize returns the size of the compressed version of the asset.
    55  func (f *Asset) BrotliSize() string {
    56  	return f.brotliSize
    57  }
    58  
    59  // BrotliReader returns a bytes.Reader for the compressed content of the asset.
    60  func (f *Asset) BrotliReader() *bytes.Reader {
    61  	return bytes.NewReader(f.brotliData)
    62  }
    63  
    64  // NameWithSum returns the filename with its shasum
    65  func NameWithSum(name, sum string) string {
    66  	nameWithSum := name
    67  
    68  	nameBase := path.Base(name)
    69  	if off := strings.IndexByte(nameBase, '.'); off >= 0 {
    70  		nameDir := path.Dir(name)
    71  		nameWithSum = path.Join("/", nameDir, nameBase[:off]+"."+sum[:sumLen]+nameBase[off:])
    72  	}
    73  
    74  	return nameWithSum
    75  }
    76  
    77  // NormalizeAssetName ensures the asset name always start with a "/"
    78  func NormalizeAssetName(name string) string {
    79  	return path.Join("/", name)
    80  }
    81  
    82  // NewAsset creates a new asset
    83  func NewAsset(opt AssetOption, rawData, brotliData []byte) *Asset {
    84  	mime := filetype.ByExtension(path.Ext(opt.Name))
    85  	if mime == "" {
    86  		mime = filetype.Match(rawData)
    87  	}
    88  
    89  	opt.Name = NormalizeAssetName(opt.Name)
    90  
    91  	sumx := opt.Shasum
    92  	etag := fmt.Sprintf(`"%s"`, sumx[:sumLen])
    93  	nameWithSum := NameWithSum(opt.Name, sumx)
    94  
    95  	return &Asset{
    96  		AssetOption: opt,
    97  		Etag:        etag,
    98  		NameWithSum: nameWithSum,
    99  		Mime:        mime,
   100  		brotliData:  brotliData,
   101  		brotliSize:  strconv.Itoa(len(brotliData)),
   102  
   103  		rawData: rawData,
   104  		rawSize: strconv.Itoa(len(rawData)),
   105  	}
   106  }