From 5cf45d21559eb4f8c69f57e9d50bcd4d00b9d430 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 20 Nov 2017 11:57:45 -0600 Subject: refactor template code (#7860) --- utils/html.go | 114 +++++++++++++++++++++++++++------------------------------- 1 file changed, 52 insertions(+), 62 deletions(-) (limited to 'utils/html.go') diff --git a/utils/html.go b/utils/html.go index fdba3e08d..02db8c97a 100644 --- a/utils/html.go +++ b/utils/html.go @@ -6,55 +6,60 @@ package utils import ( "bytes" "html/template" - "net/http" + "io" "reflect" + "sync/atomic" l4g "github.com/alecthomas/log4go" "github.com/fsnotify/fsnotify" "github.com/nicksnyder/go-i18n/i18n" ) -// Global storage for templates -var htmlTemplates *template.Template - -type HTMLTemplate struct { - TemplateName string - Props map[string]interface{} - Html map[string]template.HTML - Locale string +type HTMLTemplateWatcher struct { + templates atomic.Value + stop chan struct{} + stopped chan struct{} } -func InitHTML() { - InitHTMLWithDir("templates") -} +func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) { + templatesDir, _ := FindDir(directory) + l4g.Debug(T("api.api.init.parsing_templates.debug"), templatesDir) -func InitHTMLWithDir(dir string) { + ret := &HTMLTemplateWatcher{ + stop: make(chan struct{}), + stopped: make(chan struct{}), + } - if htmlTemplates != nil { - return + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, err } - templatesDir, _ := FindDir(dir) - l4g.Debug(T("api.api.init.parsing_templates.debug"), templatesDir) - var err error - if htmlTemplates, err = template.ParseGlob(templatesDir + "*.html"); err != nil { - l4g.Error(T("api.api.init.parsing_templates.error"), err) + if err = watcher.Add(templatesDir); err != nil { + return nil, err } - // Watch the templates folder for changes. - watcher, err := fsnotify.NewWatcher() - if err != nil { - l4g.Error(T("web.create_dir.error"), err) + if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil { + return nil, err + } else { + ret.templates.Store(htmlTemplates) } go func() { + defer close(ret.stopped) + defer watcher.Close() + for { select { + case <-ret.stop: + return case event := <-watcher.Events: if event.Op&fsnotify.Write == fsnotify.Write { l4g.Info(T("web.reparse_templates.info"), event.Name) - if htmlTemplates, err = template.ParseGlob(templatesDir + "*.html"); err != nil { + if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil { l4g.Error(T("web.parsing_templates.error"), err) + } else { + ret.templates.Store(htmlTemplates) } } case err := <-watcher.Errors: @@ -63,57 +68,42 @@ func InitHTMLWithDir(dir string) { } }() - err = watcher.Add(templatesDir) - if err != nil { - l4g.Error(T("web.watcher_fail.error"), err) - } + return ret, nil } -func NewHTMLTemplate(templateName string, locale string) *HTMLTemplate { - return &HTMLTemplate{ - TemplateName: templateName, - Props: make(map[string]interface{}), - Html: make(map[string]template.HTML), - Locale: locale, - } +func (w *HTMLTemplateWatcher) Templates() *template.Template { + return w.templates.Load().(*template.Template) } -func (t *HTMLTemplate) addDefaultProps() { - var localT i18n.TranslateFunc - if len(t.Locale) > 0 { - localT = GetUserTranslations(t.Locale) - } else { - localT = T - } +func (w *HTMLTemplateWatcher) Close() { + close(w.stop) + <-w.stopped +} - t.Props["Footer"] = localT("api.templates.email_footer") +type HTMLTemplate struct { + Templates *template.Template + TemplateName string + Props map[string]interface{} + Html map[string]template.HTML +} - if *Cfg.EmailSettings.FeedbackOrganization != "" { - t.Props["Organization"] = localT("api.templates.email_organization") + *Cfg.EmailSettings.FeedbackOrganization - } else { - t.Props["Organization"] = "" +func NewHTMLTemplate(templates *template.Template, templateName string) *HTMLTemplate { + return &HTMLTemplate{ + Templates: templates, + TemplateName: templateName, + Props: make(map[string]interface{}), + Html: make(map[string]template.HTML), } - - t.Html["EmailInfo"] = TranslateAsHtml(localT, "api.templates.email_info", - map[string]interface{}{"SupportEmail": *Cfg.SupportSettings.SupportEmail, "SiteName": Cfg.TeamSettings.SiteName}) } func (t *HTMLTemplate) Render() string { - t.addDefaultProps() - var text bytes.Buffer - - if err := htmlTemplates.ExecuteTemplate(&text, t.TemplateName, t); err != nil { - l4g.Error(T("api.api.render.error"), t.TemplateName, err) - } - + t.RenderToWriter(&text) return text.String() } -func (t *HTMLTemplate) RenderToWriter(w http.ResponseWriter) error { - t.addDefaultProps() - - if err := htmlTemplates.ExecuteTemplate(w, t.TemplateName, t); err != nil { +func (t *HTMLTemplate) RenderToWriter(w io.Writer) error { + if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil { l4g.Error(T("api.api.render.error"), t.TemplateName, err) return err } -- cgit v1.2.3-1-g7c22