feat: image variants cache panel
This commit is contained in:
1 parent
951fef18ba
commit
d768668014
53 files changed
+5809
-46
No files matched your search
@@ -0,0 +1,170 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/image"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
type VariantCacheEntry struct {
|
||||
Name string
|
||||
Enabled bool
|
||||
Files int
|
||||
Bytes int64
|
||||
}
|
||||
|
||||
type VariantCacheImage struct {
|
||||
ID uint32
|
||||
Filename string
|
||||
URL string
|
||||
Files int
|
||||
Bytes int64
|
||||
}
|
||||
|
||||
type VariantCacheStats struct {
|
||||
GeneratedFiles int
|
||||
DiskUsed int64
|
||||
VariantsDefined int
|
||||
VariantsEnabled int
|
||||
VariantsDisabled int
|
||||
RejectedRequests int
|
||||
RejectedWindowDays int
|
||||
Unused image.VariantFileTotals
|
||||
UnusedDays int
|
||||
ByVariant []VariantCacheEntry
|
||||
TopImages []VariantCacheImage
|
||||
}
|
||||
|
||||
type GetVariantCacheStatsUseCase struct {
|
||||
variants image.VariantRepository
|
||||
files image.VariantFileRepository
|
||||
cache image.VariantCacheRepository
|
||||
images image.Repository
|
||||
usage image.VariantUsageRepository
|
||||
tracker image.VariantUsageTracker
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewGetVariantCacheStatsUseCase(variants image.VariantRepository, files image.VariantFileRepository, cache image.VariantCacheRepository, images image.Repository, usage image.VariantUsageRepository, tracker image.VariantUsageTracker, now func() time.Time) *GetVariantCacheStatsUseCase {
|
||||
return &GetVariantCacheStatsUseCase{variants, files, cache, images, usage, tracker, now}
|
||||
}
|
||||
|
||||
func (u *GetVariantCacheStatsUseCase) Get() (VariantCacheStats, error) {
|
||||
_ = u.tracker.Flush()
|
||||
|
||||
variants, err := u.variants.List()
|
||||
if err != nil {
|
||||
return VariantCacheStats{}, err
|
||||
}
|
||||
totals, err := u.files.Totals()
|
||||
if err != nil {
|
||||
return VariantCacheStats{}, err
|
||||
}
|
||||
now := u.now()
|
||||
unused, err := u.cache.UnusedTotals(image.UnusedFilter{VariantNames: enabledNames(variants), Cutoff: image.UnusedCutoff(now)})
|
||||
if err != nil {
|
||||
return VariantCacheStats{}, err
|
||||
}
|
||||
rejected, err := u.usage.RejectedSince(image.RejectionWindowStart(now))
|
||||
if err != nil {
|
||||
return VariantCacheStats{}, err
|
||||
}
|
||||
top, err := u.topImages()
|
||||
if err != nil {
|
||||
return VariantCacheStats{}, err
|
||||
}
|
||||
|
||||
stats := VariantCacheStats{
|
||||
VariantsDefined: len(variants),
|
||||
RejectedRequests: rejected,
|
||||
RejectedWindowDays: image.RejectionWindowDays,
|
||||
Unused: unused,
|
||||
UnusedDays: image.UnusedVariantDays,
|
||||
ByVariant: cacheEntries(variants, totals),
|
||||
TopImages: top,
|
||||
}
|
||||
for _, entry := range stats.ByVariant {
|
||||
stats.GeneratedFiles += entry.Files
|
||||
stats.DiskUsed += entry.Bytes
|
||||
if entry.Enabled {
|
||||
stats.VariantsEnabled++
|
||||
}
|
||||
}
|
||||
stats.VariantsDisabled = stats.VariantsDefined - stats.VariantsEnabled
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func enabledNames(variants []image.Variant) []string {
|
||||
names := []string{}
|
||||
for _, variant := range variants {
|
||||
if variant.Enabled {
|
||||
names = append(names, variant.Name)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func cacheEntries(variants []image.Variant, totals map[string]image.VariantFileTotals) []VariantCacheEntry {
|
||||
entries := make([]VariantCacheEntry, 0, len(variants))
|
||||
for _, variant := range variants {
|
||||
own := totals[variant.Name]
|
||||
entries = append(entries, VariantCacheEntry{Name: variant.Name, Enabled: variant.Enabled, Files: own.Files, Bytes: own.Bytes})
|
||||
}
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
if entries[i].Bytes != entries[j].Bytes {
|
||||
return entries[i].Bytes > entries[j].Bytes
|
||||
}
|
||||
return entries[i].Name < entries[j].Name
|
||||
})
|
||||
return entries
|
||||
}
|
||||
|
||||
func (u *GetVariantCacheStatsUseCase) topImages() ([]VariantCacheImage, error) {
|
||||
limit := image.TopImagesLimit + 1
|
||||
for {
|
||||
sources, err := u.cache.TopSources(limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ranked, err := u.rank(sources)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sources) < limit || topIsSettled(ranked, sources) {
|
||||
return ranked[:min(len(ranked), image.TopImagesLimit)], nil
|
||||
}
|
||||
limit *= 2
|
||||
}
|
||||
}
|
||||
|
||||
func topIsSettled(ranked []VariantCacheImage, sources []image.SourceTotals) bool {
|
||||
return len(ranked) >= image.TopImagesLimit && ranked[image.TopImagesLimit-1].Bytes > sources[len(sources)-1].Bytes
|
||||
}
|
||||
|
||||
func (u *GetVariantCacheStatsUseCase) rank(sources []image.SourceTotals) ([]VariantCacheImage, error) {
|
||||
names := make([]string, 0, len(sources))
|
||||
for _, source := range sources {
|
||||
names = append(names, source.SourceName)
|
||||
}
|
||||
found, err := u.images.ListByStoredNames(names)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byName := make(map[string]image.Image, len(found))
|
||||
for _, img := range found {
|
||||
byName[image.StoredName(img.Path)] = img
|
||||
}
|
||||
ranked := make([]VariantCacheImage, 0, len(sources))
|
||||
for _, source := range sources {
|
||||
if img, known := byName[source.SourceName]; known {
|
||||
ranked = append(ranked, VariantCacheImage{ID: img.ID, Filename: img.Filename, URL: image.PublicPath(source.SourceName), Files: source.Files, Bytes: source.Bytes})
|
||||
}
|
||||
}
|
||||
sort.SliceStable(ranked, func(i, j int) bool {
|
||||
if ranked[i].Bytes != ranked[j].Bytes {
|
||||
return ranked[i].Bytes > ranked[j].Bytes
|
||||
}
|
||||
return ranked[i].ID < ranked[j].ID
|
||||
})
|
||||
return ranked, nil
|
||||
}
|
||||
Reference in new issue
Block a user