@samitouri / QOSami-HFS / commits / b58ad7a5

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