Monorepo for Tangled tangled.org

appview/pages: fix concurrent write in dev mode

When in dev mode. Concurrent writes to the template map will cause a
concurrent write panic and crash appview. Quickly moving between pages
can trigger this crash. This is addressed by adding a RWMutex on the
templates. RWMutex allows multiple readers, but only one writer.

Signed-off-by: Ciel <jamie@longest.voyage>

Changed files
+11 -1
appview
pages
+11 -1
appview/pages/pages.go
··· 14 "os" 15 "path/filepath" 16 "strings" 17 18 "tangled.sh/tangled.sh/core/appview/commitverify" 19 "tangled.sh/tangled.sh/core/appview/config" ··· 39 var Files embed.FS 40 41 type Pages struct { 42 - t map[string]*template.Template 43 avatar config.AvatarConfig 44 dev bool 45 embedFS embed.FS ··· 56 } 57 58 p := &Pages{ 59 t: make(map[string]*template.Template), 60 dev: config.Core.Dev, 61 avatar: config.Avatar, ··· 147 } 148 149 log.Printf("total templates loaded: %d", len(templates)) 150 p.t = templates 151 } 152 ··· 207 } 208 209 // Update the template in the map 210 p.t[name] = tmpl 211 log.Printf("template reloaded from disk: %s", name) 212 return nil ··· 221 } 222 } 223 224 tmpl, exists := p.t[templateName] 225 if !exists { 226 return fmt.Errorf("template not found: %s", templateName)
··· 14 "os" 15 "path/filepath" 16 "strings" 17 + "sync" 18 19 "tangled.sh/tangled.sh/core/appview/commitverify" 20 "tangled.sh/tangled.sh/core/appview/config" ··· 40 var Files embed.FS 41 42 type Pages struct { 43 + mu sync.RWMutex 44 + t map[string]*template.Template 45 + 46 avatar config.AvatarConfig 47 dev bool 48 embedFS embed.FS ··· 59 } 60 61 p := &Pages{ 62 + mu: sync.RWMutex{}, 63 t: make(map[string]*template.Template), 64 dev: config.Core.Dev, 65 avatar: config.Avatar, ··· 151 } 152 153 log.Printf("total templates loaded: %d", len(templates)) 154 + p.mu.Lock() 155 + defer p.mu.Unlock() 156 p.t = templates 157 } 158 ··· 213 } 214 215 // Update the template in the map 216 + p.mu.Lock() 217 + defer p.mu.Unlock() 218 p.t[name] = tmpl 219 log.Printf("template reloaded from disk: %s", name) 220 return nil ··· 229 } 230 } 231 232 + p.mu.RLock() 233 + defer p.mu.RUnlock() 234 tmpl, exists := p.t[templateName] 235 if !exists { 236 return fmt.Errorf("template not found: %s", templateName)