Add avatar cache management and cleanup functionality
All checks were successful
CI / build (push) Successful in 54s
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:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user