package template import ( "fmt" "os" "path/filepath" "sync" ) var Cache *TemplateCache type TemplateCache struct { mu sync.RWMutex templates map[string]*Template basePath string } func NewCache(basePath string) *TemplateCache { if basePath == "" { exe, err := os.Executable() if err != nil { basePath = "." } else { basePath = filepath.Dir(exe) } } return &TemplateCache{ templates: make(map[string]*Template), basePath: basePath, } } func InitializeCache(basePath string) { Cache = NewCache(basePath) } func (c *TemplateCache) Load(name string) (*Template, error) { c.mu.RLock() tmpl, exists := c.templates[name] c.mu.RUnlock() if exists { if err := c.checkAndReload(tmpl); err != nil { return nil, err } return tmpl, nil } return c.loadFromFile(name) } func (c *TemplateCache) loadFromFile(name string) (*Template, error) { filePath := filepath.Join(c.basePath, "templates", name) info, err := os.Stat(filePath) if err != nil { return nil, fmt.Errorf("template file not found: %s", name) } content, err := os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("failed to read template: %w", err) } tmpl := &Template{ name: name, content: string(content), modTime: info.ModTime(), filePath: filePath, cache: c, } c.mu.Lock() c.templates[name] = tmpl c.mu.Unlock() return tmpl, nil } func (c *TemplateCache) checkAndReload(tmpl *Template) error { info, err := os.Stat(tmpl.filePath) if err != nil { return err } if info.ModTime().After(tmpl.modTime) { content, err := os.ReadFile(tmpl.filePath) if err != nil { return err } c.mu.Lock() tmpl.content = string(content) tmpl.modTime = info.ModTime() c.mu.Unlock() } return nil }