v0.128.0: chunked browser .fab upload on /import (tunnel-proof)
Cloudflare edge caps request bodies (~100 MB, probed live: 120 MiB -> edge 413,
80 MiB -> origin), so the client slices the file into 64 MiB strictly-sequential
chunks; the server streams each to a .part file in the default drive's exports
dir and finalize renames atomically. Scan/validate/import pipeline untouched.
upload/{init,chunk,finalize,abort} inside ServeExportAPI (inherits auth+CSRF);
single-flight; offset==received or 409+echo; free-space gate; collision ->
lowest-free "name (N).fab"; startup GC of *.part-*; 15-min idle abort.
appexport.DiskFree exported (seam web.uploadDiskFree). Scenarios A-F tested,
red-proofs run (traversal / out-of-order / overwrite).
This commit is contained in:
@@ -72,7 +72,7 @@ func (e *Exporter) EstimateExport(stackName, destDrive string) (*ExportEstimate,
|
||||
// Destination free space
|
||||
exportDir := ExportDir(destDrive)
|
||||
os.MkdirAll(exportDir, 0755)
|
||||
est.DestFreeBytes = diskFree(exportDir)
|
||||
est.DestFreeBytes = DiskFree(exportDir)
|
||||
est.DestFreeHuman = humanizeBytes(est.DestFreeBytes)
|
||||
|
||||
// Need ~10% overhead for tar.gz metadata + compression margin
|
||||
@@ -135,8 +135,9 @@ func dockerVolumeSize(volumeName string) int64 {
|
||||
return duBytes(mountpoint)
|
||||
}
|
||||
|
||||
// diskFree returns available bytes on the filesystem containing path.
|
||||
func diskFree(path string) int64 {
|
||||
// DiskFree returns available bytes on the filesystem containing path (0 on any error).
|
||||
// Exported since v0.128.0 — the browser-upload space gate reuses it via a web-package seam.
|
||||
func DiskFree(path string) int64 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
out, err := exec.CommandContext(ctx, "df", "--output=avail", "-B1", path).Output()
|
||||
|
||||
Reference in New Issue
Block a user