// SPDX-FileCopyrightText: 2021 Luke Granger-Brown // // SPDX-License-Identifier: Apache-2.0 package fuphttp import ( "context" "fmt" "io/fs" "net/http" "github.com/google/safehtml/template" "github.com/google/safehtml/template/uncheckedconversions" "github.com/gorilla/mux" ) type Config struct { Templates fs.FS Static fs.FS StaticRoot string } type Application struct { indexTmpl *template.Template notFoundTmpl *template.Template } func (a *Application) Handler() http.Handler { r := mux.NewRouter() r.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(http.StatusNotFound) a.notFoundTmpl.Execute(rw, nil) }) return r } func parseTemplate(t *template.Template, fsys fs.FS, name string) (*template.Template, error) { bs, err := fs.ReadFile(fsys, name) if err != nil { return nil, fmt.Errorf("reading template %q: %w", name, err) } return t.ParseFromTrustedTemplate( uncheckedconversions.TrustedTemplateFromStringKnownToSatisfyTypeContract(string(bs)), ) } func loadTemplate(fsys fs.FS, name string) (*template.Template, error) { t := template.New(name) var err error if t, err = parseTemplate(t, fsys, "base.html"); err != nil { return nil, fmt.Errorf("loading base template: %w", err) } if t, err = parseTemplate(t, fsys, fmt.Sprintf("%s.html", name)); err != nil { return nil, fmt.Errorf("loading leaf template: %w", err) } return t, nil } func New(ctx context.Context, cfg *Config) (*Application, error) { a := new(Application) tmpls := []struct { t **template.Template name string }{ {&a.indexTmpl, "index"}, {&a.notFoundTmpl, "404"}, } for _, tmpl := range tmpls { t, err := loadTemplate(cfg.Templates, tmpl.name) if err != nil { return nil, fmt.Errorf("loading template %q: %w", tmpl.name, err) } *tmpl.t = t } return a, nil }