diff --git a/README.md b/README.md index d7d05eb..56664ec 100644 --- a/README.md +++ b/README.md @@ -92,14 +92,15 @@ Available Commands: version Print version Flags: - -c, --cache only scan directories once, at startup (or when filters are applied) - -d, --debug store list of files served and number of times they were served - -f, --filter enable filtering via query parameters - -h, --help help for roulette - -p, --port uint16 port to listen on (default 8080) - -r, --recursive recurse into subdirectories - -s, --sort enable sorting via query parameters - -v, --verbose log accessed files to stdout + -c, --cache generate directory cache at startup + -d, --debug expose stats endpoint + -f, --filter enable filtering + -h, --help help for roulette + -i, --index string path to persistent index file + -p, --port uint16 port to listen on (default 8080) + -r, --recursive recurse into subdirectories + -s, --sort enable sorting + -v, --verbose log accessed files to stdout Use "roulette [command] --help" for more information about a command. ``` diff --git a/cmd/root.go b/cmd/root.go index 4da3778..a80484f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,6 +15,7 @@ var ( cache bool debug bool filtering bool + indexFile string port uint16 recursive bool sorting bool @@ -47,6 +48,7 @@ func init() { rootCmd.Flags().BoolVarP(&cache, "cache", "c", false, "generate directory cache at startup") rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "expose stats endpoint") rootCmd.Flags().BoolVarP(&filtering, "filter", "f", false, "enable filtering") + rootCmd.Flags().StringVarP(&indexFile, "index", "i", "", "path to persistent index file") rootCmd.Flags().Uint16VarP(&port, "port", "p", 8080, "port to listen on") rootCmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "recurse into subdirectories") rootCmd.Flags().BoolVarP(&sorting, "sort", "s", false, "enable sorting") diff --git a/cmd/version.go b/cmd/version.go index dafe543..23cf362 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -var Version = "0.34.2" +var Version = "0.35.0" func init() { rootCmd.AddCommand(versionCmd) diff --git a/cmd/web.go b/cmd/web.go index c9948d9..d5204b6 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -5,7 +5,9 @@ Copyright © 2023 Seednode package cmd import ( + "encoding/gob" "encoding/json" + "errors" "fmt" "io" "log" @@ -25,6 +27,10 @@ import ( "github.com/yosssi/gohtml" ) +var ( + ErrIndexNotExist = errors.New(`specified index does not exist`) +) + const ( LogDate string = `2006-01-02T15:04:05.000-07:00` Prefix string = `/src` @@ -87,6 +93,10 @@ func (i *Index) generateCache(args []string) { i.mutex.Unlock() fileList(args, &Filters{}, "", i) + + if indexFile != "" { + i.Export(indexFile) + } } func (i *Index) IsEmpty() bool { @@ -97,6 +107,39 @@ func (i *Index) IsEmpty() bool { return length == 0 } +func (i *Index) Export(path string) error { + file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + defer file.Close() + + enc := gob.NewEncoder(file) + + enc.Encode(&i.list) + + return nil +} + +func (i *Index) Import(path string) error { + file, err := os.OpenFile(path, os.O_RDONLY, 0600) + if os.IsNotExist(err) { + return ErrIndexNotExist + } else if err != nil { + return err + } + defer file.Close() + + dec := gob.NewDecoder(file) + + err = dec.Decode(&i.list) + if err != nil { + return err + } + + return nil +} + type ServeStats struct { mutex sync.RWMutex list []string @@ -577,7 +620,9 @@ func ServePage(args []string) error { units: regexp.MustCompile(`^[0-9]+(ns|us|µs|ms|s|m|h)$`), } - rand.Seed(time.Now().UnixNano()) + //NewRand(NewSource(time.Now().UnixNano())) + + rand.New(rand.NewSource(time.Now().UnixNano())) index := &Index{ mutex: sync.RWMutex{}, @@ -585,7 +630,22 @@ func ServePage(args []string) error { } if cache { - index.generateCache(args) + skipIndex := false + + if indexFile != "" { + err = index.Import(indexFile) + switch err { + case ErrIndexNotExist: + case nil: + skipIndex = true + default: + return err + } + } + + if !skipIndex { + index.generateCache(args) + } http.Handle("/_/clear_cache", serveCacheClearHandler(args, index)) }