Fixed double-scanning with cache enabled
This commit is contained in:
parent
6c888ba20a
commit
fcdb81a9b7
149
cmd/files.go
149
cmd/files.go
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
62
cmd/web.go
62
cmd/web.go
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue