Add avatar cache management and cleanup functionality
All checks were successful
CI / build (push) Successful in 54s

- Introduced constants for avatar cache limit and cleanup interval.
- Implemented a background cleanup process to manage the avatar cache size, removing the oldest files when the limit is exceeded.
- Updated the AvatarHandler to refresh the modification time of cached avatars for better cache management.
This commit is contained in:
2025-12-27 03:21:24 -06:00
parent f2f2f88047
commit 84489a572a
2 changed files with 70 additions and 0 deletions

View File

@@ -1,5 +1,7 @@
package api
import "time"
const (
CompressionLevel = 5
@@ -7,4 +9,8 @@ const (
PrivacyFile = "privacy.txt"
TermsFile = "terms.txt"
DisclaimerFile = "disclaimer.txt"
// Avatar Cache
AvatarCacheLimit = 100 * 1024 * 1024 // 100MB
AvatarCacheInterval = 1 * time.Hour
)

View File

@@ -83,9 +83,69 @@ func NewServer(token string, initialSoftware []models.Software, statsService *st
log.Printf("Warning: failed to create avatar cache directory: %v", err)
}
go s.startAvatarCleanup()
return s
}
func (s *Server) startAvatarCleanup() {
ticker := time.NewTicker(AvatarCacheInterval)
for range ticker.C {
s.cleanupAvatarCache()
}
}
func (s *Server) cleanupAvatarCache() {
files, err := os.ReadDir(s.avatarCache)
if err != nil {
return
}
var totalSize int64
type fileInfo struct {
path string
size int64
mod time.Time
}
var infos []fileInfo
for _, f := range files {
if f.IsDir() {
continue
}
path := filepath.Join(s.avatarCache, f.Name())
info, err := f.Info()
if err != nil {
continue
}
totalSize += info.Size()
infos = append(infos, fileInfo{
path: path,
size: info.Size(),
mod: info.ModTime(),
})
}
if totalSize <= AvatarCacheLimit {
return
}
// Sort by modification time (oldest first)
sort.Slice(infos, func(i, j int) bool {
return infos[i].mod.Before(infos[j].mod)
})
for _, info := range infos {
if totalSize <= AvatarCacheLimit {
break
}
if err := os.Remove(info.path); err == nil {
totalSize -= info.size
}
}
log.Printf("Avatar cache cleaned up. Current size: %v bytes", totalSize)
}
func (s *Server) RegisterURL(targetURL string) string {
h := sha256.New()
h.Write(s.salt)
@@ -304,6 +364,10 @@ func (s *Server) AvatarHandler(w http.ResponseWriter, r *http.Request) {
cachePath := filepath.Join(s.avatarCache, id)
if _, err := os.Stat(cachePath); err == nil {
// Update modification time for LRU cleanup
now := time.Now()
_ = os.Chtimes(cachePath, now, now)
// Serve from cache
w.Header().Set("Cache-Control", "public, max-age=86400")
http.ServeFile(w, r, cachePath)