From 516a861974d054ca96f1a89dedee171d71ffe826 Mon Sep 17 00:00:00 2001 From: MickaelK Date: Thu, 4 Sep 2025 15:24:04 +1000 Subject: [PATCH] feature (buffer_size): expose buffer size configuration to admin --- server/common/config.go | 1 + server/ctrl/files.go | 20 ++++++++++++++++---- server/plugin/plg_backend_nop/index.go | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/server/common/config.go b/server/common/config.go index 855a037f..9dfb7361 100644 --- a/server/common/config.go +++ b/server/common/config.go @@ -80,6 +80,7 @@ func NewConfiguration() Configuration { FormElement{Name: "upload_button", Type: "boolean", Default: false, Description: "Display the upload button on any device"}, FormElement{Name: "upload_pool_size", Type: "number", Default: 15, Description: "Maximum number of files upload in parallel. Default: 15"}, FormElement{Name: "upload_chunk_size", Type: "number", Default: 0, Description: "Size of Chunks for Uploads in MB."}, + FormElement{Name: "buffer_size", Type: "select", Default: "medium", Opts: []string{"small", "medium", "large"}, Description: "I/O buffer size for transfers. Larger buffers boost throughput on 20 GbE+ networks but use more memory."}, FormElement{Name: "filepage_default_view", Type: "select", Default: "grid", Opts: []string{"list", "grid"}, Description: "Default layout for files and folder on the file page"}, FormElement{Name: "filepage_default_sort", Type: "select", Default: "type", Opts: []string{"type", "date", "name"}, Description: "Default order for files and folder on the file page"}, FormElement{Name: "cookie_timeout", Type: "number", Default: 60 * 24 * 7, Description: "Authentication Cookie expiration in minutes. Default: 60 * 24 * 7 = 1 week"}, diff --git a/server/ctrl/files.go b/server/ctrl/files.go index b588216c..892f1b32 100644 --- a/server/ctrl/files.go +++ b/server/ctrl/files.go @@ -247,7 +247,8 @@ func FileCat(ctx *App, res http.ResponseWriter, req *http.Request) { } // plugin hooks - if thumb := query.Get("thumbnail"); thumb == "true" { + thumb := query.Get("thumbnail") + if thumb == "true" { for plgMType, plgHandler := range Hooks.Get.Thumbnailer() { if plgMType != mType { continue @@ -358,19 +359,30 @@ func FileCat(ctx *App, res http.ResponseWriter, req *http.Request) { } header.Set("Accept-Ranges", "bytes") - // Send data to the client if req.Method != "HEAD" { + size := 32 + if thumb != "true" { + switch Config.Get("general.buffer_size").String() { + case "small": + size = 32 + case "medium": + size = 128 + case "large": + size = 2 * 1024 + } + } + buf := make([]byte, size*1024) if f, ok := file.(io.ReadSeeker); ok && len(ranges) > 0 { if _, err = f.Seek(ranges[0][0], io.SeekStart); err == nil { header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ranges[0][0], ranges[0][1], contentLength)) header.Set("Content-Length", fmt.Sprintf("%d", ranges[0][1]-ranges[0][0]+1)) res.WriteHeader(http.StatusPartialContent) - io.CopyN(res, f, ranges[0][1]-ranges[0][0]+1) + io.CopyBuffer(res, io.LimitReader(f, ranges[0][1]-ranges[0][0]+1), buf) } else { res.WriteHeader(http.StatusRequestedRangeNotSatisfiable) } } else { - io.Copy(res, file) + io.CopyBuffer(res, file, buf) } } file.Close() diff --git a/server/plugin/plg_backend_nop/index.go b/server/plugin/plg_backend_nop/index.go index 19dc9b1e..74f3cb75 100644 --- a/server/plugin/plg_backend_nop/index.go +++ b/server/plugin/plg_backend_nop/index.go @@ -105,7 +105,7 @@ func (this BlackHole) Mv(from, to string) error { } func (this BlackHole) Save(path string, content io.Reader) error { - b := make([]byte, 32<<20) // 32MB + b := make([]byte, 32*1024*1024) // 32MB for { _, err := content.Read(b) if err == io.EOF {