@@ -2,12 +2,15 @@ package frontend
22
33import (
44 "embed"
5+ "encoding/hex"
56 "fmt"
7+ "hash"
68 "html/template"
79 "net/http"
810 "os"
911 "path"
1012
13+ "github.com/gofrs/uuid/v5"
1114 "github.com/scribble-rs/scribble.rs/internal/translations"
1215)
1316
@@ -31,6 +34,9 @@ func init() {
3134// BasePageConfig is data that all pages require to function correctly, no matter
3235// whether error page or lobby page.
3336type BasePageConfig struct {
37+ checksums map [string ]string
38+ hash hash.Hash
39+
3440 // Version is the tagged source code version of this build. Can be empty for dev
3541 // builds. Untagged commits will be of format `tag-N-gSHA`.
3642 Version string `json:"version"`
@@ -45,10 +51,37 @@ type BasePageConfig struct {
4551 // domain. So it could be https://painting.com. This is required for some
4652 // non critical functionality, such as metadata tags.
4753 RootURL string `json:"rootUrl"`
48- // CacheBust is a string that is appended to all resources to prevent
49- // browsers from using cached data of a previous version, but still have
50- // long lived max age values.
51- CacheBust string `json:"cacheBust"`
54+ }
55+
56+ var fallbackChecksum = uuid .Must (uuid .NewV4 ()).String ()
57+
58+ func (baseConfig * BasePageConfig ) Hash (key string , bytes []byte ) error {
59+ _ , alreadyExists := baseConfig .checksums [key ]
60+ if alreadyExists {
61+ return fmt .Errorf ("duplicate hash key '%s'" , key )
62+ }
63+ if _ , err := baseConfig .hash .Write (bytes ); err != nil {
64+ return fmt .Errorf ("error hashing '%s': %w" , key , err )
65+ }
66+ baseConfig .checksums [key ] = hex .EncodeToString (baseConfig .hash .Sum (nil ))
67+ baseConfig .hash .Reset ()
68+ return nil
69+ }
70+
71+ // CacheBust is a string that is appended to all resources to prevent
72+ // browsers from using cached data of a previous version, but still have
73+ // long lived max age values.
74+ func (baseConfig * BasePageConfig ) withCacheBust (file string ) string {
75+ checksum , found := baseConfig .checksums [file ]
76+ if ! found {
77+ // No need to crash over
78+ return fmt .Sprintf ("%s?cache_bust=%s" , file , fallbackChecksum )
79+ }
80+ return fmt .Sprintf ("%s?cache_bust=%s" , file , checksum )
81+ }
82+
83+ func (baseConfig * BasePageConfig ) WithCacheBust (file string ) template.HTMLAttr {
84+ return template .HTMLAttr (baseConfig .withCacheBust (file ))
5285}
5386
5487func (handler * SSRHandler ) cspMiddleware (handleFunc http.HandlerFunc ) http.HandlerFunc {
@@ -108,8 +141,8 @@ func (handler *SSRHandler) SetupRoutes(register func(string, string, http.Handle
108141 }),
109142 ).ServeHTTP ,
110143 )
111- register ("GET" , path .Join (handler .cfg .RootPath , "lobbyJs " ), handler .lobbyJs )
112- register ("GET" , path .Join (handler .cfg .RootPath , "indexJs " ), handler .indexJs )
144+ register ("GET" , path .Join (handler .cfg .RootPath , "lobby.js " ), handler .lobbyJs )
145+ register ("GET" , path .Join (handler .cfg .RootPath , "index.js " ), handler .indexJs )
113146 registerWithCsp ("GET" , path .Join (handler .cfg .RootPath , "ssrEnterLobby" , "{lobby_id}" ), handler .ssrEnterLobby )
114147 registerWithCsp ("POST" , path .Join (handler .cfg .RootPath , "ssrCreateLobby" ), handler .ssrCreateLobby )
115148}
0 commit comments