Change caching mechanism

This commit is contained in:
Svilen Markov 2024-06-11 12:10:11 +01:00
parent d4ed5afe93
commit 122d05346b
4 changed files with 61 additions and 13 deletions

View File

@ -1,8 +1,14 @@
package assets package assets
import ( import (
"crypto/md5"
"embed" "embed"
"encoding/hex"
"io"
"io/fs" "io/fs"
"log/slog"
"strconv"
"time"
) )
//go:embed static //go:embed static
@ -13,3 +19,38 @@ var _templateFS embed.FS
var PublicFS, _ = fs.Sub(_publicFS, "static") var PublicFS, _ = fs.Sub(_publicFS, "static")
var TemplateFS, _ = fs.Sub(_templateFS, "templates") var TemplateFS, _ = fs.Sub(_templateFS, "templates")
func getFSHash(files fs.FS) string {
hash := md5.New()
err := fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
file, err := files.Open(path)
if err != nil {
return err
}
if _, err := io.Copy(hash, file); err != nil {
return err
}
return nil
})
if err == nil {
return hex.EncodeToString(hash.Sum(nil))[:10]
}
slog.Warn("Could not compute assets cache", "err", err)
return strconv.FormatInt(time.Now().Unix(), 10)
}
var PublicFSHash = getFSHash(PublicFS)

View File

@ -6,7 +6,7 @@
"start_url": "/", "start_url": "/",
"icons": [ "icons": [
{ {
"src": "/static/app-icon.png", "src": "app-icon.png",
"type": "image/png", "type": "image/png",
"sizes": "512x512" "sizes": "512x512"
} }

View File

@ -11,12 +11,12 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Glance"> <meta name="apple-mobile-web-app-title" content="Glance">
<meta name="theme-color" content="{{ if ne nil .App.Config.Theme.BackgroundColor }}{{ .App.Config.Theme.BackgroundColor }}{{ else }}hsl(240, 8%, 9%){{ end }}"> <meta name="theme-color" content="{{ if ne nil .App.Config.Theme.BackgroundColor }}{{ .App.Config.Theme.BackgroundColor }}{{ else }}hsl(240, 8%, 9%){{ end }}">
<link rel="apple-touch-icon" sizes="512x512" href="/static/app-icon.png"> <link rel="apple-touch-icon" sizes="512x512" href="{{ .App.AssetPath "app-icon.png" }}">
<link rel="icon" type="image/png" sizes="50x50" href="/static/favicon.png"> <link rel="icon" type="image/png" sizes="50x50" href="{{ .App.AssetPath "favicon.png" }}">
<link rel="manifest" href="/static/manifest.json"> <link rel="manifest" href="/static/manifest.json">
<link rel="icon" type="image/png" href="/static/favicon.png" /> <link rel="icon" type="image/png" href="{{ .App.AssetPath "favicon.png" }}" />
<link rel="stylesheet" href="/static/main.css?v={{ .App.Config.Server.StartedAt.Unix }}"> <link rel="stylesheet" href="{{ .App.AssetPath "main.css" }}">
<script async src="/static/main.js?v={{ .App.Config.Server.StartedAt.Unix }}"></script> <script async src="{{ .App.AssetPath "main.js" }}"></script>
{{ block "document-head-after" . }}{{ end }} {{ block "document-head-after" . }}{{ end }}
</head> </head>
<body> <body>

View File

@ -38,10 +38,10 @@ type Theme struct {
} }
type Server struct { type Server struct {
Host string `yaml:"host"` Host string `yaml:"host"`
Port uint16 `yaml:"port"` Port uint16 `yaml:"port"`
AssetsPath string `yaml:"assets-path"` AssetsPath string `yaml:"assets-path"`
StartedAt time.Time `yaml:"-"` AssetsHash string `yaml:"-"`
} }
type Column struct { type Column struct {
@ -189,7 +189,13 @@ func FileServerWithCache(fs http.FileSystem, cacheDuration time.Duration) http.H
}) })
} }
func (a *Application) AssetPath(asset string) string {
return "/static/" + a.Config.Server.AssetsHash + "/" + asset
}
func (a *Application) Serve() error { func (a *Application) Serve() error {
a.Config.Server.AssetsHash = assets.PublicFSHash
// TODO: add gzip support, static files must have their gzipped contents cached // TODO: add gzip support, static files must have their gzipped contents cached
// TODO: add HTTPS support // TODO: add HTTPS support
mux := http.NewServeMux() mux := http.NewServeMux()
@ -197,7 +203,10 @@ func (a *Application) Serve() error {
mux.HandleFunc("GET /{$}", a.HandlePageRequest) mux.HandleFunc("GET /{$}", a.HandlePageRequest)
mux.HandleFunc("GET /{page}", a.HandlePageRequest) mux.HandleFunc("GET /{page}", a.HandlePageRequest)
mux.HandleFunc("GET /api/pages/{page}/content/{$}", a.HandlePageContentRequest) mux.HandleFunc("GET /api/pages/{page}/content/{$}", a.HandlePageContentRequest)
mux.Handle("GET /static/{path...}", http.StripPrefix("/static/", FileServerWithCache(http.FS(assets.PublicFS), 2*time.Hour))) mux.Handle(
fmt.Sprintf("GET /static/%s/{path...}", a.Config.Server.AssetsHash),
http.StripPrefix("/static/"+a.Config.Server.AssetsHash, FileServerWithCache(http.FS(assets.PublicFS), 8*time.Hour)),
)
if a.Config.Server.AssetsPath != "" { if a.Config.Server.AssetsPath != "" {
absAssetsPath, err := filepath.Abs(a.Config.Server.AssetsPath) absAssetsPath, err := filepath.Abs(a.Config.Server.AssetsPath)
@ -216,8 +225,6 @@ func (a *Application) Serve() error {
Handler: mux, Handler: mux,
} }
a.Config.Server.StartedAt = time.Now()
slog.Info("Starting server", "host", a.Config.Server.Host, "port", a.Config.Server.Port) slog.Info("Starting server", "host", a.Config.Server.Host, "port", a.Config.Server.Port)
return server.ListenAndServe() return server.ListenAndServe()
} }