fix: admin/monitor: disconnect not working for uploads
Massimo Melina committed
Mar 7, 2023 at 22:51 UTC
b99bdacde07ec5a9af4371bc47c7c25d11b1a210
4 files changed
+19
-11
frontend/src/dialog.ts
+3
-3
@@ -55,18 +55,18 @@ export async function promptDialog(msg: string, { def, type, ...rest }:PromptOpt
55
56
type AlertType = 'error' | 'warning' | 'info'
57
58
-export async function alertDialog(msg: ReactElement | string | Error, type:AlertType='info') {
58
+export async function alertDialog(msg: ReactElement | string | Error, type:AlertType='info', { getClose=_.noop }={}) {
59
if (msg instanceof Error) {
60
msg = msg.message
61
type = 'error'
62
}
63
- return new Promise(resolve => newDialog({
63
+ return new Promise(resolve => getClose(newDialog({
64
className: 'dialog-alert dialog-alert-'+type,
65
title: t(_.capitalize(type)),
66
icon: '!',
67
onClose: resolve,
68
Content
69
- }))
69
+ })))
70
71
function Content(){
72
if (typeof msg === 'string' || msg instanceof Error)
frontend/src/upload.ts
+7
-4
@@ -223,7 +223,7 @@ let req: XMLHttpRequest | undefined
223
let overrideStatus = 0
224
let notificationChannel = ''
225
let notificationSource: EventSource
226
-let closeResumeDialog: DialogCloser | undefined
226
+let closeLast: DialogCloser | undefined
227
228
async function startUpload(f: File, to: string, resume=0) {
229
let resuming = false
@@ -234,6 +234,7 @@ async function startUpload(f: File, to: string, resume=0) {
234
req.onloadend = () => {
235
if (req?.readyState !== 4) return
236
const status = overrideStatus || req.status
237
+ closeLast?.()
238
if (status) // 0 = user-aborted
239
if (status >= 400)
240
error(status)
@@ -267,8 +268,9 @@ async function startUpload(f: File, to: string, resume=0) {
268
const {expires} = data
269
const timeout = typeof expires !== 'number' ? 0
270
: (Number(new Date(expires)) - Date.now()) / 1000
271
+ closeLast?.()
272
const msg = t('confirm_resume', "Resume upload?") + ` (${formatPerc(size/f.size)} = ${formatBytes(size)})`
271
- if (!await confirmDialog(msg, { timeout, getClose: x => closeResumeDialog=x })) return
273
+ if (!await confirmDialog(msg, { timeout, getClose: x => closeLast=x })) return
274
if (uploading !== uploadState.uploading) return // too late
275
resuming = true
276
abortCurrentUpload()
@@ -290,7 +292,9 @@ async function startUpload(f: File, to: string, resume=0) {
292
413: t`file too large`,
293
}
294
const specifier = (ERRORS as any)[status]
293
- alertDialog(t('failed_upload', f, "Couldn't upload {name}") + prefix(': ', specifier), 'error').then()
295
+ const msg = t('failed_upload', f, "Couldn't upload {name}") + prefix(': ', specifier)
296
+ closeLast?.()
297
+ return alertDialog(msg, 'error', { getClose: x => closeLast=x })
298
}
299
300
function done() {
@@ -300,7 +304,6 @@ async function startUpload(f: File, to: string, resume=0) {
304
}
305
306
function next() {
303
- closeResumeDialog?.()
307
uploadState.uploading = undefined
308
uploadState.partial = 0
309
const { qs } = uploadState
src/api.monitor.ts
+8
-4
@@ -13,10 +13,14 @@ const apis: ApiHandlers = {
13
async disconnect({ ip, port, wait }) {
14
const match = _.matches({ ip, port })
15
const c = getConnections().find(c => match(getConnAddress(c)))
16
- const waiter = pendingPromise<void>()
17
- c?.socket.end(waiter.resolve)
18
- if (wait)
19
- await waiter
16
+ if (c) {
17
+ const waiter = pendingPromise<void>()
18
+ c.socket.end(waiter.resolve)
19
+ c.ctx?.res.end()
20
+ c.ctx?.req.socket.end('')
21
+ if (wait)
22
+ await waiter
23
+ }
24
return { result: Boolean(c) }
25
},
26
src/index.ts
+1
@@ -47,6 +47,7 @@ function errorHandler(err:Error & { code:string, path:string }) {
47
const { code } = err
48
if (DEV && code === 'ENOENT' && err.path.endsWith('sockjs-node')) return // spam out dev stuff
49
if (code === 'ECANCELED' || code === 'ECONNRESET' || code === 'ECONNABORTED' || code === 'EPIPE'
50
+ || code === 'ERR_STREAM_WRITE_AFTER_END' // happens disconnecting uploads, don't care
51
|| code === 'HPE_INVALID_EOF_STATE') return // someone interrupted, don't care
52
console.error('server error', err)
53
}