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 }