burning.moe/internal/render/render.go
Lilian Jónsdóttir 8a2319033e refactor how template data is handled + load template data from file
Generating template data is now handled by templatedata instead of handlers.
Renderer doesn't recieve any data, but now asks for data from templatedata.
Additionally, template data is loaded from file (too lazy to split that into its own commit).
Templates in ./templates/name.page.tmpl will have data loaded from ./templates/name.page.json
2024-01-23 16:10:15 -08:00

131 lines
3.6 KiB
Go

package render
import (
"bytes"
"fmt"
"html/template"
"net/http"
"path/filepath"
"time"
"git.burning.moe/celediel/burning.moe/internal/config"
"git.burning.moe/celediel/burning.moe/internal/models"
)
const (
templatesDir string = "./templates/"
layoutGlob string = "*.layout.tmpl"
pageGlob string = "*.page.tmpl"
)
var app *config.AppConfig
// Initialise the render package.
func Initialise(a *config.AppConfig) {
var err error
app = a
if app.UseCache {
app.TemplateCache, err = GenerateNewTemplateCache()
}
if err != nil {
app.Logger.Fatal("Error generating template cache, bailing out!")
}
}
// GenerateNewTemplateCache generates a new template cache.
func GenerateNewTemplateCache() (models.TemplateCache, error) {
// start with an empty map
cache := models.TemplateCache{}
cache.Cache = map[string]models.TemplateCacheItem{}
// Generate a list of pages based on globs
pages, err := filepath.Glob(templatesDir + pageGlob)
// a nice try catch would be pretty cool right about here
if err != nil {
return cache, err
}
// Iterate each page, parsing the file and adding it to the cache
for _, page := range pages {
name := filepath.Base(page)
app.Logger.Info("Generating template " + name)
generatedAt := time.Now()
templateSet, err := template.New(name).ParseFiles(page)
if err != nil {
return cache, err
}
// Glob and parse any layouts found
layouts, err := filepath.Glob(templatesDir + layoutGlob)
if err != nil {
return cache, err
}
if len(layouts) > 0 {
templateSet, err = templateSet.ParseGlob(templatesDir + layoutGlob)
if err != nil {
return cache, err
}
}
cache.Cache[name] = models.TemplateCacheItem{
Template: templateSet,
GeneratedAt: generatedAt,
}
app.Logger.Debugf("Generated %s at %v", name, generatedAt.Format(time.UnixDate))
}
// All was good, so return the cache, and no error
return cache, nil
}
// RenderTemplate renders requested template (t), pulling from cache.
func RenderTemplate(w http.ResponseWriter, filename string) {
if !app.UseCache {
c, err := GenerateNewTemplateCache()
if err != nil {
app.Logger.Fatal("Error generating template cache, bailing out!")
}
app.TemplateCache = c
}
// Get templates from cache
template, ok := app.TemplateCache.Cache[filename]
if !ok {
app.Logger.Errorf("Couldn't get %s from template cache, dunno what happened, but we're gonna generate a new one", filename)
c, err := GenerateNewTemplateCache()
if err != nil {
app.Logger.Fatal("Error generating template cache, bailing out!")
}
app.TemplateCache = c
template = app.TemplateCache.Cache[filename]
}
// Get template data from file, or generate simple
data, err := models.LoadTemplateData(filename)
if err == nil {
app.Logger.Debug(fmt.Sprintf("Loaded data for template %s.", filename), "data", data)
if _, ok := data.StringMap["GeneratedAt"]; !ok {
data.StringMap["GeneratedAt"] = app.TemplateCache.Cache[filename].GeneratedAt.Format(time.UnixDate)
}
} else {
app.Logger.Info(fmt.Sprintf("Loading template data for %s failed, using default template data.", filename), "err", err)
data = models.MakeBasicTemplateData(template.GeneratedAt)
}
l := data.LinkMap["Personal"]
app.Logger.Debugf("%[1]v is %[1]T", l)
// Execute templates in a new buffer
buf := new(bytes.Buffer)
err = template.Template.Execute(buf, data)
if err != nil {
app.Logger.Fatal(fmt.Sprintf("Error executing template %s! Goodbye!", filename), "err", err)
}
_, err = buf.WriteTo(w)
if err != nil {
app.Logger.Error(fmt.Sprintf("Error writing template %s!", filename), "err", err)
}
}