ZDDC/zddc/internal/apps/embed.go
2026-06-11 13:32:31 -05:00

84 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package apps
import (
"crypto/sha256"
"encoding/hex"
_ "embed"
"sync"
)
// Embedded fallback: tool HTMLs from the time the binary was built.
// Used as a last-resort served-bytes when (cache miss) AND (upstream
// unreachable) AND (no operator override) — see handler.go.
//
// The files are populated by the top-level build.sh, which copies the
// freshly-built dist/<tool>.html into ./embedded/ before `go build` runs.
// Empty placeholder files are checked in so the package compiles when no
// build has been run yet (CI bootstrap, fresh clone, etc.); at runtime an
// empty embedded body is treated as "no embedded fallback available."
//go:embed embedded/archive.html
var embeddedArchive []byte
//go:embed embedded/transmittal.html
var embeddedTransmittal []byte
//go:embed embedded/classifier.html
var embeddedClassifier []byte
//go:embed embedded/index.html
var embeddedLanding []byte
//go:embed embedded/browse.html
var embeddedBrowse []byte
// EmbeddedBytes returns the embedded HTML for app, or nil if either app is
// not one of the canonical names or the embedded slot is empty (no build
// has populated it).
func EmbeddedBytes(app string) []byte {
var b []byte
switch app {
case "archive":
b = embeddedArchive
case "transmittal":
b = embeddedTransmittal
case "classifier":
b = embeddedClassifier
case "landing":
b = embeddedLanding
case "browse":
b = embeddedBrowse
default:
return nil
}
if len(b) == 0 {
return nil
}
return b
}
// EmbeddedETag returns a strong ETag (sha256-hex prefix, 32 chars) for the
// app's embedded bytes. Computed lazily on first call per-app and memoized
// — the embedded slot is fixed for the binary's lifetime, so the ETag
// changes only when the binary is redeployed. Empty slot returns "".
//
// Used by apps.Server.serveEmbedded to issue conditional-GET-friendly
// responses: with this ETag + Cache-Control: max-age=0, must-revalidate,
// every page load revalidates and gets a 304 unless the binary has been
// updated. Saves re-transmitting 50920 KB tool HTMLs on every reload.
func EmbeddedETag(app string) string {
if v, ok := etagCacheByApp.Load(app); ok {
return v.(string)
}
body := EmbeddedBytes(app)
if body == nil {
return ""
}
sum := sha256.Sum256(body)
etag := hex.EncodeToString(sum[:])[:32]
etagCacheByApp.Store(app, etag)
return etag
}
// etagCacheByApp memoizes EmbeddedETag results keyed by app name.
var etagCacheByApp sync.Map