Fixed double-scanning with cache enabled

This commit is contained in:
Seednode 2023-01-20 22:42:44 -06:00
parent 6c888ba20a
commit fcdb81a9b7
3 changed files with 109 additions and 104 deletions

View File

@ -35,6 +35,24 @@ var (
extensions = [6]string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"} extensions = [6]string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"}
) )
type Index struct {
Mutex sync.RWMutex
List []string
}
func (i *Index) GenerateCache(args []string) error {
filters := &Filters{}
i.Mutex.Lock()
i.List = []string{}
i.Mutex.Unlock()
fmt.Printf("%v | Preparing image cache...\n", time.Now().Format(LogDate))
_, err := pickFile(args, filters, "", i)
return err
}
type Dimensions struct { type Dimensions struct {
Width int Width int
Height int Height int
@ -51,63 +69,6 @@ type ScanStats struct {
DirectoriesMatched uint64 DirectoriesMatched uint64
} }
type TimesServed struct {
File string
Size string
Served uint64
Timestamps []string
}
type ServeStats struct {
Served uint64
List []string
Count map[string]uint64
FileSize map[string]string
Timestamps map[string][]string
}
func (s *ServeStats) GetFilesTotal() uint64 {
return atomic.LoadUint64(&s.Served)
}
func (s *ServeStats) IncrementCounter(image string, timestamp time.Time, filesize string) {
s.Served += 1
s.Count[image] += 1
s.Timestamps[image] = append(s.Timestamps[image], timestamp.Format(LogDate))
_, exists := s.FileSize[image]
if !exists {
s.FileSize[image] = filesize
}
if !contains(s.List, image) {
s.List = append(s.List, image)
}
}
func (s *ServeStats) ListImages() ([]byte, error) {
a := []TimesServed{}
sortedList := s.List
sort.SliceStable(sortedList, func(p, q int) bool {
return sortedList[p] < sortedList[q]
})
for _, image := range s.List {
a = append(a, TimesServed{image, s.FileSize[image], s.Count[image], s.Timestamps[image]})
}
r, err := json.MarshalIndent(a, "", " ")
if err != nil {
return []byte{}, err
}
return r, nil
}
func (s *ScanStats) GetFilesTotal() uint64 { func (s *ScanStats) GetFilesTotal() uint64 {
return atomic.LoadUint64(&s.FilesMatched) + atomic.LoadUint64(&s.FilesSkipped) return atomic.LoadUint64(&s.FilesMatched) + atomic.LoadUint64(&s.FilesSkipped)
} }
@ -136,6 +97,65 @@ func (s *ScanStats) GetDirectoriesMatched() uint64 {
return atomic.LoadUint64(&s.DirectoriesMatched) return atomic.LoadUint64(&s.DirectoriesMatched)
} }
type ServeStats struct {
Mutex sync.RWMutex
List []string
Count map[string]uint64
Size map[string]string
Times map[string][]string
}
type TimesServed struct {
File string
Served uint64
Size string
Times []string
}
func (s *ServeStats) IncrementCounter(image string, timestamp time.Time, filesize string) {
s.Mutex.Lock()
s.Count[image]++
s.Times[image] = append(s.Times[image], timestamp.Format(LogDate))
_, exists := s.Size[image]
if !exists {
s.Size[image] = filesize
}
if !contains(s.List, image) {
s.List = append(s.List, image)
}
s.Mutex.Unlock()
}
func (s *ServeStats) ListImages() ([]byte, error) {
s.Mutex.RLock()
sortedList := s.List
sort.SliceStable(sortedList, func(p, q int) bool {
return sortedList[p] < sortedList[q]
})
a := []TimesServed{}
for _, image := range s.List {
a = append(a, TimesServed{image, s.Count[image], s.Size[image], s.Times[image]})
}
s.Mutex.RUnlock()
r, err := json.MarshalIndent(a, "", " ")
if err != nil {
return []byte{}, err
}
return r, nil
}
type Path struct { type Path struct {
Base string Base string
Number int Number int
@ -279,8 +299,8 @@ func appendPaths(path string, files *Files, filters *Filters, stats *ScanStats)
return nil return nil
} }
func getNewFile(paths []string, filters *Filters, sortOrder string, regexes *Regexes, fileCache *[]string) (string, error) { func getNewFile(paths []string, filters *Filters, sortOrder string, regexes *Regexes, index *Index) (string, error) {
filePath, err := pickFile(paths, filters, sortOrder, fileCache) filePath, err := pickFile(paths, filters, sortOrder, index)
if err != nil { if err != nil {
return "", nil return "", nil
} }
@ -547,11 +567,11 @@ func prepareDirectories(files *Files, sort string) []string {
return directories return directories
} }
func pickFile(args []string, filters *Filters, sort string, fileCache *[]string) (string, error) { func pickFile(args []string, filters *Filters, sort string, index *Index) (string, error) {
var fileList []string var fileList []string
if Cache && filters.IsEmpty() && len(*fileCache) != 0 { if Cache && filters.IsEmpty() && len(index.List) != 0 {
fileList = *fileCache fileList = index.List
} else { } else {
files := &Files{ files := &Files{
List: make(map[string][]string), List: make(map[string][]string),
@ -585,8 +605,11 @@ func pickFile(args []string, filters *Filters, sort string, fileCache *[]string)
fileList = prepareDirectories(files, sort) fileList = prepareDirectories(files, sort)
if Cache { if Cache {
*fileCache = append(*fileCache, fileList...) index.Mutex.Lock()
index.List = append(index.List, fileList...)
index.Mutex.Unlock()
} }
} }
fileCount := len(fileList) fileCount := len(fileList)

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var Version = "0.31.3" var Version = "0.32.0"
func init() { func init() {
rootCmd.AddCommand(versionCmd) rootCmd.AddCommand(versionCmd)

View File

@ -17,6 +17,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/yosssi/gohtml" "github.com/yosssi/gohtml"
@ -333,20 +334,9 @@ func serveStaticFile(w http.ResponseWriter, r *http.Request, paths []string, sta
return nil return nil
} }
func generateCache(args []string, fileCache *[]string) error { func serveCacheClearHandler(args []string, index *Index) http.HandlerFunc {
filters := &Filters{}
fileCache = &[]string{}
fmt.Printf("%v | Preparing image cache...\n", time.Now().Format(LogDate))
_, err := pickFile(args, filters, "", fileCache)
return err
}
func serveCacheClearHandler(args []string, fileCache *[]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
err := generateCache(args, fileCache) err := index.GenerateCache(args)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -357,17 +347,6 @@ func serveCacheClearHandler(args []string, fileCache *[]string) http.HandlerFunc
} }
} }
func serveStats(args []string, fileCache *[]string) error {
filters := &Filters{}
fileCache = &[]string{}
fmt.Printf("%v | Preparing image cache...\n", time.Now().Format(LogDate))
_, err := pickFile(args, filters, "", fileCache)
return err
}
func serveStatsHandler(args []string, stats *ServeStats) http.HandlerFunc { func serveStatsHandler(args []string, stats *ServeStats) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@ -391,7 +370,7 @@ func serveStaticFileHandler(paths []string, stats *ServeStats) http.HandlerFunc
} }
} }
func serveHtmlHandler(paths []string, regexes *Regexes, fileCache *[]string) http.HandlerFunc { func serveHtmlHandler(paths []string, regexes *Regexes, index *Index) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
refererUri, err := stripQueryParams(refererToUri(r.Referer())) refererUri, err := stripQueryParams(refererToUri(r.Referer()))
if err != nil { if err != nil {
@ -419,7 +398,7 @@ func serveHtmlHandler(paths []string, regexes *Regexes, fileCache *[]string) htt
} }
if filePath == "" { if filePath == "" {
filePath, err = getNewFile(paths, filters, sortOrder, regexes, fileCache) filePath, err = getNewFile(paths, filters, sortOrder, regexes, index)
switch { switch {
case err != nil && err == ErrNoImagesFound: case err != nil && err == ErrNoImagesFound:
notFound(w, r, filePath) notFound(w, r, filePath)
@ -496,29 +475,32 @@ func ServePage(args []string) error {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
fileCache := &[]string{} index := &Index{
Mutex: sync.RWMutex{},
stats := &ServeStats{ List: []string{},
Served: 0,
List: []string{},
Count: make(map[string]uint64),
FileSize: make(map[string]string),
Timestamps: make(map[string][]string),
} }
http.Handle("/", serveHtmlHandler(paths, regexes, fileCache))
http.Handle(Prefix+"/", http.StripPrefix(Prefix, serveStaticFileHandler(paths, stats)))
http.HandleFunc("/favicon.ico", doNothing)
if Cache { if Cache {
err := generateCache(args, fileCache) err := index.GenerateCache(args)
if err != nil { if err != nil {
return err return err
} }
http.Handle("/clear_cache", serveCacheClearHandler(args, fileCache)) http.Handle("/clear_cache", serveCacheClearHandler(args, index))
} }
stats := &ServeStats{
Mutex: sync.RWMutex{},
List: []string{},
Count: make(map[string]uint64),
Size: make(map[string]string),
Times: make(map[string][]string),
}
http.Handle("/", serveHtmlHandler(paths, regexes, index))
http.Handle(Prefix+"/", http.StripPrefix(Prefix, serveStaticFileHandler(paths, stats)))
http.HandleFunc("/favicon.ico", doNothing)
if Debug { if Debug {
http.Handle("/stats", serveStatsHandler(args, stats)) http.Handle("/stats", serveStatsHandler(args, stats))
} }