feat: close buttons as a red cross in a square; static files revalidated by content, so a release reaches the browser at once

This commit is contained in:
redtea committed 2026-10-14 19:24:12 +03:00
1 parent 55db8f03b3
commit 8eb2bbd35d
3 files changed
+38 -3

No files matched your search

+33 -1
View File
@@ -1,7 +1,9 @@
package server
import (
"crypto/sha256"
"embed"
"encoding/hex"
"html/template"
"io/fs"
"log"
@@ -184,7 +186,7 @@ func (s *Server) Handler() http.Handler {
// Static assets (xterm.js etc.) from the embedded FS.
staticFS, _ := fs.Sub(webFS, "web/static")
mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
mux.Handle("GET /static/", http.StripPrefix("/static/", staticHandler(staticFS)))
// Public: install script + agent binary downloads.
mux.HandleFunc("GET /install.sh", s.handleInstallScript)
@@ -333,3 +335,33 @@ func clientIP(r *http.Request) string {
}
return host
}
// staticHandler serves the embedded assets with a content hash as ETag. The
// browser asks each time whether a file changed (no-cache) and gets a 304
// when it did not, so a new release reaches it at once without reloading
// what stayed the same.
func staticHandler(fsys fs.FS) http.Handler {
files := http.FileServer(http.FS(fsys))
var mu sync.Mutex
etags := map[string]string{}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
name := strings.TrimPrefix(r.URL.Path, "/")
mu.Lock()
tag, ok := etags[name]
mu.Unlock()
if !ok {
if data, err := fs.ReadFile(fsys, name); err == nil {
sum := sha256.Sum256(data)
tag = `"` + hex.EncodeToString(sum[:8]) + `"`
}
mu.Lock()
etags[name] = tag
mu.Unlock()
}
if tag != "" {
w.Header().Set("ETag", tag)
}
w.Header().Set("Cache-Control", "no-cache")
files.ServeHTTP(w, r)
})
}