blog/cache.go

90 lines
1.7 KiB
Go

// cache.go
package main
import (
"crypto/md5"
"encoding/hex"
"os"
"path/filepath"
"sync"
)
var (
memoryCache = make(map[string][]byte)
cacheMutex sync.RWMutex
cacheDir = "cache"
// TestMode disables caching when set to true
TestMode bool
)
// InitCache ensures the cache directory exists
func InitCache() {
if _, err := os.Stat(cacheDir); os.IsNotExist(err) {
os.Mkdir(cacheDir, 0755)
}
}
// ClearCache wipes the cache directory (used for Test Mode)
func ClearCache() {
os.RemoveAll(cacheDir)
InitCache()
}
// getCacheFilename generates the hashed filename preserving the extension
func getCacheFilename(key string) string {
hash := md5.Sum([]byte(key))
ext := filepath.Ext(key)
// Default to .html if no extension (e.g. for processed markdown)
if ext == "" || ext == ".md" {
ext = ".html"
}
return filepath.Join(cacheDir, hex.EncodeToString(hash[:])+ext)
}
// CheckCache looks for content in memory, then on disk.
func CheckCache(key string) ([]byte, bool) {
if TestMode {
return nil, false
}
cacheMutex.RLock()
// 1. Check Memory
if data, found := memoryCache[key]; found {
cacheMutex.RUnlock()
return data, true
}
cacheMutex.RUnlock()
// 2. Check Disk
filePath := getCacheFilename(key)
data, err := os.ReadFile(filePath)
if err == nil {
// Populate memory for next time
cacheMutex.Lock()
memoryCache[key] = data
cacheMutex.Unlock()
return data, true
}
return nil, false
}
// StoreCache saves content to memory and disk.
func StoreCache(key string, data []byte) error {
if TestMode {
return nil
}
cacheMutex.Lock()
defer cacheMutex.Unlock()
// 1. Save to memory
memoryCache[key] = data
// 2. Save to disk
filePath := getCacheFilename(key)
return os.WriteFile(filePath, data, 0644)
}