fix: upload: temp file is lost if user refuses to resume and then upload is interrupted
Massimo Melina committed
Sep 27, 2024 at 14:08 UTC
05252d265d19f95ef9ab09e77c85aaadb4a63c6f
1 file changed
+9
-6
src/upload.ts
+9
-6
@@ -96,7 +96,7 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
96
// use temporary name while uploading
97
const keepName = basename(fullPath).slice(-200)
98
let tempName = join(dir, 'hfs$upload-' + keepName)
99
- const resumable = fs.existsSync(tempName) && !openFiles.has(tempName) && tempName
99
+ const resumable = fs.existsSync(tempName) && !openFiles.has(tempName) && tempName // resumable is temp-file-1
100
if (resumable)
101
tempName = join(dir, 'hfs$upload2-' + keepName)
102
// checks for resume feature
@@ -107,13 +107,15 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
107
if (resume > size)
108
return fail(HTTP_RANGE_NOT_SATISFIABLE)
109
// warn frontend about resume possibility
110
+ let resumableLost = false
111
if (!resume && resumable) {
112
const timeout = 30
113
notifyClient(ctx, 'upload.resumable', { [path]: size, expires: Date.now() + timeout * 1000 })
113
- delayedDelete(resumable, timeout, () =>
114
- fs.rename(tempName, resumable, err => {
115
- if (!err)
116
- tempName = resumable
114
+ delayedDelete(resumable, timeout, () => // if user resumes, this upload is interrupted, and next upload will cancel this delayedDelete
115
+ fs.rename(tempName, resumable, err => { // try to rename upload2 to upload, overwriting
116
+ if (err) return
117
+ tempName = resumable
118
+ resumableLost = true
119
}) )
120
}
121
// append if resuming
@@ -142,7 +144,7 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
144
writeStream.once('close', async () => {
145
try {
146
if (ctx.req.aborted) {
145
- if (resumable && !resuming) // we don't want to be left with 2 temp files
147
+ if (resumable && !resumableLost && !resuming) // we don't want to be left with 2 temp files
148
return delayedDelete(tempName, 0)
149
const sec = deleteUnfinishedUploadsAfter.get()
150
return _.isNumber(sec) && delayedDelete(tempName, sec)
@@ -157,6 +159,7 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
159
}
160
try {
161
await rename(tempName, dest)
162
+ cancelDeletion(tempName) // not necessary, as deletion's failure is silent, but still
163
ctx.state.uploadDestinationPath = dest
164
setUploadMeta(dest, ctx)
165
if (ctx.query.comment)