Add concurrency limits; add optional admin path prefix

This commit is contained in:
Seednode 2023-12-17 06:35:03 -06:00
parent fef51438c0
commit 14adbdf742
6 changed files with 40 additions and 18 deletions

View File

@ -16,6 +16,8 @@ import (
) )
var ( var (
ErrInvalidAdminPrefix = errors.New("admin path must not contain a '/'")
ErrInvalidConcurrency = errors.New("concurrency limit must be between 1 and 8192 inclusive")
ErrInvalidFileCountRange = errors.New("maximum file count limit must be greater than or equal to minimum file count limit") ErrInvalidFileCountRange = errors.New("maximum file count limit must be greater than or equal to minimum file count limit")
ErrInvalidFileCountValue = errors.New("file count limits must be non-negative integers no greater than 2147483647") ErrInvalidFileCountValue = errors.New("file count limits must be non-negative integers no greater than 2147483647")
ErrInvalidPort = errors.New("listen port must be an integer between 1 and 65535 inclusive") ErrInvalidPort = errors.New("listen port must be an integer between 1 and 65535 inclusive")

View File

@ -226,7 +226,13 @@ func hasSupportedFiles(path string, formats types.Types) (bool, error) {
} }
} }
func walkPath(path string, fileChannel chan<- string, stats *scanStatsChannels, formats types.Types) error { func walkPath(path string, fileChannel chan<- string, stats *scanStatsChannels, limit chan int, formats types.Types) error {
limit <- 1
defer func() {
<-limit
}()
errorChannel := make(chan error) errorChannel := make(chan error)
done := make(chan bool, 1) done := make(chan bool, 1)
@ -277,7 +283,7 @@ func walkPath(path string, fileChannel chan<- string, stats *scanStatsChannels,
switch { switch {
case node.IsDir() && Recursive: case node.IsDir() && Recursive:
err := walkPath(fullPath, fileChannel, stats, formats) err := walkPath(fullPath, fileChannel, stats, limit, formats)
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err
@ -398,6 +404,8 @@ func scanPaths(paths []string, sort string, index *fileIndex, formats types.Type
} }
}() }()
limit := make(chan int, Concurrency)
var wg sync.WaitGroup var wg sync.WaitGroup
for i := 0; i < len(paths); i++ { for i := 0; i < len(paths); i++ {
@ -407,7 +415,8 @@ func scanPaths(paths []string, sort string, index *fileIndex, formats types.Type
defer func() { defer func() {
wg.Done() wg.Done()
}() }()
err := walkPath(paths[i], fileChannel, statsChannels, formats)
err := walkPath(paths[i], fileChannel, statsChannels, limit, formats)
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err

View File

@ -305,19 +305,19 @@ func serveEnabledMediaTypes(formats types.Types, errorChannel chan<- error) http
func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats types.Types, errorChannel chan<- error) { func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats types.Types, errorChannel chan<- error) {
if Index { if Index {
registerHandler(mux, Prefix+"/index/html", serveIndexHtml(args, index, false)) registerHandler(mux, Prefix+AdminPrefix+"/index/html", serveIndexHtml(args, index, false))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/index/html/:page", serveIndexHtml(args, index, true)) registerHandler(mux, Prefix+AdminPrefix+"/index/html/:page", serveIndexHtml(args, index, true))
} }
registerHandler(mux, Prefix+"/index/json", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/index/json", serveIndexJson(args, index, errorChannel))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/index/json/:page", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/index/json/:page", serveIndexJson(args, index, errorChannel))
} }
} }
registerHandler(mux, Prefix+"/extensions/available", serveAvailableExtensions(errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/extensions/available", serveAvailableExtensions(errorChannel))
registerHandler(mux, Prefix+"/extensions/enabled", serveEnabledExtensions(formats, errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/extensions/enabled", serveEnabledExtensions(formats, errorChannel))
registerHandler(mux, Prefix+"/types/available", serveAvailableMediaTypes(errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/types/available", serveAvailableMediaTypes(errorChannel))
registerHandler(mux, Prefix+"/types/enabled", serveEnabledMediaTypes(formats, errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/types/enabled", serveEnabledMediaTypes(formats, errorChannel))
} }

View File

@ -25,9 +25,9 @@ func registerProfileHandler(mux *httprouter.Router, verb, path string, handler h
} }
func registerProfileHandlers(mux *httprouter.Router) { func registerProfileHandlers(mux *httprouter.Router) {
registerProfileHandler(mux, "GET", Prefix+"/debug/pprof/", pprof.Index) registerProfileHandler(mux, "GET", Prefix+AdminPrefix+"/debug/pprof/", pprof.Index)
registerProfileHandler(mux, "GET", Prefix+"/debug/pprof/cmdline", pprof.Cmdline) registerProfileHandler(mux, "GET", Prefix+AdminPrefix+"/debug/pprof/cmdline", pprof.Cmdline)
registerProfileHandler(mux, "GET", Prefix+"/debug/pprof/profile", pprof.Profile) registerProfileHandler(mux, "GET", Prefix+AdminPrefix+"/debug/pprof/profile", pprof.Profile)
registerProfileHandler(mux, "GET", Prefix+"/debug/pprof/symbol", pprof.Symbol) registerProfileHandler(mux, "GET", Prefix+AdminPrefix+"/debug/pprof/symbol", pprof.Symbol)
registerProfileHandler(mux, "GET", Prefix+"/debug/pprof/trace", pprof.Trace) registerProfileHandler(mux, "GET", Prefix+AdminPrefix+"/debug/pprof/trace", pprof.Trace)
} }

View File

@ -7,21 +7,24 @@ package cmd
import ( import (
"log" "log"
"math" "math"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const ( const (
ReleaseVersion string = "3.3.2" ReleaseVersion string = "3.4.0"
) )
var ( var (
AdminPrefix string
All bool All bool
Audio bool Audio bool
Bind string Bind string
CaseSensitive bool CaseSensitive bool
Code bool Code bool
CodeTheme string CodeTheme string
Concurrency int
DisableButtons bool DisableButtons bool
ExitOnError bool ExitOnError bool
Fallback bool Fallback bool
@ -61,6 +64,12 @@ var (
return ErrInvalidFileCountRange return ErrInvalidFileCountRange
case Port < 1 || Port > 65535: case Port < 1 || Port > 65535:
return ErrInvalidPort return ErrInvalidPort
case Concurrency < 1 || Concurrency > 8192:
return ErrInvalidConcurrency
case strings.Contains(AdminPrefix, "/"):
return ErrInvalidAdminPrefix
case AdminPrefix != "":
AdminPrefix = "/" + AdminPrefix
} }
return nil return nil
@ -84,12 +93,14 @@ func Execute() {
} }
func init() { func init() {
rootCmd.Flags().StringVar(&AdminPrefix, "admin-prefix", "", "string to prepend to administrative paths")
rootCmd.Flags().BoolVarP(&All, "all", "a", false, "enable all supported file types") rootCmd.Flags().BoolVarP(&All, "all", "a", false, "enable all supported file types")
rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files") rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files")
rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to") rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to")
rootCmd.Flags().BoolVar(&CaseSensitive, "case-sensitive", false, "use case-sensitive matching for filters") rootCmd.Flags().BoolVar(&CaseSensitive, "case-sensitive", false, "use case-sensitive matching for filters")
rootCmd.Flags().BoolVar(&Code, "code", false, "enable support for source code files") rootCmd.Flags().BoolVar(&Code, "code", false, "enable support for source code files")
rootCmd.Flags().StringVar(&CodeTheme, "code-theme", "solarized-dark256", "theme for source code syntax highlighting") rootCmd.Flags().StringVar(&CodeTheme, "code-theme", "solarized-dark256", "theme for source code syntax highlighting")
rootCmd.Flags().IntVar(&Concurrency, "concurrency", 1024, "maximum concurrency for scan threads")
rootCmd.Flags().BoolVar(&DisableButtons, "disable-buttons", false, "disable first/prev/next/last buttons") rootCmd.Flags().BoolVar(&DisableButtons, "disable-buttons", false, "disable first/prev/next/last buttons")
rootCmd.Flags().BoolVar(&ExitOnError, "exit-on-error", false, "shut down webserver on error, instead of just printing the error") rootCmd.Flags().BoolVar(&ExitOnError, "exit-on-error", false, "shut down webserver on error, instead of just printing the error")
rootCmd.Flags().BoolVar(&Fallback, "fallback", false, "serve files as application/octet-stream if no matching format is registered") rootCmd.Flags().BoolVar(&Fallback, "fallback", false, "serve files as application/octet-stream if no matching format is registered")

View File

@ -544,7 +544,7 @@ func ServePage(args []string) error {
registerHandler(mux, Prefix+"/version", serveVersion()) registerHandler(mux, Prefix+"/version", serveVersion())
if Index { if Index {
registerHandler(mux, Prefix+"/index/rebuild", serveIndexRebuild(args, index, formats, errorChannel)) registerHandler(mux, Prefix+AdminPrefix+"/index/rebuild", serveIndexRebuild(args, index, formats, errorChannel))
err = importIndex(paths, index, formats) err = importIndex(paths, index, formats)
if err != nil { if err != nil {