feat: track active uploads with ttlcache

pull/5270/head
Ramires Viana 2025-07-10 16:33:05 -03:00
parent 76cf7bd5c2
commit 99edda74cf
3 changed files with 31 additions and 11 deletions

2
go.mod
View File

@ -46,6 +46,7 @@ require (
github.com/golang/geo v0.0.0-20250606134707-e8fe6a72b492 // indirect github.com/golang/geo v0.0.0-20250606134707-e8fe6a72b492 // indirect
github.com/golang/snappy v1.0.0 // indirect github.com/golang/snappy v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jellydator/ttlcache/v3 v3.4.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect github.com/nwaples/rardecode v1.1.3 // indirect
@ -61,6 +62,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.41.0 // indirect golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

2
go.sum
View File

@ -83,6 +83,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=

View File

@ -1,6 +1,7 @@
package http package http
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -8,32 +9,47 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"time"
"github.com/jellydator/ttlcache/v3"
"github.com/spf13/afero" "github.com/spf13/afero"
"sync"
"github.com/filebrowser/filebrowser/v2/files" "github.com/filebrowser/filebrowser/v2/files"
) )
// Tracks active uploads along with their respective upload lengths const maxUploadWait = 3 * time.Minute
var activeUploads sync.Map
func registerUpload(filePath string, fileSize int64) { // Tracks active uploads along with their respective upload lengths
activeUploads.Store(filePath, fileSize) var activeUploads = initActiveUploads()
func initActiveUploads() *ttlcache.Cache[string, int64] {
cache := ttlcache.New[string, int64]()
cache.OnEviction(func(_ context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, int64]) {
if reason == ttlcache.EvictionReasonExpired {
fmt.Printf("deleting incomplete upload file: \"%s\"", item.Key())
os.Remove(item.Key())
}
})
go cache.Start()
return cache
} }
func unregisterUpload(filePath string) { func registerUpload(filePath string, fileSize int64) {
activeUploads.Set(filePath, fileSize, maxUploadWait)
}
func completeUpload(filePath string) {
activeUploads.Delete(filePath) activeUploads.Delete(filePath)
} }
func getActiveUploadLength(filePath string) (int64, error) { func getActiveUploadLength(filePath string) (int64, error) {
value, exists := activeUploads.Load(filePath) item := activeUploads.Get(filePath)
if !exists { if item == nil {
return 0, fmt.Errorf("no active upload found for the given path") return 0, fmt.Errorf("no active upload found for the given path")
} }
return value.(int64), nil return item.Value(), nil
} }
func tusPostHandler() handleFunc { func tusPostHandler() handleFunc {
@ -212,7 +228,7 @@ func tusPatchHandler() handleFunc {
w.Header().Set("Upload-Offset", strconv.FormatInt(newOffset, 10)) w.Header().Set("Upload-Offset", strconv.FormatInt(newOffset, 10))
if newOffset >= uploadLength { if newOffset >= uploadLength {
unregisterUpload(file.RealPath()) completeUpload(file.RealPath())
_ = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user) _ = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user)
} }