github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/emb/embed.go (about) 1 package emb 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "crypto/md5" 7 "encoding/hex" 8 "io" 9 "io/fs" 10 "mime" 11 "net/http" 12 "path/filepath" 13 "strings" 14 ) 15 16 // from https://github.com/pyros2097/go-embed 17 18 func AssetString(f fs.FS, name string, useGzip bool) string { 19 return string(AssetBytes(f, name, useGzip)) 20 } 21 22 func AssetBytes(f fs.FS, name string, useGzip bool) (data []byte) { 23 data, _, _, _ = Asset(f, name, useGzip) 24 return data 25 } 26 27 // Asset Gets the file from embed.FS if debug otherwise gets it from the stored 28 // data returns the data, the md5 hash of its content and its content type 29 // and error if it is not found. 30 func Asset(f fs.FS, name string, useGzip bool) (data []byte, hash, contentType string, err error) { 31 if strings.HasPrefix(name, "/") { 32 name = name[1:] 33 } 34 35 var fn fs.File 36 fn, err = f.Open(name) 37 if err != nil { 38 return nil, "", "", err 39 } 40 data, err = io.ReadAll(fn) 41 if err != nil { 42 return nil, "", "", err 43 } 44 45 if useGzip && len(data) > 0 { 46 var b bytes.Buffer 47 w := gzip.NewWriter(&b) 48 _, _ = w.Write(data) 49 _ = w.Close() 50 data = b.Bytes() 51 } 52 53 sum := md5.Sum(data) 54 contentType = mime.TypeByExtension(filepath.Ext(name)) 55 return data, hex.EncodeToString(sum[:]), contentType, nil 56 } 57 58 func FileHandler(f fs.FS, name string) http.HandlerFunc { 59 return func(w http.ResponseWriter, r *http.Request) { ServeFile(f, name, w, r) } 60 } 61 62 func ServeFile(f fs.FS, name string, w http.ResponseWriter, r *http.Request) { 63 ServeFileGzip(f, name, w, r, true) 64 } 65 66 func ServeFileGzip(f fs.FS, name string, w http.ResponseWriter, r *http.Request, useGzip bool) { 67 if useGzip && w.Header().Get("Content-Encoding") == "gzip" { 68 useGzip = false // if already gzip outside 69 } 70 71 data, hash, contentType, err := Asset(f, name, useGzip) 72 if err != nil { 73 http.Error(w, err.Error(), http.StatusInternalServerError) 74 return 75 } 76 77 if r.Header.Get("If-None-Match") == hash { 78 w.WriteHeader(http.StatusNotModified) 79 return 80 } 81 82 if useGzip { 83 w.Header().Set("Content-Encoding", "gzip") 84 } 85 w.Header().Set("Content-Type", contentType) 86 w.Header().Add("Cache-Control", "public, max-age=31536000") 87 w.Header().Add("ETag", hash) 88 w.WriteHeader(http.StatusOK) 89 _, _ = w.Write(data) 90 }