feat(downloads): pre-flight free-disk guard before each download (hueco medio)
CheckDiskSpace (internal/engine/diskspace.go) refuses a download before writing when its expected size wouldn't leave a configurable reserve free, so a download never fills the filesystem to 0 mid-write (which corrupts the partial file). Wired into all three downloaders ahead of any write — torrent (DataDir), debrid (outputDir, resume-aware), usenet (outputDir, fresh only). Reserve from downloads.min_free_disk_mb (default 2048 MiB) via SetMinFreeBytes. The manager treats an InsufficientDiskError as terminal — no source fallback, since another source would fill the same disk — and surfaces the clear message. Best-effort: unknown size or a stat failure doesn't block (ENOSPC stays the backstop). Also hardens formatBytes against an exabyte-scale out-of-bounds panic.
This commit is contained in:
parent
2be92516c6
commit
1cad73b9a7
9 changed files with 196 additions and 4 deletions
|
|
@ -27,6 +27,8 @@ var httpClient = &http.Client{
|
|||
type DebridDownloader struct {
|
||||
activeMu sync.Mutex
|
||||
active map[string]context.CancelFunc
|
||||
|
||||
minFreeBytes int64 // disk reserve for the pre-flight space check (0 = reserve disabled)
|
||||
}
|
||||
|
||||
// NewDebridDownloader creates a debrid downloader.
|
||||
|
|
@ -36,6 +38,11 @@ func NewDebridDownloader() *DebridDownloader {
|
|||
}
|
||||
}
|
||||
|
||||
// SetMinFreeBytes sets the free-space reserve enforced before a download starts.
|
||||
// Call once at construction; 0 disables the reserve (the size-vs-free check still
|
||||
// runs). See CheckDiskSpace.
|
||||
func (d *DebridDownloader) SetMinFreeBytes(n int64) { d.minFreeBytes = n }
|
||||
|
||||
func (d *DebridDownloader) Method() DownloadMethod { return MethodDebrid }
|
||||
|
||||
// Available returns true if the task has a direct HTTPS URL from the server.
|
||||
|
|
@ -167,6 +174,12 @@ func (d *DebridDownloader) Download(ctx context.Context, task *Task, outputDir s
|
|||
log.Printf("[%s] starting debrid download: %s", agent.ShortID(task.ID), fileName)
|
||||
}
|
||||
|
||||
// Pre-flight disk-space guard on the bytes still to write (resume subtracts
|
||||
// what's already on disk). Best-effort; ENOSPC stays the backstop.
|
||||
if err := CheckDiskSpace(outputDir, totalBytes-startOffset, d.minFreeBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create directory: %w", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue