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 }