package tplmap import ( "fmt" "log" "os" "prose/common" "prose/watcher" "strconv" "sync" "time" "github.com/aymerick/raymond" ) type tplMap struct { mu sync.RWMutex templates map[string]*raymond.Template } func New() (watcher.AutoMap[string, *raymond.Template], error) { folder, err := os.ReadDir("templates/") if err != nil { return nil, fmt.Errorf("could not load templates directory: %w", err) } tm := &tplMap{ templates: make(map[string]*raymond.Template), } for _, s := range folder { err := tm.fetchLocked(s.Name()) if err != nil { return nil, fmt.Errorf("could not load template %q: %w", s.Name(), err) } log.Printf("loaded template %q", s.Name()) } go watcher.Watch("templates/", tm) return tm, nil } func (tm *tplMap) Get(filename string) (*raymond.Template, bool) { tm.mu.RLock() defer tm.mu.RUnlock() got, ok := tm.templates[filename] return got, ok } func (tm *tplMap) Delete(filename string) error { tm.mu.Lock() defer tm.mu.Unlock() delete(tm.templates, filename) return nil } func (tm *tplMap) Fetch(filename string) error { tm.mu.Lock() defer tm.mu.Unlock() return tm.fetchLocked(filename) } func (tm *tplMap) fetchLocked(filename string) error { tpl, err := raymond.ParseFile("templates/" + filename) if err != nil { return fmt.Errorf("could not parse template %q: %w", filename, err) } tpl.RegisterHelper("datetime", func(timeStr string) string { timestamp, err := strconv.ParseInt(timeStr, 10, 64) if err != nil { log.Printf("Could not parse timestamp '%v', falling back to current time", timeStr) timestamp = time.Now().Unix() } return time.Unix(timestamp, 0).Format("Jan 2 2006, 3:04 PM") }) tpl.RegisterHelper("rssDatetime", func(timeStr string) string { timestamp, err := strconv.ParseInt(timeStr, 10, 64) if err != nil { log.Printf("Could not parse timestamp '%v', falling back to current time", timeStr) timestamp = time.Now().Unix() } return common.RSSDatetime(timestamp) }) tpl.RegisterHelper("getFullUrl", func(slug string) string { return common.BlogURL + "/" + slug }) tm.templates[filename] = tpl return nil }