plugins: api event 'uploadStart'
Massimo Melina committed
May 16, 2024 at 00:03 UTC
be0bc7d06b443c04641adcfcadfb3a6a8e6eded2
1 file changed
+32
-34
src/upload.ts
+32
-34
@@ -1,11 +1,6 @@
1
import { getNodeByName, hasPermission, statusCodeForMissingPerm, VfsNode } from './vfs'
2
import Koa from 'koa'
3
-import {
4
- HTTP_CONFLICT, HTTP_FOOL,
5
- HTTP_PAYLOAD_TOO_LARGE,
6
- HTTP_RANGE_NOT_SATISFIABLE,
7
- HTTP_SERVER_ERROR,
8
-} from './const'
3
+import { HTTP_CONFLICT, HTTP_FOOL, HTTP_PAYLOAD_TOO_LARGE, HTTP_RANGE_NOT_SATISFIABLE, HTTP_SERVER_ERROR } from './const'
4
import { basename, dirname, extname, join } from 'path'
5
import fs from 'fs'
6
import { Callback, dirTraversal, escapeHTML, loadFileAttr, storeFileAttr, try_ } from './misc'
@@ -16,6 +11,8 @@ import { disconnect, updateConnection, updateConnectionForCtx } from './connecti
11
import { roundSpeed } from './throttler'
12
import { getCurrentUsername } from './auth'
13
import { setCommentFor } from './comments'
14
+import _ from 'lodash'
15
+import events from './events'
16
17
export const deleteUnfinishedUploadsAfter = defineConfig<undefined|number>('delete_unfinished_uploads_after', 86_400)
18
export const minAvailableMb = defineConfig('min_available_mb', 100)
@@ -95,7 +92,7 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
92
const resuming = resume && resumable
93
if (!resuming)
94
resume = 0
98
- const ret = resuming ? fs.createWriteStream(resumable, { flags: 'r+', start: resume })
95
+ const writeStream = resuming ? fs.createWriteStream(resumable, { flags: 'r+', start: resume })
96
: fs.createWriteStream(tempName)
97
if (resuming) {
98
fs.rm(tempName, () => {})
@@ -103,33 +100,34 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
100
}
101
cancelDeletion(tempName)
102
trackProgress()
106
- ret.once('close', async () => {
107
- if (!ctx.req.aborted) {
108
- let dest = fullPath
109
- if (dontOverwriteUploading.get() && fs.existsSync(dest) && !await overwriteAnyway()) {
110
- const ext = extname(dest)
111
- const base = dest.slice(0, -ext.length)
112
- let i = 1
113
- do dest = `${base} (${i++})${ext}`
114
- while (fs.existsSync(dest))
115
- }
116
- return fs.rename(tempName, dest, err => {
117
- setUploadMeta(err ? tempName : dest, ctx)
118
- if (err)
119
- console.error("couldn't rename temp to", dest, String(err))
120
- else if (ctx.query.comment)
121
- setCommentFor(dest, escapeHTML(String(ctx.query.comment)))
122
- if (resumable)
123
- delayedDelete(resumable, 0)
124
- })
103
+ writeStream.once('close', async () => {
104
+ if (ctx.req.aborted) {
105
+ if (resumable) // we don't want to be left with 2 temp files
106
+ return delayedDelete(tempName, 0)
107
+ const sec = deleteUnfinishedUploadsAfter.get()
108
+ return _.isNumber(sec) && delayedDelete(tempName, sec)
109
+ }
110
+ let dest = fullPath
111
+ if (dontOverwriteUploading.get() && fs.existsSync(dest) && !await overwriteAnyway()) {
112
+ const ext = extname(dest)
113
+ const base = dest.slice(0, -ext.length)
114
+ let i = 1
115
+ do dest = `${base} (${i++})${ext}`
116
+ while (fs.existsSync(dest))
117
}
126
- if (resumable) // we don't want to be left with 2 temp files
127
- return delayedDelete(tempName, 0)
128
- const sec = deleteUnfinishedUploadsAfter.get()
129
- if (typeof sec !== 'number') return
130
- delayedDelete(tempName, sec)
118
+ return fs.rename(tempName, dest, err => {
119
+ setUploadMeta(err ? tempName : dest, ctx)
120
+ if (err)
121
+ console.error("couldn't rename temp to", dest, String(err))
122
+ else if (ctx.query.comment)
123
+ setCommentFor(dest, escapeHTML(String(ctx.query.comment)))
124
+ if (resumable)
125
+ delayedDelete(resumable, 0)
126
+ })
127
})
132
- return ret
128
+ const obj = { ctx, writeStream }
129
+ events.emit('uploadStart', obj)
130
+ return obj.writeStream
131
132
async function overwriteAnyway() {
133
if (ctx.query.overwrite === undefined // legacy pre-0.52
@@ -147,13 +145,13 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
145
if (!conn) return
146
const h = setInterval(() => {
147
const now = Date.now()
150
- const got = ret.bytesWritten
148
+ const got = writeStream.bytesWritten
149
const inSpeed = roundSpeed((got - lastGot) / (now - lastGotTime))
150
lastGot = got
151
lastGotTime = now
152
updateConnection(conn, { inSpeed, got }, { opProgress: (resume + got) / opTotal })
153
}, 1000)
156
- ret.once('close', () => clearInterval(h) )
154
+ writeStream.once('close', () => clearInterval(h) )
155
}
156
157
function delayedDelete(path: string, secs: number, cb?: Callback) {